File Coverage

blib/lib/Template/Provider/PAR.pm
Criterion Covered Total %
statement 58 59 98.3
branch 10 18 55.5
condition 1 5 20.0
subroutine 15 15 100.0
pod 1 1 100.0
total 85 98 86.7


line stmt bran cond sub pod time code
1             package Template::Provider::PAR;
2 4     4   417114 use strict;
  4         10  
  4         167  
3 4     4   27 use warnings;
  4         7  
  4         135  
4 4     4   2401 use Archive::Zip qw(:ERROR_CODES);
  4         216340  
  4         568  
5 4     4   4198 use PAR;
  4         49472  
  4         25  
6 4     4   50026 use Scalar::Util qw(blessed);
  4         13  
  4         409  
7 4     4   28 use Carp qw(croak);
  4         9  
  4         341  
8 4     4   26 use File::Spec;
  4         8  
  4         95  
9 4     4   34 use Template::Provider;
  4         49611  
  4         120  
10              
11 4     4   33 use vars qw(@ISA $VERSION %AZ_ERROR_CODES);
  4         8  
  4         278  
12              
13             @ISA = qw(Template::Provider);
14 4     4   70 use version; $VERSION = qv('0.1.102'); # last digit is SVN revision number
  4         18443  
  4         28  
15              
16             # FIXME disallow use of RELATIVE paths?
17              
18             =head1 NAME
19              
20             Template::Provider::PAR - Include templates from a path within a PAR or Zip archive.
21              
22             =head1 VERSION
23              
24             This document describes Template::Provider::PAR version 0.1.102.
25              
26             =head1 SYNOPSIS
27              
28             use Template;
29             use Template::Provider::PAR;
30              
31             # Specify the provider in the config for Template::Toolkit. Note,
32             # since no archive name is specified here, the name of the archive
33             # will be obtained from $0
34             my $tt_config =
35             {
36             LOAD_TEMPLATES =>
37             [Template::Provider::PAR->new(INCLUDE_PATH => 'some/archive/dir')]
38             };
39              
40             my $template = <<TEMPLATE;
41             [% PROCESS something_in_the_archive.tt %]
42             TEMPLATE
43              
44             my $tt = Template->new($tt_config);
45             $tt->process($template, $vars) || die $tt->error;
46              
47             =head1 DESCRIPTION
48              
49             This C<Template::Provider::PAR> is designed to behave like a regular
50             C<Template::Provider>, except that it retrieves templates from a path
51             in a PAR archive, by default the archive in which the running script
52             is embedded within.
53              
54             This allows C<Template::Toolkit> to be used from an entirely
55             self-contained PAR archive.
56              
57             =cut
58              
59              
60             # package variables
61              
62             %AZ_ERROR_CODES =
63             (AZ_OK => 'Everything is fine.',
64             AZ_STREAM_END => 'The read stream (or central directory) ended normally.',
65             AZ_ERROR => 'There was some generic kind of error.',
66             AZ_FORMAT_ERROR => 'There is a format error in a ZIP file being read.',
67             AZ_IO_ERROR => 'There was an IO error.');
68              
69              
70              
71             =head1 INHERITED METHODS
72              
73             These methods are inherited from L<Template::Provider> and function in
74             exactly the same way:
75              
76             =over 4
77              
78             =item * C<fetch()>
79              
80             =item * C<store()>
81              
82             =item * C<load()>
83              
84             =item * C<include_path()>
85              
86             =item * C<paths()>
87              
88             =item * C<DESTROY()>
89              
90             =back
91              
92             See L<Template::Provider> for details of these methods.
93              
94             =head1 CLASS METHODS
95              
96             =head2 C<< $obj = $class->new(%parameters) >>
97              
98             Constructs a new instance.
99              
100             Accepts all the arguments as for the base class L<Template::Provider>,
101             with the following additions:
102              
103             =over 4
104              
105             =item C<ARCHIVE>
106              
107             This optional parameter explicity sets the archive to use, either as a
108             filename or a reference to a C<Archive::Zip> object. If omitted, then
109             the return value of C<PAR::par_handle($0)> is used. If this returns
110             undef, an error is thrown.
111              
112              
113             =item C<INCLUDE_PATH>
114              
115             This works as before, except obviously it refers to a path
116             within the archive.
117              
118             =back
119              
120             Note that the C<RELATIVE> parameter makes no sense within a PAR
121             archive, as it has no concept of a current directory, so the behaviour
122             is currently undefined and it should not be used.
123              
124              
125             =cut
126              
127              
128             =head1 INSTANCE METHODS
129              
130             =head2 C<< $obj->archive >>
131              
132             Returns a reference to the PAR archive (an instance of L<Archive::Zip>).
133              
134             =cut
135              
136 9     9 1 67 sub archive { shift->{ARCHIVE} }
137              
138              
139              
140             #------------------------------------------------------------------------
141             # private class methods
142             #------------------------------------------------------------------------
143              
144             #------------------------------------------------------------------------
145             # $zip_path = $class->_zip_path($native_path)
146             #
147             # Converts native paths as returned by File::Spec to zip archive
148             # (unix) style paths.
149             #------------------------------------------------------------------------
150             sub _zip_path
151             {
152 9     9   12 shift;
153             # make sure we have a zip (unix style) path.
154             # (I'd like to use unix paths through and through, but
155             # we can't really override the parent class's use of
156             # File::Spec without overriding everything else)
157 9         112 join "/", File::Spec->splitdir(shift);
158             }
159              
160              
161              
162              
163             #------------------------------------------------------------------------
164             # $obj = $obj->_init(\%params)
165             #
166             # Initialise a new instance - sets the C<ARCHIVE> attribute and calls the
167             # parent class's C<_init> method.
168             #------------------------------------------------------------------------
169             sub _init {
170 3     3   31051 my ( $self, $params ) = @_;
171 3         10 my $archive;
172 3 50       29 if ($params->{ARCHIVE})
173             {
174 3         17 $archive = $params->{ARCHIVE};
175 3 100       26 if (blessed $archive)
176             {
177 2 50       39 croak "ARCHIVE parameter is not an Archive::Zip instance"
178             unless $archive->isa('Archive::Zip');
179             }
180             else
181             {
182 1 50       37 croak "Archive '$archive' does not exist"
183             unless -f $archive;
184            
185 1         14 $archive = Archive::Zip->new($archive);
186             }
187             }
188             else
189             {
190 0   0     0 $archive = PAR::par_handle($0)
191             || croak "As we do not seem to be used within a PAR archive".
192             " you must define the ARCHIVE parameter to reference a Zip archive";
193             }
194              
195 3         1800 $self->SUPER::_init( $params );
196 3         306 $self->{ ARCHIVE } = $archive;
197             # FIXME disallow RELATIVE?
198            
199 3         15 return $self;
200             }
201              
202              
203              
204              
205              
206             #------------------------------------------------------------------------
207             # $time = $obj->_template_modified($path)
208             #
209             # Returns the last modified time of the $path.
210             # Returns undef if the path does not exist.
211             # Override if templates are not on disk, for example
212             #------------------------------------------------------------------------
213              
214             sub _template_modified {
215 6     6   186112 my $self = shift;
216 6   50     40 my $template = shift || return;
217 6         31 $template = $self->_zip_path($template);
218              
219 6         36 my $member = $self->archive->memberNamed($template);
220            
221 6 50       377 return $member->lastModTime() if $member;
222             }
223              
224              
225             #------------------------------------------------------------------------
226             # $data = $obj->_template_content($path)
227             # ($data, $error, $mtime) = $obj->_template_content($path)
228             #
229             # Fetches content pointed to by $path (which is a local path spec referring
230             # to a path within the archive, that will be converted to a zip-path
231             # internally).
232             #
233             # Returns the content in scalar context.
234             # Returns ($data, $error, $mtime) in list context where
235             # $data - content
236             # $error - error string if there was an error, otherwise undef
237             # $mtime - last modified time from calling stat() on the path
238             #------------------------------------------------------------------------
239              
240             sub _template_content {
241 3     3   508 my ($self, $path) = @_;
242              
243 3 50       15 return (undef, "No path specified to fetch content from ")
244             unless $path;
245 3         10 $path = $self->_zip_path($path);
246              
247 3         16 my $archive = $self->archive;
248 3         24 my ($data, $error) = $archive->contents($path);
249 3         3284 my $member = $archive->memberNamed($path);
250 3 50       127 my $mod_date = $member? $member->lastModTime() : 0;
251              
252             # convert the error code
253 3 50       292 $error = $error == AZ_OK? undef :
254             "$path: Archive::Zip - ". $AZ_ERROR_CODES{$error};
255            
256            
257             return wantarray
258 3 50       22 ? ( $data, $error, $mod_date )
259             : $data;
260             }
261              
262              
263             1; # End of the module code; everything from here is documentation...
264             __END__
265              
266             =head1 SEE ALSO
267              
268             L<Template>, L<Template::Provider>, L<PAR>, L<Archive::Zip>
269              
270              
271             =head1 DIAGNOSTICS
272              
273             In addition to errors raised by L<Template::Provider> and L<DBIx::Class>,
274             Template::Provider::PAR may generate the following error messages:
275              
276             =over
277              
278             =item C<< Archive '$archive' does not exist >>
279              
280             Thrown by the constructor if the C<ARCHIVE> paramter is a non-existant
281             filename.
282              
283             =item C<< ARCHIVE parameter is not an Archive::Zip instance >>
284              
285             Thrown by the constructor if the C<ARCHIVE> paramter references an
286             object which isn't an C<Archive::Zip> instance.
287              
288             =item C<< As we do not seem to be used within a PAR archive you must define the ARCHIVE parameter to reference a Zip archive >>
289              
290             Thown by the constructor if no C<ARCHIVE> parameter is defined and the
291             host archive can't be inferred (i.e. if the running script is not
292             packaged within a PAR archive).
293              
294             =back
295              
296             =head1 CONFIGURATION AND ENVIRONMENT
297              
298             C<Template::Provider::PAR> requires no configuration files or
299             environment variables, other than those set by C<PAR>'s runtime
300             environment.
301              
302             =head1 DEPENDENCIES
303              
304             =over
305              
306             =item
307              
308             L<Archive::Zip>
309              
310             =item
311              
312             L<PAR>
313              
314             =item
315              
316             L<Scalar::Util>
317              
318             =item
319              
320             L<File::Spec>
321              
322             =item
323              
324             L<Carp>
325              
326             =item
327              
328             L<Template::Provider>
329              
330             =item
331              
332             L<Module::Build>
333              
334             =item
335              
336             L<Test::More>
337              
338             =back
339              
340             Additionally, use of this module requires an object of the class
341             L<DBIx::Class::Schema> or L<DBIx::Class::ResultSet>.
342              
343              
344             =head1 INCOMPATIBILITIES
345              
346             None reported.
347              
348             =head1 BUGS
349              
350             Please report any bugs or feature requests to
351             C<bug-template-provider-par at rt.cpan.org>, or through the web interface at
352             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Template-Provider-PAR>.
353              
354             =head1 SUPPORT
355              
356             You can find documentation for this module with the perldoc command.
357              
358             perldoc Template::Provider::PAR
359              
360             You may also look for information at:
361              
362             =over 4
363              
364             =item * AnnoCPAN: Annotated CPAN documentation
365              
366             L<http://annocpan.org/dist/Template-Provider-PAR/>
367              
368             =item * RT: CPAN's request tracker
369              
370             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Template-Provider-PAR>
371              
372             =item * Search CPAN
373              
374             L<http://search.cpan.org/dist/Template-Provider-PAR/>
375              
376             =back
377              
378              
379             =head1 AUTHOR
380              
381             Nick Woolley <npw@cpan.org>
382              
383             Much of the code was adapted from L<Template::Provider> by Andy
384             Wardley and L<Template::Provider::DBIC>, by David Cardwell.
385              
386             =head1 COPYRIGHT AND LICENSE
387              
388             Copyright (c) 2007 Nick Woolley. All rights reserved.
389              
390             This module is free software; you can redistribute it and/or
391             modify it under the same terms as Perl itself. See L<perlartistic>.
392              
393             =head1 DISCLAIMER OF WARRANTY
394              
395             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
396             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
397             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
398             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
399             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
400             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
401             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
402             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
403             NECESSARY SERVICING, REPAIR, OR CORRECTION.
404              
405             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
406             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
407             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
408             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
409             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
410             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
411             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
412             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
413             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
414             SUCH DAMAGES.
415              
416              
417             =cut