File Coverage

lib/Template/Document.pm
Criterion Covered Total %
statement 81 92 88.0
branch 17 28 60.7
condition 10 17 58.8
subroutine 13 15 86.6
pod 8 8 100.0
total 129 160 80.6


line stmt bran cond sub pod time code
1             ##============================================================= -*-Perl-*-
2             #
3             # Template::Document
4             #
5             # DESCRIPTION
6             # Module defining a class of objects which encapsulate compiled
7             # templates, storing additional block definitions and metadata
8             # as well as the compiled Perl sub-routine representing the main
9             # template content.
10             #
11             # AUTHOR
12             # Andy Wardley
13             #
14             # COPYRIGHT
15             # Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
16             #
17             # This module is free software; you can redistribute it and/or
18             # modify it under the same terms as Perl itself.
19             #
20             #============================================================================
21              
22             package Template::Document;
23              
24 86     86   470 use strict;
  86         164  
  86         7927  
25 86     86   510 use warnings;
  86         158  
  86         2846  
26 86     86   440 use base 'Template::Base';
  86         172  
  86         6899  
27 86     86   2077 use Template::Constants;
  86         178  
  86         17345  
28              
29             our $VERSION = 2.79;
30             our $DEBUG = 0 unless defined $DEBUG;
31             our $ERROR = '';
32             our ($COMPERR, $AUTOLOAD, $UNICODE);
33              
34             BEGIN {
35             # UNICODE is supported in versions of Perl from 5.008 onwards
36 86 50   86   1199 if ($UNICODE = $] > 5.007 ? 1 : 0) {
    50          
37 86 50       445 if ($] > 5.008) {
    0          
38             # utf8::is_utf8() available from Perl 5.8.1 onwards
39 86         139198 *is_utf8 = \&utf8::is_utf8;
40             }
41             elsif ($] == 5.008) {
42             # use Encode::is_utf8() for Perl 5.8.0
43 0         0 require Encode;
44 0         0 *is_utf8 = \&Encode::is_utf8;
45             }
46             }
47             }
48              
49              
50             #========================================================================
51             # ----- PUBLIC METHODS -----
52             #========================================================================
53              
54             #------------------------------------------------------------------------
55             # new(\%document)
56             #
57             # Creates a new self-contained Template::Document object which
58             # encapsulates a compiled Perl sub-routine, $block, any additional
59             # BLOCKs defined within the document ($defblocks, also Perl sub-routines)
60             # and additional $metadata about the document.
61             #------------------------------------------------------------------------
62              
63             sub new {
64 1294     1294 1 3202 my ($class, $doc) = @_;
65 1294         4610 my ($block, $defblocks, $variables, $metadata) = @$doc{ qw( BLOCK DEFBLOCKS VARIABLES METADATA ) };
66 1294   50     3374 $defblocks ||= { };
67 1294   50     3037 $metadata ||= { };
68              
69             # evaluate Perl code in $block to create sub-routine reference if necessary
70 1294 100       3577 unless (ref $block) {
71 1276         9231 local $SIG{__WARN__} = \&catch_warnings;
72 1276         3236 $COMPERR = '';
73              
74             # DON'T LOOK NOW! - blindly untainting can make you go blind!
75 1276         4860 $block =~ /(.*)/s;
76 1276         5393 $block = $1;
77            
78 1276         454817 $block = eval $block;
79 1276 50       32485 return $class->error($@)
80             unless defined $block;
81             }
82              
83             # same for any additional BLOCK definitions
84 137 100 50     36223 @$defblocks{ keys %$defblocks } =
85             # MORE BLIND UNTAINTING - turn away if you're squeamish
86             map {
87 1294         4607 ref($_)
88             ? $_
89             : ( /(.*)/s && eval($1) or return $class->error($@) )
90             } values %$defblocks;
91            
92 1294         30354 bless {
93             %$metadata,
94             _BLOCK => $block,
95             _DEFBLOCKS => $defblocks,
96             _VARIABLES => $variables,
97             _HOT => 0,
98             }, $class;
99             }
100              
101              
102             #------------------------------------------------------------------------
103             # block()
104             #
105             # Returns a reference to the internal sub-routine reference, _BLOCK,
106             # that constitutes the main document template.
107             #------------------------------------------------------------------------
108              
109             sub block {
110 2     2 1 7 return $_[0]->{ _BLOCK };
111             }
112              
113              
114             #------------------------------------------------------------------------
115             # blocks()
116             #
117             # Returns a reference to a hash array containing any BLOCK definitions
118             # from the template. The hash keys are the BLOCK name and the values
119             # are references to Template::Document objects. Returns 0 (# an empty hash)
120             # if no blocks are defined.
121             #------------------------------------------------------------------------
122              
123             sub blocks {
124 1287     1287 1 9258 return $_[0]->{ _DEFBLOCKS };
125             }
126              
127              
128             #-----------------------------------------------------------------------
129             # variables()
130             #
131             # Returns a reference to a hash of variables used in the template.
132             # This requires the TRACE_VARS option to be enabled.
133             #-----------------------------------------------------------------------
134              
135             sub variables {
136 0     0 1 0 return $_[0]->{ _VARIABLES };
137             }
138              
139             #------------------------------------------------------------------------
140             # process($context)
141             #
142             # Process the document in a particular context. Checks for recursion,
143             # registers the document with the context via visit(), processes itself,
144             # and then unwinds with a large gin and tonic.
145             #------------------------------------------------------------------------
146              
147             sub process {
148 1347     1347 1 6401 my ($self, $context) = @_;
149 1347         3318 my $defblocks = $self->{ _DEFBLOCKS };
150 1347         1782 my $output;
151              
152              
153             # check we're not already visiting this template
154             return $context->throw(Template::Constants::ERROR_FILE,
155             "recursion into '$self->{ name }'")
156 1347 100 100     4888 if $self->{ _HOT } && ! $context->{ RECURSION }; ## RETURN ##
157              
158 1346         5925 $context->visit($self, $defblocks);
159              
160 1346         3142 $self->{ _HOT } = 1;
161 1346         2429 eval {
162 1346         2370 my $block = $self->{ _BLOCK };
163 1346         46931 $output = &$block($context);
164             };
165 1346         38195 $self->{ _HOT } = 0;
166              
167 1346         5322 $context->leave();
168              
169 1346 100       3975 die $context->catch($@)
170             if $@;
171            
172 1328         4117 return $output;
173             }
174              
175              
176             #------------------------------------------------------------------------
177             # AUTOLOAD
178             #
179             # Provides pseudo-methods for read-only access to various internal
180             # members.
181             #------------------------------------------------------------------------
182              
183             sub AUTOLOAD {
184 36     36   960 my $self = shift;
185 36         134 my $method = $AUTOLOAD;
186              
187 36         162 $method =~ s/.*:://;
188 36 50       230 return if $method eq 'DESTROY';
189             # my ($pkg, $file, $line) = caller();
190             # print STDERR "called $self->AUTOLOAD($method) from $file line $line\n";
191 36         230 return $self->{ $method };
192             }
193              
194              
195             #========================================================================
196             # ----- PRIVATE METHODS -----
197             #========================================================================
198              
199              
200             #------------------------------------------------------------------------
201             # _dump()
202             #
203             # Debug method which returns a string representing the internal state
204             # of the object.
205             #------------------------------------------------------------------------
206              
207             sub _dump {
208 0     0   0 my $self = shift;
209 0         0 my $dblks;
210 0         0 my $output = "$self : $self->{ name }\n";
211              
212 0         0 $output .= "BLOCK: $self->{ _BLOCK }\nDEFBLOCKS:\n";
213              
214 0 0       0 if ($dblks = $self->{ _DEFBLOCKS }) {
215 0         0 foreach my $b (keys %$dblks) {
216 0         0 $output .= " $b: $dblks->{ $b }\n";
217             }
218             }
219              
220 0         0 return $output;
221             }
222              
223              
224             #========================================================================
225             # ----- CLASS METHODS -----
226             #========================================================================
227              
228             #------------------------------------------------------------------------
229             # as_perl($content)
230             #
231             # This method expects a reference to a hash passed as the first argument
232             # containing 3 items:
233             # METADATA # a hash of template metadata
234             # BLOCK # string containing Perl sub definition for main block
235             # DEFBLOCKS # hash containing further subs for addional BLOCK defs
236             # It returns a string containing Perl code which, when evaluated and
237             # executed, will instantiate a new Template::Document object with the
238             # above data. On error, it returns undef with an appropriate error
239             # message set in $ERROR.
240             #------------------------------------------------------------------------
241              
242             sub as_perl {
243 14     14 1 36 my ($class, $content) = @_;
244 14         86 my ($block, $defblocks, $metadata) = @$content{ qw( BLOCK DEFBLOCKS METADATA ) };
245              
246 14         412 $block =~ s/\n(?!#line)/\n /g;
247 14         355 $block =~ s/\s+$//;
248              
249 6         16 $defblocks = join('', map {
250 14         68 my $code = $defblocks->{ $_ };
251 6         179 $code =~ s/\n(?!#line)/\n /g;
252 6         981 $code =~ s/\s*$//;
253 6         54 " '$_' => $code,\n";
254             } keys %$defblocks);
255 14         210 $defblocks =~ s/\s+$//;
256              
257 34         68 $metadata = join('', map {
258 14         57 my $x = $metadata->{ $_ };
259 34         72 $x =~ s/(['\\])/\\$1/g;
260 34         133 " '$_' => '$x',\n";
261             } keys %$metadata);
262 14         108 $metadata =~ s/\s+$//;
263              
264             return <
265             #------------------------------------------------------------------------
266             # Compiled template generated by the Template Toolkit version $Template::VERSION
267             #------------------------------------------------------------------------
268              
269             $class->new({
270             METADATA => {
271             $metadata
272             },
273             BLOCK => $block,
274             DEFBLOCKS => {
275             $defblocks
276             },
277             });
278             EOF
279 14         256 }
280              
281              
282             #------------------------------------------------------------------------
283             # write_perl_file($filename, \%content)
284             #
285             # This method calls as_perl() to generate the Perl code to represent a
286             # compiled template with the content passed as the second argument.
287             # It then writes this to the file denoted by the first argument.
288             #
289             # Returns 1 on success. On error, sets the $ERROR package variable
290             # to contain an error message and returns undef.
291             #------------------------------------------------------------------------
292              
293             sub write_perl_file {
294 14     14 1 31 my ($class, $file, $content) = @_;
295 14         24 my ($fh, $tmpfile);
296            
297 14 50       80 return $class->error("invalid filename: $file")
298             unless $file =~ /^(.+)$/s;
299              
300 14         24 eval {
301 14         3754 require File::Temp;
302 14         69132 require File::Basename;
303 14         721 ($fh, $tmpfile) = File::Temp::tempfile(
304             DIR => File::Basename::dirname($file)
305             );
306 14   50     6979 my $perlcode = $class->as_perl($content) || die $!;
307            
308 14 100 66     132 if ($UNICODE && is_utf8($perlcode)) {
309 5         20 $perlcode = "use utf8;\n\n$perlcode";
310 5         29 binmode $fh, ":utf8";
311             }
312 14         186 print $fh $perlcode;
313 14         48807 close($fh);
314             };
315 14 50       71 return $class->error($@) if $@;
316 14   33     1496 return rename($tmpfile, $file)
317             || $class->error($!);
318             }
319              
320              
321             #------------------------------------------------------------------------
322             # catch_warnings($msg)
323             #
324             # Installed as
325             #------------------------------------------------------------------------
326              
327             sub catch_warnings {
328 1     1 1 236 $COMPERR .= join('', @_);
329             }
330              
331            
332             1;
333              
334             __END__