Commit | Line | Data |
e374d8da |
1 | package Template::Simple; |
2 | |
3 | use warnings; |
4 | use strict; |
5 | |
6 | use Carp ; |
7 | use Scalar::Util qw( reftype ) ; |
8 | use File::Slurp ; |
9 | |
10 | use Data::Dumper ; |
11 | |
12 | our $VERSION = '0.03'; |
13 | |
14 | my %opt_defaults = ( |
15 | |
16 | pre_delim => qr/\[%/, |
17 | post_delim => qr/%\]/, |
18 | greedy_chunk => 0, |
19 | # upper_case => 0, |
20 | # lower_case => 0, |
21 | include_paths => [ qw( templates ) ], |
22 | ) ; |
23 | |
24 | sub new { |
25 | |
26 | my( $class, %opts ) = @_ ; |
27 | |
28 | my $self = bless {}, $class ; |
29 | |
30 | # get all the options or defaults into the object |
31 | |
32 | while( my( $name, $default ) = each %opt_defaults ) { |
33 | |
34 | $self->{$name} = defined( $opts{$name} ) ? |
35 | $opts{$name} : $default ; |
36 | } |
37 | |
38 | # make up the regexes to parse the markup from templates |
39 | |
40 | # this matches scalar markups and grabs the name |
41 | |
42 | $self->{scalar_re} = qr{ |
43 | $self->{pre_delim} |
44 | \s* # optional leading whitespace |
45 | (\w+?) # grab scalar name |
46 | \s* # optional trailing whitespace |
47 | $self->{post_delim} |
48 | }xi ; # case insensitive |
49 | |
50 | #print "RE <$self->{scalar_re}>\n" ; |
51 | |
52 | # this grabs the body of a chunk in either greedy or non-greedy modes |
53 | |
54 | my $chunk_body = $self->{greedy_chunk} ? qr/.+/s : qr/.+?/s ; |
55 | |
56 | # this matches a marked chunk and grabs its name and text body |
57 | |
58 | $self->{chunk_re} = qr{ |
59 | $self->{pre_delim} |
60 | \s* # optional leading whitespace |
61 | START # required START token |
62 | \s+ # required whitespace |
63 | (\w+?) # grab the chunk name |
64 | \s* # optional trailing whitespace |
65 | $self->{post_delim} |
66 | ($chunk_body) # grab the chunk body |
67 | $self->{pre_delim} |
68 | \s* # optional leading whitespace |
69 | END # required END token |
70 | \s+ # required whitespace |
71 | \1 # match the grabbed chunk name |
72 | \s* # optional trailing whitespace |
73 | $self->{post_delim} |
74 | }xi ; # case insensitive |
75 | |
76 | #print "RE <$self->{chunk_re}>\n" ; |
77 | |
78 | # this matches a include markup and grabs its template name |
79 | |
80 | $self->{include_re} = qr{ |
81 | $self->{pre_delim} |
82 | \s* # optional leading whitespace |
83 | INCLUDE # required INCLUDE token |
84 | \s+ # required whitespace |
85 | (\w+?) # grab the included template name |
86 | \s* # optional trailing whitespace |
87 | $self->{post_delim} |
88 | }xi ; # case insensitive |
89 | |
90 | # load in any templates |
91 | |
92 | $self->add_templates( $opts{templates} ) ; |
93 | |
94 | return $self ; |
95 | } |
96 | |
59d7205c |
97 | sub compile { |
e374d8da |
98 | |
59d7205c |
99 | my( $self, $template_name ) = @_ ; |
100 | |
101 | my $tmpl_ref = eval { |
102 | $self->_get_template( $template_name ) ; |
103 | } ; |
104 | |
105 | croak "Template::Simple $@" if $@ ; |
106 | |
107 | # compile a copy of the template as it will be destroyed |
108 | |
109 | my $code_body = $self->_compile_chunk( '', "${$tmpl_ref}", "\t" ) ; |
110 | |
89bd07c7 |
111 | my $source = <<CODE ; |
59d7205c |
112 | |
113 | no warnings ; |
114 | |
115 | sub { |
116 | my( \$data ) = \@_ ; |
117 | |
7dd12000 |
118 | my \$out = $code_body ; |
59d7205c |
119 | |
120 | return \\\$out ; |
121 | } |
122 | CODE |
123 | |
89bd07c7 |
124 | #print $source ; |
59d7205c |
125 | |
89bd07c7 |
126 | my $code_ref = eval $source ; |
59d7205c |
127 | |
ca30cbfe |
128 | print $@ if $@ ; |
59d7205c |
129 | |
130 | $self->{compiled_cache}{$template_name} = $code_ref ; |
89bd07c7 |
131 | $self->{source_cache}{$template_name} = $source ; |
132 | } |
133 | |
134 | sub get_source { |
135 | |
136 | my( $self, $template_name ) = @_ ; |
137 | |
138 | return $self->{source_cache}{$template_name} ; |
59d7205c |
139 | } |
140 | |
141 | |
142 | sub _compile_chunk { |
143 | |
144 | my( $self, $chunk_name, $template, $indent ) = @_ ; |
145 | |
146 | return '' unless length $template ; |
147 | |
59d7205c |
148 | my @parts ; |
149 | |
150 | # loop all nested chunks and the text separating them |
151 | |
ca30cbfe |
152 | while( $template =~ m{$self->{chunk_re}} ) { |
59d7205c |
153 | |
7dd12000 |
154 | # grab the pre-match text and compile its scalars and save all of its parts |
59d7205c |
155 | |
156 | push @parts, $self->_compile_scalars( |
157 | substr( $template, 0, $-[0] ) ) ; |
158 | |
ca30cbfe |
159 | # print "OFF: $-[0] $+[0]\n" ; |
160 | # print "PRE: [", substr( $template, 0, $-[0] ), "]\n\n" ; |
161 | # print "CHUNK: [$1] BODY [$2]\n\n" ; |
162 | # print "TRUNC: [", substr( $template, 0, $+[0] ), "]\n\n" ; |
163 | # print "LEFT: [$template]\n\n" ; |
164 | |
59d7205c |
165 | # compile the nested chunk and save its parts |
166 | |
7dd12000 |
167 | push @parts, $self->_compile_chunk( $1, $2, "$indent\t\t" ) ; |
59d7205c |
168 | |
7dd12000 |
169 | # chop off the pre-match and the chunk |
59d7205c |
170 | |
171 | substr( $template, 0, $+[0], '' ) ; |
ca30cbfe |
172 | |
173 | # print "LEFT2: [$template]\n\n" ; |
174 | # print Dumper \@parts ; |
175 | |
59d7205c |
176 | } |
177 | |
178 | # compile trailing text for scalars and save all of its parts |
179 | |
180 | push @parts, $self->_compile_scalars( $template ) ; |
181 | |
182 | # generate the code for this chunk |
183 | |
184 | # start it with a do{} block open |
185 | |
7dd12000 |
186 | my $code = <<CODE ; |
187 | do { |
188 | CODE |
189 | |
190 | $indent .= "\t" ; |
59d7205c |
191 | |
192 | # generate a lookup in data for this chunk name (unless it is the top |
193 | # level). this descends down the data tree during rendering |
194 | |
7dd12000 |
195 | $code .= <<CODE if $chunk_name ; |
196 | ${indent}my \$data = \$data->{$chunk_name} ; |
197 | CODE |
198 | |
199 | # add the loop code to handle a scalar or an array |
200 | |
201 | $code .= <<CODE ; |
202 | ${indent}my \$out ; |
ca30cbfe |
203 | |
204 | ${indent}my \@data = \$data ; |
205 | ${indent}while( defined( my \$data = shift \@data ) ) { |
206 | |
207 | ${indent} if ( ref \$data eq 'ARRAY' ) { |
208 | ${indent} push \@data, \@{\$data} ; |
209 | ${indent} next ; |
210 | ${indent} } |
7dd12000 |
211 | |
212 | ${indent}\$out .= ref \$data ne 'HASH' ? \$data : |
59d7205c |
213 | CODE |
214 | |
ca30cbfe |
215 | #${indent}foreach my \$data ( ref \$data eq 'ARRAY' ? \@{\$data} : \$data ) { |
216 | |
217 | |
218 | |
7dd12000 |
219 | $indent .= "\t" ; |
220 | |
59d7205c |
221 | # now generate the code to output all the parts of this chunk. they |
222 | # are all concatentated by the . operator |
223 | |
7dd12000 |
224 | $code .= $indent . join( "\n$indent.\n$indent", @parts ) ; |
225 | |
226 | chop $indent ; |
59d7205c |
227 | |
7dd12000 |
228 | # now we end the .= statement, the loop and the do block for this chunk |
229 | $code .= <<CODE ; |
230 | ; |
231 | $indent} |
232 | $indent\$out ; |
233 | CODE |
59d7205c |
234 | |
235 | chop $indent ; |
7dd12000 |
236 | $code .= "$indent}" ; |
59d7205c |
237 | |
238 | return $code ; |
239 | } |
240 | |
241 | sub _compile_scalars { |
242 | |
243 | my( $self, $template ) = @_ ; |
244 | |
245 | # if the template is empty return no parts |
246 | |
247 | return unless length $template ; |
248 | |
249 | my @parts ; |
250 | |
251 | while( $template =~ m{$self->{scalar_re}}g ) { |
252 | |
253 | # keep the text before the scalar markup and the code to access the scalar |
254 | |
255 | push( @parts, |
256 | dump_text( substr( $template, 0, $-[0] ) ), |
257 | "\$data->{$1}" |
258 | ) ; |
ca30cbfe |
259 | |
260 | # truncate the matched text so the next match starts at begining of string |
261 | |
59d7205c |
262 | substr( $template, 0, $+[0], '' ) ; |
263 | } |
264 | |
265 | # keep any trailing text part |
266 | |
267 | push @parts, dump_text( $template ) ; |
268 | |
269 | return @parts ; |
270 | } |
271 | |
272 | use Data::Dumper ; |
273 | |
274 | sub dump_text { |
275 | |
276 | my( $text ) = @_ ; |
277 | |
278 | return unless length $text ; |
279 | |
280 | local( $Data::Dumper::Useqq ) = 1 ; |
281 | |
282 | my $dumped = Dumper $text ; |
283 | |
284 | $dumped =~ s/^[^"]+// ; |
285 | $dumped =~ s/;\n$// ; |
286 | |
287 | return $dumped ; |
288 | } |
e374d8da |
289 | |
290 | sub render { |
291 | |
59d7205c |
292 | my( $self, $template_name, $data ) = @_ ; |
293 | |
7dd12000 |
294 | my $tmpl_ref = ref $template_name eq 'SCALAR' ? $template_name : '' ; |
59d7205c |
295 | |
7dd12000 |
296 | unless( $tmpl_ref ) { |
59d7205c |
297 | |
7dd12000 |
298 | # render with cached code and return if we precompiled this template |
e374d8da |
299 | |
7dd12000 |
300 | if ( my $compiled = $self->{compiled_cache}{$template_name} ) { |
59d7205c |
301 | |
7dd12000 |
302 | return $compiled->($data) ; |
303 | } |
59d7205c |
304 | |
7dd12000 |
305 | # not compiled so get this template by name |
59d7205c |
306 | |
7dd12000 |
307 | $tmpl_ref ||= eval{ $self->_get_template($template_name) } ; |
e374d8da |
308 | |
7dd12000 |
309 | # we couldn't find this template name so assume it is the template text |
310 | |
311 | $tmpl_ref ||= \$template_name ; |
312 | } |
e374d8da |
313 | |
314 | my $rendered = $self->_render_includes( $tmpl_ref ) ; |
315 | |
316 | #print "INC EXP <$rendered>\n" ; |
317 | |
318 | $rendered = eval { |
319 | $self->_render_chunk( $rendered, $data ) ; |
320 | } ; |
321 | |
322 | croak "Template::Simple $@" if $@ ; |
323 | |
324 | return $rendered ; |
325 | } |
326 | |
327 | sub _render_includes { |
328 | |
329 | my( $self, $tmpl_ref ) = @_ ; |
330 | |
331 | # make a copy of the initial template so we can render it. |
332 | |
333 | my $rendered = ${$tmpl_ref} ; |
334 | |
335 | # loop until we can render no more include markups |
336 | |
337 | 1 while $rendered =~ |
338 | s{$self->{include_re}} |
339 | { ${ $self->_get_template($1) } |
340 | }e ; |
341 | |
342 | return \$rendered ; |
343 | } |
344 | |
345 | my %renderers = ( |
346 | |
347 | HASH => \&_render_hash, |
348 | ARRAY => \&_render_array, |
349 | CODE => \&_render_code, |
350 | # if no ref then data is a scalar so replace the template with just the data |
351 | '' => sub { \$_[2] }, |
352 | ) ; |
353 | |
354 | |
355 | sub _render_chunk { |
356 | |
357 | my( $self, $tmpl_ref, $data ) = @_ ; |
358 | |
359 | #print "T ref [$tmpl_ref] [$$tmpl_ref]\n" ; |
360 | #print "CHUNK ref [$tmpl_ref] TMPL\n<$$tmpl_ref>\n" ; |
361 | |
362 | #print Dumper $data ; |
363 | |
364 | return \'' unless defined $data ; |
365 | |
366 | # now render this chunk based on the type of data |
367 | |
368 | my $renderer = $renderers{reftype $data || ''} ; |
369 | |
370 | #print "EXP $renderer\nREF ", reftype $data, "\n" ; |
371 | |
372 | die "unknown template data type '$data'\n" unless defined $renderer ; |
373 | |
374 | return $self->$renderer( $tmpl_ref, $data ) ; |
375 | } |
376 | |
377 | sub _render_hash { |
378 | |
379 | my( $self, $tmpl_ref, $href ) = @_ ; |
380 | |
381 | return $tmpl_ref unless keys %{$href} ; |
382 | |
383 | # we need a local copy of the template to render |
384 | |
385 | my $rendered = ${$tmpl_ref} ; |
386 | |
387 | |
388 | # recursively render all top level chunks in this chunk |
389 | |
390 | $rendered =~ s{$self->{chunk_re}} |
391 | { |
392 | # print "CHUNK $1\nBODY\n----\n<$2>\n\n------\n" ; |
ca30cbfe |
393 | # print "CHUNK $1\nBODY\n----\n<$2>\n\n------\n" ; |
394 | # print "pre CHUNK [$`]\n" ; |
e374d8da |
395 | ${ $self->_render_chunk( \"$2", $href->{$1} ) } |
396 | }gex ; |
397 | |
398 | # now render scalars |
399 | |
400 | #print "HREF: ", Dumper $href ; |
401 | |
402 | $rendered =~ s{$self->{scalar_re}} |
403 | { |
404 | # print "SCALAR $1 VAL $href->{$1}\n" ; |
405 | defined $href->{$1} ? $href->{$1} : '' |
406 | }ge ; |
407 | |
408 | #print "HASH REND3\n<$rendered>\n" ; |
409 | |
410 | return \$rendered ; |
411 | } |
412 | |
413 | sub _render_array { |
414 | |
415 | my( $self, $tmpl_ref, $aref ) = @_ ; |
416 | |
417 | # render this $tmpl_ref for each element of the aref and join them |
418 | |
419 | my $rendered ; |
420 | |
421 | #print "AREF: ", Dumper $aref ; |
422 | |
423 | $rendered .= ${$self->_render_chunk( $tmpl_ref, $_ )} for @{$aref} ; |
424 | |
425 | return \$rendered ; |
426 | } |
427 | |
428 | sub _render_code { |
429 | |
430 | my( $self, $tmpl_ref, $cref ) = @_ ; |
431 | |
432 | my $rendered = $cref->( $tmpl_ref ) ; |
433 | |
434 | die <<DIE if ref $rendered ne 'SCALAR' ; |
435 | data callback to code didn't return a scalar or scalar reference |
436 | DIE |
437 | |
438 | return $rendered ; |
439 | } |
440 | |
441 | sub add_templates { |
442 | |
443 | my( $self, $tmpls ) = @_ ; |
444 | |
445 | #print Dumper $tmpls ; |
446 | return unless defined $tmpls ; |
447 | |
448 | ref $tmpls eq 'HASH' or croak "templates argument is not a hash ref" ; |
59d7205c |
449 | |
450 | # copy all the templates from the arg hash and force the values to be |
451 | # scalar refs |
e374d8da |
452 | |
59d7205c |
453 | @{ $self->{tmpl_cache}}{ keys %{$tmpls} } = |
e374d8da |
454 | map ref $_ eq 'SCALAR' ? \"${$_}" : \"$_", values %{$tmpls} ; |
455 | |
59d7205c |
456 | #print Dumper $self->{tmpl_cache} ; |
e374d8da |
457 | |
458 | return ; |
459 | } |
460 | |
461 | sub delete_templates { |
462 | |
463 | my( $self, @names ) = @_ ; |
464 | |
060b866c |
465 | # delete all the cached stuff or just the names passed in |
466 | |
59d7205c |
467 | @names = keys %{$self->{tmpl_cache}} unless @names ; |
e374d8da |
468 | |
060b866c |
469 | # clear out all the caches |
470 | # TODO: reorg these into a hash per name |
471 | |
59d7205c |
472 | delete @{$self->{tmpl_cache}}{ @names } ; |
060b866c |
473 | delete @{$self->{compiled_cache}}{ @names } ; |
474 | delete @{$self->{source_cache}}{ @names } ; |
475 | |
476 | # also remove where we found it to force a fresh search |
e374d8da |
477 | |
478 | delete @{$self->{template_paths}}{ @names } ; |
479 | |
480 | return ; |
481 | } |
482 | |
483 | sub _get_template { |
484 | |
485 | my( $self, $tmpl_name ) = @_ ; |
486 | |
487 | #print "INC $tmpl_name\n" ; |
488 | |
59d7205c |
489 | my $tmpls = $self->{tmpl_cache} ; |
e374d8da |
490 | |
491 | # get the template from the cache and send it back if it was found there |
492 | |
493 | my $template = $tmpls->{ $tmpl_name } ; |
494 | return $template if $template ; |
495 | |
496 | # not found, so find, slurp in and cache the template |
497 | |
498 | $template = $self->_find_template( $tmpl_name ) ; |
499 | $tmpls->{ $tmpl_name } = $template ; |
500 | |
501 | return $template ; |
502 | } |
503 | |
504 | sub _find_template { |
505 | |
506 | my( $self, $tmpl_name ) = @_ ; |
507 | |
508 | foreach my $dir ( @{$self->{include_paths}} ) { |
509 | |
510 | my $tmpl_path = "$dir/$tmpl_name.tmpl" ; |
511 | |
512 | #print "PATH: $tmpl_path\n" ; |
513 | next unless -r $tmpl_path ; |
514 | |
515 | # cache the path to this template |
516 | |
517 | $self->{template_paths}{$tmpl_name} = $tmpl_path ; |
518 | |
519 | # slurp in the template file and return it as a scalar ref |
520 | |
521 | return scalar read_file( $tmpl_path, scalar_ref => 1 ) ; |
522 | } |
523 | |
524 | die <<DIE ; |
525 | can't find template '$tmpl_name' in '@{$self->{include_paths}}' |
526 | DIE |
527 | |
528 | } |
529 | |
530 | 1; # End of Template::Simple |
531 | |
532 | __END__ |
533 | |
534 | =head1 NAME |
535 | |
536 | Template::Simple - A simple and fast template module |
537 | |
538 | =head1 VERSION |
539 | |
540 | Version 0.03 |
541 | |
542 | =head1 SYNOPSIS |
543 | |
544 | use Template::Simple; |
545 | |
546 | my $tmpl = Template::Simple->new(); |
547 | |
548 | my $template = <<TMPL ; |
549 | [%INCLUDE header%] |
550 | [%START row%] |
551 | [%first%] - [%second%] |
552 | [%END row%] |
553 | [%INCLUDE footer%] |
554 | TMPL |
555 | |
556 | my $data = { |
557 | header => { |
558 | date => 'Jan 1, 2008', |
559 | author => 'Me, myself and I', |
560 | }, |
561 | row => [ |
562 | { |
563 | first => 'row 1 value 1', |
564 | second => 'row 1 value 2', |
565 | }, |
566 | { |
567 | first => 'row 2 value 1', |
568 | second => 'row 2 value 2', |
569 | }, |
570 | ], |
571 | footer => { |
572 | modified => 'Aug 31, 2006', |
573 | }, |
574 | } ; |
575 | |
576 | my $rendered = $tmpl->render( $template, $data ) ; |
577 | |
578 | =head1 DESCRIPTION |
579 | |
580 | Template::Simple has these goals: |
581 | |
582 | =over 4 |
583 | |
584 | =item * Support most common template operations |
585 | |
586 | It can recursively include other templates, replace tokens (scalars), |
587 | recursively render nested chunks of text and render lists. By using |
588 | simple idioms you can get conditional renderings. |
589 | |
590 | =item * Complete isolation of template from program code |
591 | |
592 | This is very important as template design can be done by different |
593 | people than the program logic. It is rare that one person is well |
594 | skilled in both template design and also programming. |
595 | |
596 | =item * Very simple template markup (only 4 markups) |
597 | |
598 | The only markups are C<INCLUDE>, C<START>, C<END> and C<token>. See |
599 | MARKUP for more. |
600 | |
601 | =item * Easy to follow rendering rules |
602 | |
603 | Rendering of templates and chunks is driven from a data tree. The type |
604 | of the data element used in an rendering controls how the rendering |
605 | happens. The data element can be a scalar or scalar reference or an |
606 | array, hash or code reference. |
607 | |
608 | =item * Efficient template rendering |
609 | |
610 | Rendering is very simple and uses Perl's regular expressions |
611 | efficiently. Because the markup is so simple less processing is needed |
612 | than many other templaters. Precompiling templates is not supported |
613 | yet but that optimization is on the TODO list. |
614 | |
615 | =item * Easy user extensions |
616 | |
617 | User code can be called during an rendering so you can do custom |
618 | renderings and plugins. Closures can be used so the code can have its |
619 | own private data for use in rendering its template chunk. |
620 | |
621 | =back |
622 | |
623 | =head2 new() |
624 | |
625 | You create a Template::Simple by calling the class method new: |
626 | |
627 | my $tmpl = Template::Simple->new() ; |
628 | |
629 | All the arguments to C<new()> are key/value options that change how |
630 | the object will do renderings. |
631 | |
632 | =over 4 |
633 | |
634 | =item pre_delim |
635 | |
636 | This option sets the string or regex that is the starting delimiter |
637 | for all markups. You can use a plain string or a qr// but you need to |
638 | escape (with \Q or \) any regex metachars if you want them to be plain |
639 | chars. The default is qr/\[%/. |
640 | |
641 | my $tmpl = Template::Simple->new( |
642 | pre_delim => '<%', |
643 | ); |
644 | |
645 | my $rendered = $tmpl->render( '<%FOO%]', 'bar' ) ; |
646 | |
647 | =item post_delim |
648 | |
649 | This option sets the string or regex that is the ending delimiter |
650 | for all markups. You can use a plain string or a qr// but you need to |
651 | escape (with \Q or \) any regex metachars if you want them to be plain |
652 | chars. The default is qr/%]/. |
653 | |
654 | my $tmpl = Template::Simple->new( |
655 | post_delim => '%>', |
656 | ); |
657 | |
658 | my $rendered = $tmpl->render( '[%FOO%>', 'bar' ) ; |
659 | |
660 | =item greedy_chunk |
661 | |
662 | This boolean option will cause the regex that grabs a chunk of text |
663 | between the C<START/END> markups to become greedy (.+). The default is |
664 | a not-greedy grab of the chunk text. (UNTESTED) |
665 | |
666 | =item templates |
667 | |
668 | This option lets you load templates directly into the cache of the |
669 | Template::Simple object. This cache will be searched by the C<INCLUDE> |
670 | markup which will be replaced by the template if found. The option |
671 | value is a hash reference which has template names (the name in the |
672 | C<INCLUDE> markup) for keys and their template text as their |
673 | values. You can delete or clear templates from the object cache with |
674 | the C<delete_template> method. |
675 | |
676 | |
677 | my $tmpl = Template::Simple->new( |
678 | templates => { |
679 | |
680 | foo => <<FOO, |
681 | [%baz%] is a [%quux%] |
682 | FOO |
683 | bar => <<BAR, |
684 | [%user%] is not a [%fool%] |
685 | BAR |
686 | }, |
687 | ); |
688 | |
689 | my $template = <<TMPL ; |
690 | [%INCLUDE foo %] |
691 | TMPL |
692 | |
693 | my $rendered = $tmpl->render( |
694 | $template, |
695 | { |
696 | baz => 'blue', |
697 | quux => 'color, |
698 | } |
699 | ) ; |
700 | |
701 | =item include_paths |
702 | |
703 | Template::Simple can also load C<INCLUDE> templates from files. This |
704 | option lets you set the directory paths to search for those |
705 | files. Note that the template name in the C<INCLUDE> markup has the |
706 | .tmpl suffix appended to it when searched for in one of these |
707 | paths. The loaded file is cached inside the Template::Simple object |
708 | along with any loaded by the C<templates> option. |
709 | |
710 | =back |
711 | |
712 | =head1 METHODS |
713 | |
714 | =head2 render |
715 | |
716 | This method is passed a template and a data tree and it renders it and |
717 | returns a reference to the resulting string. The template argument can |
718 | be a scalar or a scalar reference. The data tree argument can be any |
719 | value allowed by Template::Simple when rendering a template. It can |
720 | also be a blessed reference (Perl object) since |
721 | C<Scalar::Util::reftype> is used instead of C<ref> to determine the |
722 | data type. |
723 | |
724 | Note that the author recommends against passing in an object as this |
725 | breaks encapsulation and forces your object to be (most likely) a |
726 | hash. It would be better to create a simple method that copies the |
727 | object contents to a hash reference and pass that. But current |
728 | templaters allow passing in objects so that is supported here as well. |
729 | |
730 | my $rendered = $tmpl->render( $template, $data ) ; |
731 | |
732 | =head2 add_templates |
733 | |
734 | This method adds templates to the object cache. It takes a list of template names and texts just like the C<templates> constructor option. |
735 | |
736 | $tmpl->add_templates( |
737 | { |
738 | foo => \$foo_template, |
739 | bar => '[%include bar%]', |
740 | } |
741 | ) ; |
742 | |
743 | =head2 delete_templates |
744 | |
745 | This method takes a list of template names and will delete them from |
746 | the template cache in the object. If you pass in an empty list then |
747 | all the templates will be deleted. This can be used when you know a |
748 | template file has been updated and you want to get it loaded back into |
749 | the cache. Note that you can delete templates that were loaded |
750 | directly (via the C<templates> constructor option or the |
751 | C<add_templates> method) or loaded from a file. |
752 | |
753 | # this deletes only the foo and bar templates from the object cache |
754 | |
755 | $tmpl->delete_templates( qw( foo bar ) ; |
756 | |
757 | # this deletes all of templates from the object cache |
758 | |
759 | $tmpl->delete_templates() ; |
760 | |
761 | =head2 get_dependencies |
762 | |
763 | This method render the only C<INCLUDE> markups of a template and it |
764 | returns a list of the file paths that were found and loaded. It is |
765 | meant to be used to build up a dependency list of included templates |
766 | for a main template. Typically this can be called from a script (see |
767 | TODO) that will do this for a set of main templates and will generate |
768 | Makefile dependencies for them. Then you can regenerate rendered |
769 | templates only when any of their included templates have changed. It |
770 | takes a single argument of a template. |
771 | |
772 | UNKNOWN: will this require a clearing of the cache or will it do the |
773 | right thing on its own? or will it use the file path cache? |
774 | |
775 | my @dependencies = |
776 | $tmpl->get_dependencies( '[%INCLUDE top_level%]' ); |
777 | |
778 | =head1 MARKUP |
779 | |
780 | All the markups in Template::Simple use the same delimiters which are |
781 | C<[%> and C<%]>. You can change the delimiters with the C<pre_delim> |
782 | and C<post_delim> options in the C<new()> constructor. |
783 | |
784 | =head2 Tokens |
785 | |
786 | A token is a single markup with a C<\w+> Perl word inside. The token |
787 | can have optional whitespace before and after it. A token is replaced |
788 | by a value looked up in a hash with the token as the key. The hash |
789 | lookup keeps the same case as parsed from the token markup. |
790 | |
791 | [% foo %] [%BAR%] |
792 | |
793 | Those will be replaced by C<$href->{foo}> and C<$href->{BAR}> assuming |
794 | C<$href> is the current data for this rendering. Tokens are only |
795 | parsed out during hash data rendering so see Hash Data for more. |
796 | |
797 | =head2 Chunks |
798 | |
799 | Chunks are regions of text in a template that are marked off with a |
800 | start and end markers with the same name. A chunk start marker is |
801 | C<[%START name%]> and the end marker for that chunk is C<[%END |
802 | name%]>. C<name> is a C<\w+> Perl word which is the name of this |
803 | chunk. The whitespace between C<START/END> and C<name> is required and |
804 | there is optional whitespace before C<START/END> and after the |
805 | C<name>. C<START/END> are case insensitive but the C<name>'s case is |
806 | kept. C<name> must match in the C<START/END> pair and it used as a key |
807 | in a hash data rendering. Chunks are the primary way to markup |
808 | templates for structures (sets of tokens), nesting (hashes of hashes), |
809 | repeats (array references) and callbacks to user code. Chunks are only |
810 | parsed out during hash data rendering so see Hash Data for more. |
811 | |
812 | The body of text between the C<START/END> markups is grabbed with a |
813 | C<.+?> regular expression with the /s option enabled so it will match |
814 | all characters. By default it will be a non-greedy grab but you can |
815 | change that in the constructor by enabling the C<greedy_chunk> option. |
816 | |
817 | [%Start FOO%] |
818 | [% START bar %] |
819 | [% field %] |
820 | [% end bar %] |
821 | [%End FOO%] |
822 | |
823 | =head2 Includes |
824 | |
825 | =head1 RENDERING RULES |
826 | |
827 | Template::Simple has a short list of rendering rules and they are easy |
828 | to understand. There are two types of renderings, include rendering |
829 | and chunk rendering. In the C<render> method, the template is an |
830 | unnamed top level chunk of text and it first gets its C<INCLUDE> |
831 | markups rendered. The text then undergoes a chunk rendering and a |
832 | scalar reference to that rendered template is returned to the caller. |
833 | |
834 | =head2 Include Rendering |
835 | |
836 | Include rendering is performed one time on a top level template. When |
837 | it is done the template is ready for chunk rendering. Any markup of |
838 | the form C<[%INCLUDE name]%> will be replaced by the text found in the |
839 | template C<name>. The template name is looked up in the object's |
840 | template cache and if it is found there its text is used as the |
841 | replacement. |
842 | |
843 | If a template is not found in the cache, it will be searched for in |
844 | the list of directories in the C<include_paths> option. The file name |
845 | will be a directory in that list appended with the template name and |
846 | the C<.tmpl> suffix. The first template file found will be read in and |
847 | stored in the cache. Its path is also saved and those will be returned |
848 | in the C<get_dependencies> method. See the C<add_templates> and |
849 | C<delete_templates> methods and the C<include_paths> option. |
850 | |
851 | Rendered include text can contain more C<INCLUDE> markups and they |
852 | will also be rendered. The include rendering phase ends where there |
853 | are no more C<INCLUDE> found. |
854 | |
855 | =head2 Chunk Rendering |
856 | |
857 | A chunk is the text found between C<START> and C<END> markups and it |
858 | gets its named from the C<START> markup. The top level template is |
859 | considered an unamed chunk and also gets chunk rendered. |
860 | |
861 | The data for a chunk determines how it will be rendered. The data can |
862 | be a scalar or scalar reference or an array, hash or code |
863 | reference. Since chunks can contain nested chunks, rendering will |
864 | recurse down the data tree as it renders the chunks. Each of these |
865 | renderings are explained below. Also see the IDIOMS and BEST PRACTICES |
866 | section for examples and used of these renderings. |
867 | |
868 | =head2 Scalar Data Rendering |
869 | |
870 | If the current data for a chunk is a scalar or scalar reference, the |
871 | chunk's text in the templated is replaced by the scalar's value. This |
872 | can be used to overwrite one default section of text with from the |
873 | data tree. |
874 | |
875 | =head2 Code Data Rendering |
876 | |
877 | If the current data for a chunk is a code reference (also called |
878 | anonymous sub) then the code reference is called and it is passed a |
879 | scalar reference to the that chunk's text. The code must return a |
880 | scalar or a scalar reference and its value replaces the chunk's text |
881 | in the template. If the code returns any other type of data it is a |
882 | fatal error. Code rendering is how you can do custom renderings and |
883 | plugins. A key idiom is to use closures as the data in code renderings |
884 | and keep the required outside data in the closure. |
885 | |
886 | =head2 Array Data Rendering |
887 | |
888 | If the current data for a chunk is an array reference do a full chunk |
889 | rendering for each value in the array. It will replace the original |
890 | chunk text with the joined list of rendered chunks. This is how you do |
891 | repeated sections in Template::Simple and why there is no need for any |
892 | loop markups. Note that this means that rendering a chunk with $data |
893 | and [ $data ] will do the exact same thing. A value of an empty array |
894 | C<[]> will cause the chunk to be replaced by the empty string. |
895 | |
896 | =head2 Hash Data Rendering |
897 | |
898 | If the current data for a chunk is a hash reference then two phases of |
899 | rendering happen, nested chunk rendering and token rendering. First |
900 | nested chunks are parsed of of this chunk along with their names. Each |
901 | parsed out chunk is rendered based on the value in the current hash |
902 | with the nested chunk's name as the key. |
903 | |
904 | If a value is not found (undefined), then the nested chunk is replaced |
905 | by the empty string. Otherwise the nested chunk is rendered according |
906 | to the type of its data (see chunk rendering) and it is replaced by |
907 | the rendered text. |
908 | |
909 | Chunk name and token lookup in the hash data is case sensitive (see |
910 | the TODO for cased lookups). |
911 | |
912 | Note that to keep a plain text chunk or to just have the all of its |
913 | markups (chunks and tokens) be deleted just pass in an empty hash |
914 | reference C<{}> as the data for the chunk. It will be rendered but all |
915 | markups will be replaced by the empty string. |
916 | |
917 | =head2 Token Rendering |
918 | |
919 | The second phase is token rendering. Markups of the form [%token%] are |
920 | replaced by the value of the hash element with the token as the |
921 | key. If a token's value is not defined it is replaced by the empty |
922 | string. This means if a token key is missing in the hash or its value |
923 | is undefined or its value is the empty string, the [%token%] markup |
924 | will be deleted in the rendering. |
925 | |
926 | =head1 IDIOMS and BEST PRACTICES |
927 | |
928 | With all template systems there are better ways to do things and |
929 | Template::Simple is no different. This section will show some ways to |
930 | handle typical template needs while using only the 4 markups in this |
931 | module. |
932 | |
933 | =head2 Conditionals |
934 | |
935 | This conditional idiom can be when building a fresh data tree or |
936 | modifying an existing one. |
937 | |
938 | $href->{$chunk_name} = $keep_chunk ? {} : '' ; |
939 | |
940 | If you are building a fresh data tree you can use this idiom to do a |
941 | conditional chunk: |
942 | |
943 | $href->{$chunk_name} = {} if $keep_chunk ; |
944 | |
945 | To handle an if/else conditional use two chunks, with the else chunk's |
946 | name prefixed with NOT_ (or use any name munging you want). Then you |
947 | set the data for either the true chunk (just the plain name) or the |
948 | false trunk with the NOT_ name. You can use a different name for the |
949 | else chunk if you want but keeping the names of the if/else chunks |
950 | related is a good idea. Here are two ways to set the if/else data. The |
951 | first one uses the same data for both the if and else chunks and the |
952 | second one uses different data so the it uses the full if/else code |
953 | for that. |
954 | |
955 | $href->{ ($boolean ? '' : 'NOT_') . $chunk_name} = $data |
956 | |
957 | if ( $boolean ) { |
958 | $href->{ $chunk_name} = $true_data ; |
959 | else { |
960 | $href->{ "NOT_$chunk_name" } = $false_data ; |
961 | } |
962 | |
963 | NOTE TO ALPHA USERS: i am also thinking that a non-existing key or |
964 | undefined hash value should leave the chunk as is. then you would need |
965 | to explicitly replace a chunk with the empty string if you wanted it |
966 | deleted. It does affect the list of styles idiom. Any thoughts on |
967 | this change of behavior? Since this hasn't been released it is the |
968 | time to decide this. |
969 | |
970 | =head2 Chunked Includes |
971 | |
972 | One of the benefits of using include templates is the ability to share |
973 | and reuse existing work. But if an included template has a top level |
974 | named chunk, then that name would also be the same everywhere where |
975 | this template is included. If a template included another template in |
976 | multiple places, its data tree would use the same name for each and |
977 | not allow unique data to be rendered for each include. A better way is |
978 | to have the current template wrap an include markup in a named chunk |
979 | markup. Then the data tree could use unique names for each included |
980 | template. Here is how it would look: |
981 | |
982 | [%START foo_prime%][%INCLUDE foo%][%START foo_prime%] |
983 | random noise |
984 | [%START foo_second%][%INCLUDE foo%][%START foo_second%] |
985 | |
986 | See the TODO section for some ideas on how to make this even more high level. |
987 | |
988 | =head2 Repeated Sections |
989 | |
990 | If you looked at the markup of Template::Simple you have noticed that |
991 | there is no loop or repeat construct. That is because there is no need |
992 | for one. Any chunk can be rendered in a loop just by having its |
993 | rendering data be an anonymous array. The renderer will loop over each |
994 | element of the array and do a fresh rendering of the chunk with this |
995 | data. A join (on '') of the list of renderings replaces the original |
996 | chunk and you have a repeated chunk. |
997 | |
998 | =head2 A List of Mixed Styles |
999 | |
1000 | One formating style is to have a list of sections each which can have |
1001 | its own style or content. Template::Simple can do this very easily |
1002 | with just a 2 level nested chunk and an array of data for |
1003 | rendering. The outer chunk includes (or contains) each of the desired |
1004 | styles in any order. It looks like this: |
1005 | |
1006 | [%START para_styles%] |
1007 | [%START main_style%] |
1008 | [%INCLUDE para_style_main%] |
1009 | [%END main_style%] |
1010 | [%START sub_style%] |
1011 | [%INCLUDE para_style_sub%] |
1012 | [%END sub_style%] |
1013 | [%START footer_style%] |
1014 | [%INCLUDE para_style_footer%] |
1015 | [%END footer_style%] |
1016 | [%END para_styles%] |
1017 | |
1018 | The other part to make this work is in the data tree. The data for |
1019 | para_styles should be a list of hashes. Each hash contains the data |
1020 | for one pargraph style which is keyed by the style's chunk name. Since |
1021 | the other styles's chunk names are not hash they are deleted. Only the |
1022 | style which has its name as a key in the hash is rendered. The data |
1023 | tree would look something like this: |
1024 | |
1025 | [ |
1026 | { |
1027 | main_style => $main_data, |
1028 | }, |
1029 | { |
1030 | sub_style => $sub_data, |
1031 | }, |
1032 | { |
1033 | sub_style => $other_sub_data, |
1034 | }, |
1035 | { |
1036 | footer_style => $footer_data, |
1037 | }, |
1038 | ] |
1039 | |
1040 | =head1 TESTS |
1041 | |
1042 | The test scripts use a common test driver module in t/common.pl. It is |
1043 | passed a list of hashes, each of which has the data for one test. A |
1044 | test can create a ne Template::Simple object or use the one from the |
1045 | previous test. The template source, the data tree and the expected |
1046 | results are also important keys. See the test scripts for examples of |
1047 | how to write tests using this common driver. |
1048 | |
1049 | =over 4 |
1050 | |
1051 | =item name |
1052 | |
1053 | This is the name of the test and is used by Test::More |
1054 | |
1055 | =item opts |
1056 | |
1057 | This is a hash ref of the options passed to the Template::Simple |
1058 | constructor. The object is not built if the C<keep_obj> key is set. |
1059 | |
1060 | =item keep_obj |
1061 | |
1062 | If set, this will make this test keep the Template::Simple object from |
1063 | the previous test and not build a new one. |
1064 | |
1065 | =item template |
1066 | |
1067 | This is the template to render for this test. If not set, the test |
1068 | driver will use the template from the previous test. This is useful to |
1069 | run a series of test variants with the same template. |
1070 | |
1071 | =item data |
1072 | |
1073 | This is the data tree for the rendering of the template. |
1074 | |
1075 | =item expected |
1076 | |
1077 | This is the text that is expected after the rendering. |
1078 | |
1079 | =item skip |
1080 | |
1081 | If set, this test is skipped. |
1082 | |
1083 | =back |
1084 | |
1085 | =head1 TODO |
1086 | |
1087 | Even though this template system is simple, that doesn't mean it can't |
1088 | be extended in many ways. Here are some features and designs that |
1089 | would be good extensions which add useful functionality without adding |
1090 | too much complexity. |
1091 | |
1092 | =head2 Compiled Templates |
1093 | |
1094 | A commonly performed optimization in template modules is to precompile |
1095 | (really preparse) templates into a internal form that will render |
1096 | faster. Precompiling is slower than rendering from the original |
1097 | template which means you won't want to do it for each rendering. This |
1098 | means it has a downside that you lose out when you want to render |
1099 | using templates which change often. Template::Simple makes it very |
1100 | easy to precompile as it already has the regexes to parse out the |
1101 | markup. So instead of calling subs to do actual rendering, a |
1102 | precompiler would call subs to generate a compiled rendering tree. |
1103 | The rendering tree can then be run or processes with rendering data |
1104 | passed to it. You can think of a precompiled template as having all |
1105 | the nested chunks be replaced by nested code that does the same |
1106 | rendering. It can still do the dynamic rendering of the data but it |
1107 | saves the time of parsing the template souice. There are three |
1108 | possible internal formats for the precompiled template: |
1109 | |
1110 | =over 4 |
1111 | |
1112 | =item Source code |
1113 | |
1114 | This precompiler will generate source code that can be stored and/or |
1115 | eval'ed. The eval'ed top level sub can then be called and passed the |
1116 | rendering data. |
1117 | |
1118 | =item Closure call tree |
1119 | |
1120 | The internal format can be a nested set of closures. Each closure would contain |
1121 | private data such as fixed text parts of the original template, lists |
1122 | of other closures to run, etc. It is trivial to write a basic closure |
1123 | generator which will make build this tree a simple task. |
1124 | |
1125 | =item Code ref call tree |
1126 | |
1127 | This format is a Perl data tree where the nodes have a code reference |
1128 | and its args (which can be nested instances of the same |
1129 | nodes). Instead of executing this directly, you will need a small |
1130 | interpreter to execute all the code refs as it runs through the tree. |
1131 | |
1132 | This would make for a challenging project to any intermediate Perl |
1133 | hacker. It just involves knowing recursion, data trees and code refs. |
1134 | Contact me if you are interested in doing this. |
1135 | |
1136 | =back |
1137 | |
1138 | =head2 Cased Hash Lookups |
1139 | |
1140 | One possible option is to allow hash renderings to always use upper or |
1141 | lower cased keys in their lookups. |
1142 | |
1143 | =head2 Render tokens before includes and chunks |
1144 | |
1145 | Currently tokens are rendered after includes and chunks. If tokens |
1146 | were rendered in a pass before the others, the include and chunk names |
1147 | could be dynamically set. This would make it harder to precompile |
1148 | templates as too much would be dynamic, i.e. you won't know what the |
1149 | fixed text to parse out is since anything can be included at render |
1150 | time. But the extra flexibility of changing the include and chunk |
1151 | names would be interesting. It could be done easily and enabled by an |
1152 | option. |
1153 | |
1154 | =head2 Plugins |
1155 | |
1156 | There are two different potential areas in Template::Simple that could |
1157 | use plugins. The first is with the rendering of chunkas and |
1158 | dispatching based on the data type. This dispatch table can easily be |
1159 | replaced by loaded modules which offer a different way to |
1160 | render. These include the precompiled renderers mentioned above. The |
1161 | other area is with code references as the data type. By defining a |
1162 | closure (or a closure making) API you can create different code refs |
1163 | for the rendering data. The range of plugins is endless some of the |
1164 | major template modules have noticed. One idea is to make a closure |
1165 | which contains a different Template::Simple object than the current |
1166 | one. This will allow rendering of a nested chunk with different rules |
1167 | than the current chunk being rendered. |
1168 | |
1169 | =head2 Data Escaping |
1170 | |
1171 | Some templaters have options to properly escape data for some types of |
1172 | text files such as html. this can be done with some variant of the |
1173 | _render_hash routine which also does the scalar rendering (which is |
1174 | where data is rendered). The rendering scalars code could be factored |
1175 | out into a set of subs one of which is used based on any escaping |
1176 | needs. |
1177 | |
1178 | =head2 Data Tree is an Object |
1179 | |
1180 | This is a concept I don't like but it was requested so it goes into |
1181 | the TODO file. Currently C<render> can only be passed a regular |
1182 | (unblessed) ref (or a scalar) for its data tree. Passing in an object |
1183 | would break encapsulation and force the object layout to be a hash |
1184 | tree that matches the layout of the template. I doubt that most |
1185 | objects will want to be organized to match a template. I have two |
1186 | ideas, one is that you add a method to that object that builds up a |
1187 | proper (unblessed) data tree to pass to C<render>. The other is by |
1188 | subclassing C<Template::Simple> and overriding C<render> with a sub |
1189 | that does take an object hash and it can unbless it or build a proper |
1190 | data tree and then call C<render> in SUPER::. A quick solution is to |
1191 | use C<reftype> (from Scalar::Utils) instead of C<ref> to allow object |
1192 | hashes to be passed in. |
1193 | |
1194 | =head2 Includes and Closure Synergy |
1195 | |
1196 | By pairing up an include template along with code that can generate |
1197 | the appropriate data tree for its rendering, you can create a higher |
1198 | level template framework (the synergy). Additional code can be |
1199 | associated with them that will handle input processing and |
1200 | verification for the templates (e.g. web forms) that need it. A key to |
1201 | this will be making all the closures for the data tree. This can be |
1202 | greatly simplified by using a closure maker sub that can create all |
1203 | the required closures. |
1204 | |
1205 | =head2 Metafields and UI Generation |
1206 | |
1207 | Taking the synergy up to a much higher level is the concept of meta |
1208 | knowledge of fields which can generate templates, output processing |
1209 | (data tree generation), input processing, DB backing and more. If you |
1210 | want to discuss such grandiose wacky application schemes in a long |
1211 | rambling mind bending conversation, please contact me. |
1212 | |
1213 | =head2 More Examples and Idioms |
1214 | |
1215 | As I convert several scripts over to this module (they all used the |
1216 | hack version), I will add them to an examples section or possibly put |
1217 | them in another (pod only) module. Similarly the Idioms section needs |
1218 | rendering and could be also put into a pod module. One goal requested |
1219 | by an early alpha tester is to keep the primary docs as simple as the |
1220 | markup itself. This means moving all the extra stuff (and plenty of |
1221 | that) into other pod modules. All the pod modules would be in the same |
1222 | cpan tarball so you get all the docs and examples when you install |
1223 | this. |
1224 | |
1225 | =head1 AUTHOR |
1226 | |
1227 | Uri Guttman, C<< <uri at sysarch.com> >> |
1228 | |
1229 | =head1 BUGS |
1230 | |
1231 | Please report any bugs or feature requests to |
1232 | C<bug-template-simple at rt.cpan.org>, or through the web interface at |
1233 | L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Template-Simple>. |
1234 | I will be notified, and then you'll automatically be notified of progress on |
1235 | your bug as I make changes. |
1236 | |
1237 | =head1 SUPPORT |
1238 | |
1239 | You can find documentation for this module with the perldoc command. |
1240 | |
1241 | perldoc Template::Simple |
1242 | |
1243 | You can also look for information at: |
1244 | |
1245 | =over 4 |
1246 | |
1247 | =item * RT: CPAN's request tracker |
1248 | |
1249 | L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Template-Simple> |
1250 | |
1251 | =item * Search CPAN |
1252 | |
1253 | L<http://search.cpan.org/dist/Template-Simple> |
1254 | |
1255 | =back |
1256 | |
1257 | =head1 ACKNOWLEDGEMENTS |
1258 | |
1259 | I wish to thank Turbo10 for their support in developing this module. |
1260 | |
1261 | =head1 COPYRIGHT & LICENSE |
1262 | |
1263 | Copyright 2006 Uri Guttman, all rights reserved. |
1264 | |
1265 | This program is free software; you can redistribute it and/or modify it |
1266 | under the same terms as Perl itself. |
1267 | |
1268 | =cut |
1269 | |
1270 | |
1271 | find templates and tests |
1272 | |
1273 | deep nesting tests |
1274 | |
1275 | greedy tests |
1276 | |
1277 | methods pod |
1278 | |
1279 | delete_templates test |
1280 | |
1281 | pod cleanup |
1282 | |
1283 | fine edit |
1284 | |
1285 | more tests |
1286 | |
1287 | slurp dependency in makefile.pl |
1288 | |