Commit | Line | Data |
f12977de |
1 | package Template::Simple ; |
e374d8da |
2 | |
f12977de |
3 | use warnings ; |
4 | use strict ; |
e374d8da |
5 | |
6 | use Carp ; |
9d1a25cd |
7 | use Data::Dumper ; |
f12977de |
8 | use Scalar::Util qw( reftype blessed ) ; |
e374d8da |
9 | use File::Slurp ; |
10 | |
f12977de |
11 | our $VERSION = '0.06'; |
e374d8da |
12 | |
13 | my %opt_defaults = ( |
14 | |
15 | pre_delim => qr/\[%/, |
16 | post_delim => qr/%\]/, |
a5b978a4 |
17 | token_re => qr/\w+?/, |
e374d8da |
18 | greedy_chunk => 0, |
19 | # upper_case => 0, |
20 | # lower_case => 0, |
f12977de |
21 | search_dirs => [ qw( templates ) ], |
e374d8da |
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 | |
f12977de |
32 | # support the old name 'include_paths' ; |
33 | |
34 | $opts{search_dirs} ||= delete $opts{include_paths} ; |
35 | |
e374d8da |
36 | while( my( $name, $default ) = each %opt_defaults ) { |
37 | |
38 | $self->{$name} = defined( $opts{$name} ) ? |
39 | $opts{$name} : $default ; |
40 | } |
41 | |
f12977de |
42 | croak "search_dirs is not an ARRAY reference" unless |
43 | ref $self->{search_dirs} eq 'ARRAY' ; |
44 | |
e374d8da |
45 | # make up the regexes to parse the markup from templates |
46 | |
47 | # this matches scalar markups and grabs the name |
48 | |
49 | $self->{scalar_re} = qr{ |
50 | $self->{pre_delim} |
51 | \s* # optional leading whitespace |
a5b978a4 |
52 | ($self->{token_re}) # grab scalar name |
e374d8da |
53 | \s* # optional trailing whitespace |
54 | $self->{post_delim} |
55 | }xi ; # case insensitive |
56 | |
57 | #print "RE <$self->{scalar_re}>\n" ; |
58 | |
59 | # this grabs the body of a chunk in either greedy or non-greedy modes |
60 | |
61 | my $chunk_body = $self->{greedy_chunk} ? qr/.+/s : qr/.+?/s ; |
62 | |
63 | # this matches a marked chunk and grabs its name and text body |
64 | |
65 | $self->{chunk_re} = qr{ |
66 | $self->{pre_delim} |
67 | \s* # optional leading whitespace |
68 | START # required START token |
69 | \s+ # required whitespace |
a5b978a4 |
70 | ($self->{token_re}) # grab the chunk name |
e374d8da |
71 | \s* # optional trailing whitespace |
72 | $self->{post_delim} |
73 | ($chunk_body) # grab the chunk body |
74 | $self->{pre_delim} |
75 | \s* # optional leading whitespace |
76 | END # required END token |
77 | \s+ # required whitespace |
78 | \1 # match the grabbed chunk name |
79 | \s* # optional trailing whitespace |
80 | $self->{post_delim} |
81 | }xi ; # case insensitive |
82 | |
83 | #print "RE <$self->{chunk_re}>\n" ; |
84 | |
85 | # this matches a include markup and grabs its template name |
86 | |
87 | $self->{include_re} = qr{ |
88 | $self->{pre_delim} |
89 | \s* # optional leading whitespace |
90 | INCLUDE # required INCLUDE token |
91 | \s+ # required whitespace |
a5b978a4 |
92 | ($self->{token_re}) # grab the included template name |
e374d8da |
93 | \s* # optional trailing whitespace |
94 | $self->{post_delim} |
95 | }xi ; # case insensitive |
96 | |
97 | # load in any templates |
98 | |
99 | $self->add_templates( $opts{templates} ) ; |
100 | |
101 | return $self ; |
102 | } |
103 | |
59d7205c |
104 | sub compile { |
e374d8da |
105 | |
59d7205c |
106 | my( $self, $template_name ) = @_ ; |
107 | |
108 | my $tmpl_ref = eval { |
109 | $self->_get_template( $template_name ) ; |
110 | } ; |
111 | |
f12977de |
112 | #print Dumper $self ; |
113 | |
59d7205c |
114 | croak "Template::Simple $@" if $@ ; |
115 | |
f12977de |
116 | my $included = $self->_render_includes( $tmpl_ref ) ; |
117 | |
59d7205c |
118 | # compile a copy of the template as it will be destroyed |
119 | |
f12977de |
120 | my $code_body = $self->_compile_chunk( '', "${$included}", "\t" ) ; |
59d7205c |
121 | |
89bd07c7 |
122 | my $source = <<CODE ; |
59d7205c |
123 | no warnings ; |
124 | |
125 | sub { |
126 | my( \$data ) = \@_ ; |
127 | |
9d1a25cd |
128 | my \$out ; |
59d7205c |
129 | |
f12977de |
130 | use Scalar::Util qw( reftype ) ; |
131 | |
9d1a25cd |
132 | $code_body |
59d7205c |
133 | return \\\$out ; |
134 | } |
135 | CODE |
136 | |
89bd07c7 |
137 | #print $source ; |
59d7205c |
138 | |
89bd07c7 |
139 | my $code_ref = eval $source ; |
59d7205c |
140 | |
f12977de |
141 | #print $@ if $@ ; |
59d7205c |
142 | |
143 | $self->{compiled_cache}{$template_name} = $code_ref ; |
89bd07c7 |
144 | $self->{source_cache}{$template_name} = $source ; |
145 | } |
146 | |
9d1a25cd |
147 | sub _compile_chunk { |
89bd07c7 |
148 | |
9d1a25cd |
149 | my( $self, $chunk_name, $template, $indent ) = @_ ; |
89bd07c7 |
150 | |
9d1a25cd |
151 | return '' unless length $template ; |
59d7205c |
152 | |
9d1a25cd |
153 | # generate a lookup in data for this chunk name (unless it is the top |
154 | # level). this descends down the data tree during rendering |
59d7205c |
155 | |
9d1a25cd |
156 | my $data_init = $chunk_name ? "\$data->{$chunk_name}" : '$data' ; |
59d7205c |
157 | |
9d1a25cd |
158 | my $code = <<CODE ; |
159 | ${indent}my \@data = $data_init ; |
52705b1c |
160 | ${indent}while( \@data ) { |
59d7205c |
161 | |
52705b1c |
162 | ${indent} my \$data = shift \@data ; |
f12977de |
163 | ${indent} if ( reftype \$data eq 'ARRAY' ) { |
9d1a25cd |
164 | ${indent} push \@data, \@{\$data} ; |
165 | ${indent} next ; |
166 | ${indent} } |
59d7205c |
167 | |
9d1a25cd |
168 | CODE |
169 | |
170 | $indent .= "\t" ; |
59d7205c |
171 | |
172 | # loop all nested chunks and the text separating them |
173 | |
52705b1c |
174 | while( my( $parsed_name, $parsed_body ) = |
175 | $template =~ m{$self->{chunk_re}} ) { |
59d7205c |
176 | |
544b9c25 |
177 | my $chunk_left_index = $-[0] ; |
178 | my $chunk_right_index = $+[0] ; |
179 | |
9d1a25cd |
180 | # get the pre-match text and compile its scalars and text. append to the code |
59d7205c |
181 | |
9d1a25cd |
182 | $code .= $self->_compile_scalars( |
544b9c25 |
183 | substr( $template, 0, $chunk_left_index ), $indent ) ; |
59d7205c |
184 | |
ca30cbfe |
185 | # print "CHUNK: [$1] BODY [$2]\n\n" ; |
544b9c25 |
186 | # print "TRUNC: [", substr( $template, 0, $chunk_right_index ), "]\n\n" ; |
187 | # print "PRE: [", substr( $template, 0, $chunk_left_index ), "]\n\n" ; |
188 | |
189 | # chop off the pre-match and the chunk |
190 | |
191 | substr( $template, 0, $chunk_right_index, '' ) ; |
192 | |
193 | # print "REMAIN: [$template]\n\n" ; |
ca30cbfe |
194 | |
9d1a25cd |
195 | # compile the nested chunk and append to the code |
59d7205c |
196 | |
52705b1c |
197 | $code .= $self->_compile_chunk( |
198 | $parsed_name, $parsed_body, $indent |
199 | ) ; |
59d7205c |
200 | } |
201 | |
9d1a25cd |
202 | # compile trailing text for scalars and append to the code |
59d7205c |
203 | |
9d1a25cd |
204 | $code .= $self->_compile_scalars( $template, $indent ) ; |
7dd12000 |
205 | |
206 | chop $indent ; |
59d7205c |
207 | |
9d1a25cd |
208 | # now we end the loop for this chunk |
7dd12000 |
209 | $code .= <<CODE ; |
7dd12000 |
210 | $indent} |
7dd12000 |
211 | CODE |
59d7205c |
212 | |
59d7205c |
213 | return $code ; |
214 | } |
215 | |
216 | sub _compile_scalars { |
217 | |
9d1a25cd |
218 | my( $self, $template, $indent ) = @_ ; |
59d7205c |
219 | |
220 | # if the template is empty return no parts |
221 | |
9d1a25cd |
222 | return '' unless length $template ; |
59d7205c |
223 | |
224 | my @parts ; |
225 | |
226 | while( $template =~ m{$self->{scalar_re}}g ) { |
227 | |
9d1a25cd |
228 | # get the pre-match text before the scalar markup and generate code to |
229 | # access the scalar |
59d7205c |
230 | |
231 | push( @parts, |
f12977de |
232 | _dump_text( substr( $template, 0, $-[0] ) ), |
59d7205c |
233 | "\$data->{$1}" |
234 | ) ; |
ca30cbfe |
235 | |
236 | # truncate the matched text so the next match starts at begining of string |
237 | |
59d7205c |
238 | substr( $template, 0, $+[0], '' ) ; |
239 | } |
240 | |
241 | # keep any trailing text part |
242 | |
f12977de |
243 | push @parts, _dump_text( $template ) ; |
59d7205c |
244 | |
9d1a25cd |
245 | my $parts_code = join( "\n$indent.\n$indent", @parts ) ; |
246 | |
247 | return <<CODE ; |
248 | |
f12977de |
249 | ${indent}\$out .= reftype \$data ne 'HASH' ? \$data : |
9d1a25cd |
250 | ${indent}$parts_code ; |
251 | |
252 | CODE |
59d7205c |
253 | } |
254 | |
59d7205c |
255 | |
f12977de |
256 | # internal sub to dump text for the template compiler. the output is |
257 | # a legal perl double quoted string without any leading text before |
258 | # the opening " and no trailing newline or ; |
259 | |
260 | sub _dump_text { |
59d7205c |
261 | |
262 | my( $text ) = @_ ; |
263 | |
264 | return unless length $text ; |
265 | |
266 | local( $Data::Dumper::Useqq ) = 1 ; |
267 | |
268 | my $dumped = Dumper $text ; |
269 | |
270 | $dumped =~ s/^[^"]+// ; |
271 | $dumped =~ s/;\n$// ; |
272 | |
273 | return $dumped ; |
274 | } |
e374d8da |
275 | |
9d1a25cd |
276 | sub get_source { |
277 | |
278 | my( $self, $template_name ) = @_ ; |
279 | |
280 | return $self->{source_cache}{$template_name} ; |
281 | } |
282 | |
e374d8da |
283 | sub render { |
284 | |
59d7205c |
285 | my( $self, $template_name, $data ) = @_ ; |
286 | |
7dd12000 |
287 | my $tmpl_ref = ref $template_name eq 'SCALAR' ? $template_name : '' ; |
59d7205c |
288 | |
7dd12000 |
289 | unless( $tmpl_ref ) { |
59d7205c |
290 | |
7dd12000 |
291 | # render with cached code and return if we precompiled this template |
e374d8da |
292 | |
7dd12000 |
293 | if ( my $compiled = $self->{compiled_cache}{$template_name} ) { |
59d7205c |
294 | |
7dd12000 |
295 | return $compiled->($data) ; |
296 | } |
59d7205c |
297 | |
544b9c25 |
298 | # not compiled so try to get this template by name or |
299 | # assume the template name are is the actual template |
7dd12000 |
300 | |
544b9c25 |
301 | $tmpl_ref = |
f12977de |
302 | eval{ $self->_get_template( $template_name ) } || |
544b9c25 |
303 | \$template_name ; |
7dd12000 |
304 | } |
e374d8da |
305 | |
306 | my $rendered = $self->_render_includes( $tmpl_ref ) ; |
307 | |
308 | #print "INC EXP <$rendered>\n" ; |
309 | |
310 | $rendered = eval { |
311 | $self->_render_chunk( $rendered, $data ) ; |
312 | } ; |
313 | |
314 | croak "Template::Simple $@" if $@ ; |
315 | |
316 | return $rendered ; |
317 | } |
318 | |
319 | sub _render_includes { |
320 | |
321 | my( $self, $tmpl_ref ) = @_ ; |
322 | |
323 | # make a copy of the initial template so we can render it. |
324 | |
325 | my $rendered = ${$tmpl_ref} ; |
326 | |
327 | # loop until we can render no more include markups |
328 | |
329 | 1 while $rendered =~ |
f12977de |
330 | s{$self->{include_re}}{ ${ $self->_get_template($1) }}e ; |
e374d8da |
331 | |
332 | return \$rendered ; |
333 | } |
334 | |
335 | my %renderers = ( |
336 | |
f12977de |
337 | SCALAR => sub { return $_[2] }, |
338 | '' => sub { return \$_[2] }, |
e374d8da |
339 | HASH => \&_render_hash, |
340 | ARRAY => \&_render_array, |
341 | CODE => \&_render_code, |
342 | # if no ref then data is a scalar so replace the template with just the data |
e374d8da |
343 | ) ; |
344 | |
345 | |
346 | sub _render_chunk { |
347 | |
348 | my( $self, $tmpl_ref, $data ) = @_ ; |
349 | |
350 | #print "T ref [$tmpl_ref] [$$tmpl_ref]\n" ; |
351 | #print "CHUNK ref [$tmpl_ref] TMPL\n<$$tmpl_ref>\n" ; |
352 | |
353 | #print Dumper $data ; |
354 | |
355 | return \'' unless defined $data ; |
356 | |
f12977de |
357 | # get the type of this data. handle blessed types |
358 | |
359 | my $reftype = blessed( $data ) ; |
360 | |
361 | #print "REF $reftype\n" ; |
362 | |
363 | # handle the case of a qr// which blessed returns as Regexp |
364 | |
365 | if ( $reftype ) { |
366 | |
367 | $reftype = reftype $data unless $reftype eq 'Regexp' ; |
368 | } |
369 | else { |
370 | $reftype = ref $data ; |
371 | } |
372 | |
373 | #print "REF2 $reftype\n" ; |
374 | |
e374d8da |
375 | # now render this chunk based on the type of data |
376 | |
f12977de |
377 | my $renderer = $renderers{ $reftype || ''} ; |
e374d8da |
378 | |
f12977de |
379 | #print "EXP $renderer\nREF $reftype\n" ; |
e374d8da |
380 | |
f12977de |
381 | croak "unknown template data type '$data'\n" unless defined $renderer ; |
e374d8da |
382 | |
383 | return $self->$renderer( $tmpl_ref, $data ) ; |
384 | } |
385 | |
386 | sub _render_hash { |
387 | |
388 | my( $self, $tmpl_ref, $href ) = @_ ; |
389 | |
390 | return $tmpl_ref unless keys %{$href} ; |
391 | |
392 | # we need a local copy of the template to render |
393 | |
394 | my $rendered = ${$tmpl_ref} ; |
395 | |
e374d8da |
396 | # recursively render all top level chunks in this chunk |
397 | |
398 | $rendered =~ s{$self->{chunk_re}} |
399 | { |
400 | # print "CHUNK $1\nBODY\n----\n<$2>\n\n------\n" ; |
ca30cbfe |
401 | # print "CHUNK $1\nBODY\n----\n<$2>\n\n------\n" ; |
402 | # print "pre CHUNK [$`]\n" ; |
e374d8da |
403 | ${ $self->_render_chunk( \"$2", $href->{$1} ) } |
404 | }gex ; |
405 | |
406 | # now render scalars |
407 | |
408 | #print "HREF: ", Dumper $href ; |
409 | |
410 | $rendered =~ s{$self->{scalar_re}} |
411 | { |
412 | # print "SCALAR $1 VAL $href->{$1}\n" ; |
413 | defined $href->{$1} ? $href->{$1} : '' |
414 | }ge ; |
415 | |
416 | #print "HASH REND3\n<$rendered>\n" ; |
417 | |
418 | return \$rendered ; |
419 | } |
420 | |
421 | sub _render_array { |
422 | |
423 | my( $self, $tmpl_ref, $aref ) = @_ ; |
424 | |
425 | # render this $tmpl_ref for each element of the aref and join them |
426 | |
427 | my $rendered ; |
428 | |
429 | #print "AREF: ", Dumper $aref ; |
430 | |
431 | $rendered .= ${$self->_render_chunk( $tmpl_ref, $_ )} for @{$aref} ; |
432 | |
433 | return \$rendered ; |
434 | } |
435 | |
436 | sub _render_code { |
437 | |
438 | my( $self, $tmpl_ref, $cref ) = @_ ; |
439 | |
440 | my $rendered = $cref->( $tmpl_ref ) ; |
441 | |
f12977de |
442 | croak <<DIE if ref $rendered ne 'SCALAR' ; |
e374d8da |
443 | data callback to code didn't return a scalar or scalar reference |
444 | DIE |
445 | |
446 | return $rendered ; |
447 | } |
448 | |
449 | sub add_templates { |
450 | |
451 | my( $self, $tmpls ) = @_ ; |
452 | |
453 | #print Dumper $tmpls ; |
454 | return unless defined $tmpls ; |
455 | |
456 | ref $tmpls eq 'HASH' or croak "templates argument is not a hash ref" ; |
59d7205c |
457 | |
458 | # copy all the templates from the arg hash and force the values to be |
459 | # scalar refs |
f12977de |
460 | |
461 | while( my( $name, $tmpl ) = each %{$tmpls} ) { |
462 | |
463 | defined $tmpl or croak "undefined template value for '$name'" ; |
464 | |
465 | # cache the a scalar ref of the template |
466 | |
467 | $self->{tmpl_cache}{$name} = ref $tmpl eq 'SCALAR' ? |
468 | \"${$tmpl}" : \"$tmpl" |
469 | } |
e374d8da |
470 | |
59d7205c |
471 | #print Dumper $self->{tmpl_cache} ; |
e374d8da |
472 | |
473 | return ; |
474 | } |
475 | |
476 | sub delete_templates { |
477 | |
478 | my( $self, @names ) = @_ ; |
479 | |
060b866c |
480 | # delete all the cached stuff or just the names passed in |
481 | |
59d7205c |
482 | @names = keys %{$self->{tmpl_cache}} unless @names ; |
e374d8da |
483 | |
f12977de |
484 | #print "NAMES @names\n" ; |
060b866c |
485 | # clear out all the caches |
486 | # TODO: reorg these into a hash per name |
487 | |
59d7205c |
488 | delete @{$self->{tmpl_cache}}{ @names } ; |
060b866c |
489 | delete @{$self->{compiled_cache}}{ @names } ; |
490 | delete @{$self->{source_cache}}{ @names } ; |
491 | |
492 | # also remove where we found it to force a fresh search |
e374d8da |
493 | |
494 | delete @{$self->{template_paths}}{ @names } ; |
495 | |
496 | return ; |
497 | } |
498 | |
499 | sub _get_template { |
500 | |
501 | my( $self, $tmpl_name ) = @_ ; |
502 | |
503 | #print "INC $tmpl_name\n" ; |
504 | |
59d7205c |
505 | my $tmpls = $self->{tmpl_cache} ; |
e374d8da |
506 | |
507 | # get the template from the cache and send it back if it was found there |
508 | |
509 | my $template = $tmpls->{ $tmpl_name } ; |
510 | return $template if $template ; |
511 | |
512 | # not found, so find, slurp in and cache the template |
513 | |
514 | $template = $self->_find_template( $tmpl_name ) ; |
515 | $tmpls->{ $tmpl_name } = $template ; |
516 | |
517 | return $template ; |
518 | } |
519 | |
520 | sub _find_template { |
521 | |
522 | my( $self, $tmpl_name ) = @_ ; |
523 | |
f12977de |
524 | #print "FIND $tmpl_name\n" ; |
525 | foreach my $dir ( @{$self->{search_dirs}} ) { |
e374d8da |
526 | |
527 | my $tmpl_path = "$dir/$tmpl_name.tmpl" ; |
528 | |
529 | #print "PATH: $tmpl_path\n" ; |
f12977de |
530 | |
531 | next if $tmpl_path =~ /\n/ ; |
e374d8da |
532 | next unless -r $tmpl_path ; |
533 | |
534 | # cache the path to this template |
535 | |
536 | $self->{template_paths}{$tmpl_name} = $tmpl_path ; |
537 | |
538 | # slurp in the template file and return it as a scalar ref |
539 | |
f12977de |
540 | #print "FOUND $tmpl_name\n" ; |
541 | |
542 | return read_file( $tmpl_path, scalar_ref => 1 ) ; |
e374d8da |
543 | } |
544 | |
f12977de |
545 | #print "CAN'T FIND $tmpl_name\n" ; |
546 | |
547 | croak <<DIE ; |
548 | can't find template '$tmpl_name' in '@{$self->{search_dirs}}' |
e374d8da |
549 | DIE |
550 | |
551 | } |
552 | |
553 | 1; # End of Template::Simple |
554 | |
555 | __END__ |
556 | |
557 | =head1 NAME |
558 | |
f12977de |
559 | Template::Simple - A simple and very fast template module |
e374d8da |
560 | |
561 | =head1 VERSION |
562 | |
563 | Version 0.03 |
564 | |
565 | =head1 SYNOPSIS |
566 | |
567 | use Template::Simple; |
568 | |
569 | my $tmpl = Template::Simple->new(); |
570 | |
f12977de |
571 | # here is a simple template store in a scalar |
572 | # the header and footer templates will be included from the cache or files. |
573 | |
574 | my $template_text = <<TMPL ; |
e374d8da |
575 | [%INCLUDE header%] |
576 | [%START row%] |
577 | [%first%] - [%second%] |
578 | [%END row%] |
579 | [%INCLUDE footer%] |
580 | TMPL |
581 | |
f12977de |
582 | # this is data that will be used to render that template the keys |
583 | # are mapped to the chunk names (START & END markups) in the |
584 | # template the row is an array reference so multiple rows will be |
585 | # rendered usually the data tree is generated by code instead of |
586 | # being pure data. |
587 | |
e374d8da |
588 | my $data = { |
589 | header => { |
590 | date => 'Jan 1, 2008', |
591 | author => 'Me, myself and I', |
592 | }, |
593 | row => [ |
594 | { |
595 | first => 'row 1 value 1', |
596 | second => 'row 1 value 2', |
597 | }, |
598 | { |
599 | first => 'row 2 value 1', |
600 | second => 'row 2 value 2', |
601 | }, |
602 | ], |
603 | footer => { |
604 | modified => 'Aug 31, 2006', |
605 | }, |
606 | } ; |
607 | |
f12977de |
608 | # this call renders the template with the data tree |
e374d8da |
609 | |
f12977de |
610 | my $rendered = $tmpl->render( \$template_text, $data ) ; |
e374d8da |
611 | |
f12977de |
612 | # here we add the template to the cache and give it a name |
e374d8da |
613 | |
f12977de |
614 | $tmpl->add_templates( { demo => $template_text } ) ; |
e374d8da |
615 | |
f12977de |
616 | # this compiles and then renders that template with the same data |
617 | # but is much faster |
e374d8da |
618 | |
f12977de |
619 | $tmpl->compile( 'demo' ) ; |
620 | my $rendered = $tmpl->render( 'demo', $data ) ; |
e374d8da |
621 | |
e374d8da |
622 | |
f12977de |
623 | =head1 DESCRIPTION |
e374d8da |
624 | |
f12977de |
625 | Template::Simple is a very fast template rendering module with a |
626 | simple markup. It can do almost any templating task and is extendable |
627 | with user callbacks. It can render templates directly or compile them |
628 | for more speed. |
e374d8da |
629 | |
f12977de |
630 | =head1 CONSTRUCTOR |
e374d8da |
631 | |
f12977de |
632 | =head2 new |
633 | |
e374d8da |
634 | You create a Template::Simple by calling the class method new: |
635 | |
636 | my $tmpl = Template::Simple->new() ; |
637 | |
638 | All the arguments to C<new()> are key/value options that change how |
f12977de |
639 | the object will render templates. |
e374d8da |
640 | |
f12977de |
641 | =head2 pre_delim |
e374d8da |
642 | |
643 | This option sets the string or regex that is the starting delimiter |
644 | for all markups. You can use a plain string or a qr// but you need to |
645 | escape (with \Q or \) any regex metachars if you want them to be plain |
646 | chars. The default is qr/\[%/. |
647 | |
648 | my $tmpl = Template::Simple->new( |
649 | pre_delim => '<%', |
650 | ); |
651 | |
652 | my $rendered = $tmpl->render( '<%FOO%]', 'bar' ) ; |
653 | |
f12977de |
654 | =head2 post_delim |
e374d8da |
655 | |
656 | This option sets the string or regex that is the ending delimiter |
657 | for all markups. You can use a plain string or a qr// but you need to |
658 | escape (with \Q or \) any regex metachars if you want them to be plain |
659 | chars. The default is qr/%]/. |
660 | |
661 | my $tmpl = Template::Simple->new( |
662 | post_delim => '%>', |
663 | ); |
664 | |
665 | my $rendered = $tmpl->render( '[%FOO%>', 'bar' ) ; |
666 | |
f12977de |
667 | =head2 token_re |
668 | |
669 | This option overrides the regular expression that is used match a |
670 | token or name in the markup. It should be a qr// and you may need to |
671 | escape (with \Q or \) any regex metachars if you want them to be plain |
672 | chars. The default is qr/\w+?/. |
673 | |
674 | my $tmpl = Template::Simple->new( |
675 | token_re => qr/[\w-]+?/, |
676 | ); |
677 | |
678 | my $rendered = $tmpl->render( |
679 | '[% id-with-hyphens %]', |
680 | { 'id-with-hyphens' => 'bar' } |
681 | ) ; |
682 | |
683 | =head2 greedy_chunk |
e374d8da |
684 | |
685 | This boolean option will cause the regex that grabs a chunk of text |
686 | between the C<START/END> markups to become greedy (.+). The default is |
687 | a not-greedy grab of the chunk text. (UNTESTED) |
688 | |
f12977de |
689 | =head2 templates |
e374d8da |
690 | |
691 | This option lets you load templates directly into the cache of the |
f12977de |
692 | Template::Simple object. See <TEMPLATE CACHE> for more on this. |
e374d8da |
693 | |
694 | my $tmpl = Template::Simple->new( |
695 | templates => { |
e374d8da |
696 | foo => <<FOO, |
697 | [%baz%] is a [%quux%] |
698 | FOO |
699 | bar => <<BAR, |
700 | [%user%] is not a [%fool%] |
701 | BAR |
702 | }, |
703 | ); |
704 | |
f12977de |
705 | =head2 search_dirs, include_paths |
e374d8da |
706 | |
f12977de |
707 | This option lets you set the directory paths to search for template |
708 | files. Its value is an array reference with the paths. Its default is |
709 | 'templates'. |
e374d8da |
710 | |
f12977de |
711 | my $tmpl = Template::Simple->new( |
712 | search_dirs => [ qw( |
713 | templates |
714 | templates/deeper |
715 | ) ], |
716 | ) ; |
e374d8da |
717 | |
f12977de |
718 | NOTE: This option was called C<include_paths> but since it is used to |
719 | locate named templates as well as included ones, it was changed to |
720 | C<search_dirs>. The older name C<include_paths> is still supported |
721 | but new code should use C<search_dirs>. |
e374d8da |
722 | |
723 | =head1 METHODS |
724 | |
725 | =head2 render |
726 | |
727 | This method is passed a template and a data tree and it renders it and |
f12977de |
728 | returns a reference to the resulting string. |
729 | |
730 | If the template argument is a scalar reference, then it is the |
731 | template text to be rendered. A scalar template argument is first |
732 | assumed to be a template name which is searched for in the template |
733 | cache and the compiled template caches. If found in there it is used |
734 | as the template. If not found there, it is searched for in the |
735 | directories of the C<search_dirs>. Finally if not found, it will be |
736 | used as the template text. |
737 | |
738 | The data tree argument can be any value allowed by Template::Simple |
739 | when rendering a template. It can also be a blessed reference (Perl |
740 | object) since C<Scalar::Util::reftype> is used instead of C<ref> to |
741 | determine the data type. |
e374d8da |
742 | |
743 | Note that the author recommends against passing in an object as this |
744 | breaks encapsulation and forces your object to be (most likely) a |
745 | hash. It would be better to create a simple method that copies the |
f12977de |
746 | object contents to a hash reference and pass that. But other current |
e374d8da |
747 | templaters allow passing in objects so that is supported here as well. |
748 | |
749 | my $rendered = $tmpl->render( $template, $data ) ; |
750 | |
f12977de |
751 | =head2 compile |
752 | |
753 | This method takes a template and compiles it to make it run much |
754 | faster. Its only argument is a template name and that is used to |
755 | locate the template in the object cache or it is loaded from a file |
756 | (with the same search technique as regular rendering). The compiled |
757 | template is stored in its own cache and can be rendered by a call to |
758 | the render method and passing the name and the data tree. |
759 | |
760 | $tmpl->compile( 'foo' ) ; |
761 | my $rendered = $tmpl->render( 'foo', $data ) ; |
762 | |
763 | There are a couple of restrictions to compiled templates. They don't |
764 | support code references in the data tree (that may get supported in |
765 | the future). Also since the include expansion happens one time during |
766 | the compiling, any changes to the template or its includes will not be |
767 | detected when rendering a compiled template. You need to re-compile a |
768 | template to force it to use changed templates. Note that you may need |
769 | to delete templates from the object cache (with the delete_templates |
770 | method) to force them to be reloaded from files. |
771 | |
e374d8da |
772 | =head2 add_templates |
773 | |
f12977de |
774 | This method adds templates to the object cache. It takes a list of |
775 | template names and texts just like the C<templates> constructor |
776 | option. These templates are located by name when compiling or |
777 | rendering. |
e374d8da |
778 | |
779 | $tmpl->add_templates( |
780 | { |
781 | foo => \$foo_template, |
782 | bar => '[%include bar%]', |
783 | } |
784 | ) ; |
785 | |
786 | =head2 delete_templates |
787 | |
788 | This method takes a list of template names and will delete them from |
f12977de |
789 | the template cache in the object. If you pass no arguments then all |
790 | the cached templates will be deleted. This can be used when you know |
791 | a template file has been updated and you want to get it loaded back |
792 | into the cache. |
e374d8da |
793 | |
794 | # this deletes only the foo and bar templates from the object cache |
795 | |
796 | $tmpl->delete_templates( qw( foo bar ) ; |
797 | |
798 | # this deletes all of templates from the object cache |
799 | |
800 | $tmpl->delete_templates() ; |
801 | |
f12977de |
802 | =head2 get_source |
803 | |
804 | $tmpl->get_source( 'bar' ) ; |
805 | |
806 | This method is passed a compiled template name and returns the |
807 | generated Perl source for a compiled template. You can compile a |
808 | template and paste the generated source (a single sub per template) |
809 | into another program. The sub can be called and passed a data tree and |
810 | return a rendered template. It saves the compile time for that |
811 | template but it still needs to be compiled by Perl. This method is |
812 | also useful for debugging the template compiler. |
813 | |
814 | =head1 TEMPLATE CACHE |
815 | |
816 | This cache is stored in the object and will be searched to find any |
817 | template by name. It is initially loaded via the C<templates> option |
818 | to new and more can be added with the C<add_templates> method. You can |
819 | delete templates from the cache with the C<delete_templates> |
820 | method. Compiled templates have their own cache in the |
821 | module. Deleting a template also deletes it from the compiled cache. |
822 | |
823 | =head1 INCLUDE EXPANSION |
e374d8da |
824 | |
f12977de |
825 | Before a template is either rendered or compiled it undergoes include |
826 | expansion. All include markups are replaced by a templated located in |
827 | the cache or from a file. Included templates can include other |
828 | templates. This expansion keeps going until no more includes are |
829 | found. |
e374d8da |
830 | |
f12977de |
831 | =head1 LOCATING TEMPLATES |
e374d8da |
832 | |
f12977de |
833 | When a template needs to be loaded by name (when rendering, compiling |
834 | or expanding includes) it is first searched for in the object cache |
835 | (and the compiled cache for compiled templates). If not found there, |
836 | the C<templates_paths> are searched for files with that name and a |
837 | suffix of .tmpl. If a file is found, it used and also loaded into the |
838 | template cache in the object with the searched for name as its key. |
e374d8da |
839 | |
840 | =head1 MARKUP |
841 | |
842 | All the markups in Template::Simple use the same delimiters which are |
843 | C<[%> and C<%]>. You can change the delimiters with the C<pre_delim> |
844 | and C<post_delim> options in the C<new()> constructor. |
845 | |
846 | =head2 Tokens |
847 | |
848 | A token is a single markup with a C<\w+> Perl word inside. The token |
849 | can have optional whitespace before and after it. A token is replaced |
850 | by a value looked up in a hash with the token as the key. The hash |
f12977de |
851 | lookup keeps the same case as parsed from the token markup. You can |
852 | override the regular expression used to match a token with the |
a5b978a4 |
853 | C<token_re> option. |
e374d8da |
854 | |
855 | [% foo %] [%BAR%] |
856 | |
857 | Those will be replaced by C<$href->{foo}> and C<$href->{BAR}> assuming |
858 | C<$href> is the current data for this rendering. Tokens are only |
859 | parsed out during hash data rendering so see Hash Data for more. |
860 | |
861 | =head2 Chunks |
862 | |
863 | Chunks are regions of text in a template that are marked off with a |
864 | start and end markers with the same name. A chunk start marker is |
865 | C<[%START name%]> and the end marker for that chunk is C<[%END |
f12977de |
866 | name%]>. C<name> is matched with C<\w+?> and that is the name of this |
e374d8da |
867 | chunk. The whitespace between C<START/END> and C<name> is required and |
868 | there is optional whitespace before C<START/END> and after the |
869 | C<name>. C<START/END> are case insensitive but the C<name>'s case is |
f12977de |
870 | kept. Chunks are the primary way to markup templates for structures |
871 | (sets of tokens), nesting (hashes of hashes), repeats (array |
872 | references) and callbacks to user code. By default a chunk will be a |
873 | non-greedy grab but you can change that in the constructor by enabling |
874 | the C<greedy_chunk> option. You can override the regular expression |
a5b978a4 |
875 | used to match the chunk name with the C<token_re> option. |
e374d8da |
876 | |
877 | [%Start FOO%] |
878 | [% START bar %] |
879 | [% field %] |
880 | [% end bar %] |
881 | [%End FOO%] |
882 | |
883 | =head2 Includes |
884 | |
f12977de |
885 | When a markup C<[%include name%]> is seen, that text is replaced by |
886 | the template of that name. C<name> is matched with C<\w+?> which is |
887 | the name of the template. You can override the regular expression used |
a5b978a4 |
888 | to match the include C<name> with the C<token_re> option. |
f12977de |
889 | |
890 | See C<INCLUDE EXPANSION> for more on this. |
891 | |
e374d8da |
892 | =head1 RENDERING RULES |
893 | |
894 | Template::Simple has a short list of rendering rules and they are easy |
895 | to understand. There are two types of renderings, include rendering |
896 | and chunk rendering. In the C<render> method, the template is an |
897 | unnamed top level chunk of text and it first gets its C<INCLUDE> |
898 | markups rendered. The text then undergoes a chunk rendering and a |
899 | scalar reference to that rendered template is returned to the caller. |
900 | |
901 | =head2 Include Rendering |
902 | |
f12977de |
903 | All include file rendering happens before any other rendering is |
904 | done. After this phase, the rendered template will not have |
905 | C<[%include name%]> markups in it. |
e374d8da |
906 | |
907 | =head2 Chunk Rendering |
908 | |
f12977de |
909 | A chunk is the text found between matching C<START> and C<END> markups |
910 | and it gets its name from the C<START> markup. The top level template |
911 | is considered an unamed chunk and also gets chunk rendered. |
e374d8da |
912 | |
913 | The data for a chunk determines how it will be rendered. The data can |
914 | be a scalar or scalar reference or an array, hash or code |
915 | reference. Since chunks can contain nested chunks, rendering will |
916 | recurse down the data tree as it renders the chunks. Each of these |
917 | renderings are explained below. Also see the IDIOMS and BEST PRACTICES |
918 | section for examples and used of these renderings. |
919 | |
f12977de |
920 | =over 4 |
e374d8da |
921 | |
f12977de |
922 | =item Hash Data Rendering |
e374d8da |
923 | |
924 | If the current data for a chunk is a hash reference then two phases of |
925 | rendering happen, nested chunk rendering and token rendering. First |
926 | nested chunks are parsed of of this chunk along with their names. Each |
927 | parsed out chunk is rendered based on the value in the current hash |
928 | with the nested chunk's name as the key. |
929 | |
930 | If a value is not found (undefined), then the nested chunk is replaced |
931 | by the empty string. Otherwise the nested chunk is rendered according |
932 | to the type of its data (see chunk rendering) and it is replaced by |
933 | the rendered text. |
934 | |
f12977de |
935 | Chunk name and token lookup in the hash data is case sensitive. |
e374d8da |
936 | |
937 | Note that to keep a plain text chunk or to just have the all of its |
938 | markups (chunks and tokens) be deleted just pass in an empty hash |
939 | reference C<{}> as the data for the chunk. It will be rendered but all |
940 | markups will be replaced by the empty string. |
941 | |
e374d8da |
942 | The second phase is token rendering. Markups of the form [%token%] are |
943 | replaced by the value of the hash element with the token as the |
944 | key. If a token's value is not defined it is replaced by the empty |
945 | string. This means if a token key is missing in the hash or its value |
946 | is undefined or its value is the empty string, the [%token%] markup |
947 | will be deleted in the rendering. |
948 | |
f12977de |
949 | =item Array Data Rendering |
e374d8da |
950 | |
f12977de |
951 | If the current data for a chunk is an array reference it will do a |
952 | full chunk rendering for each value in the array. It will replace the |
953 | original chunk text with the concatenated list of rendered |
954 | chunks. This is how you do repeated sections in Template::Simple and |
955 | why there is no need for any loop markups. Note that this means that |
956 | rendering a chunk with $data and [ $data ] will do the exact same |
957 | thing. A value of an empty array C<[]> will cause the chunk to be |
958 | replaced by the empty string. |
e374d8da |
959 | |
f12977de |
960 | =item Scalar Data Rendering |
e374d8da |
961 | |
f12977de |
962 | If the current data for a chunk is a scalar or scalar reference, the |
963 | entire chunk is replaced by the scalar's value. This can be used to |
964 | overwrite one default section of text with from the data tree. |
e374d8da |
965 | |
f12977de |
966 | =item Code Data Rendering |
e374d8da |
967 | |
f12977de |
968 | If the current data for a chunk is a code reference (also called |
969 | anonymous sub) then the code reference is called and it is passed a |
970 | scalar reference to the that chunk's text. The code must return a |
971 | scalar or a scalar reference and its value replaces the chunk's text |
972 | in the template. If the code returns any other type of data it is a |
973 | fatal error. Code rendering is how you can do custom renderings and |
974 | plugins. A key idiom is to use closures as the data in code renderings |
975 | and keep the required outside data in the closure. |
e374d8da |
976 | |
f12977de |
977 | =back |
e374d8da |
978 | |
f12977de |
979 | =head1 DESIGN GOALS |
e374d8da |
980 | |
981 | =over 4 |
982 | |
f12977de |
983 | =item * High speed |
e374d8da |
984 | |
f12977de |
985 | When using compiled templates T::S is one of the fastest template |
986 | tools around. There is a benchmark script in the extras/ directory |
987 | comparing it to Template `Toolkit and Template::Teeny |
e374d8da |
988 | |
f12977de |
989 | =item * Support most common template operations |
e374d8da |
990 | |
f12977de |
991 | It can recursively include other templates, replace tokens (scalars), |
992 | recursively render nested chunks of text and render lists. By using |
993 | simple idioms you can get conditional renderings. |
e374d8da |
994 | |
f12977de |
995 | =item * Complete isolation of template from program code |
e374d8da |
996 | |
f12977de |
997 | Template design and programming the data logic can be done by |
998 | different people. Templates and data logic can be mixed and matched |
999 | which improves reuse and flexibility. |
e374d8da |
1000 | |
f12977de |
1001 | =item * Very simple template markup (only 4 markups) |
e374d8da |
1002 | |
f12977de |
1003 | The only markups are C<INCLUDE>, C<START>, C<END> and C<token>. See |
1004 | MARKUP for more. |
e374d8da |
1005 | |
f12977de |
1006 | =item * Easy to follow rendering rules |
e374d8da |
1007 | |
f12977de |
1008 | Rendering of templates and chunks is driven from a data tree. The type |
1009 | of the data element used in an rendering controls how the rendering |
1010 | happens. The data element can be a scalar, scalar reference, or an |
1011 | array, hash or code reference. |
e374d8da |
1012 | |
f12977de |
1013 | =item * Efficient template rendering |
e374d8da |
1014 | |
f12977de |
1015 | Rendering is very simple and uses Perl's regular expressions |
1016 | efficiently. Because the markup is so simple less processing is needed |
1017 | than many other templaters. You can precompile templates for even |
1018 | faster rendering but with some minor restrictions in flexibility |
e374d8da |
1019 | |
f12977de |
1020 | =item * Easy user extensions |
e374d8da |
1021 | |
f12977de |
1022 | User code can be called during an rendering so you can do custom |
1023 | renderings and plugins. Closures can be used so the code can have its |
1024 | own private data for use in rendering its template chunk. |
e374d8da |
1025 | |
1026 | =back |
1027 | |
e374d8da |
1028 | =head1 BUGS |
1029 | |
1030 | Please report any bugs or feature requests to |
1031 | C<bug-template-simple at rt.cpan.org>, or through the web interface at |
1032 | L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Template-Simple>. |
1033 | I will be notified, and then you'll automatically be notified of progress on |
1034 | your bug as I make changes. |
1035 | |
e374d8da |
1036 | =over 4 |
1037 | |
1038 | =item * RT: CPAN's request tracker |
1039 | |
1040 | L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Template-Simple> |
1041 | |
1042 | =item * Search CPAN |
1043 | |
1044 | L<http://search.cpan.org/dist/Template-Simple> |
1045 | |
1046 | =back |
1047 | |
1048 | =head1 ACKNOWLEDGEMENTS |
1049 | |
1050 | I wish to thank Turbo10 for their support in developing this module. |
1051 | |
f12977de |
1052 | =head2 LICENSE |
e374d8da |
1053 | |
f12977de |
1054 | Same as Perl. |
e374d8da |
1055 | |
f12977de |
1056 | =head1 COPYRIGHT |
e374d8da |
1057 | |
f12977de |
1058 | Copyright 2011 Uri Guttman, all rights reserved. |
e374d8da |
1059 | |
f12977de |
1060 | =head2 SEE ALSO |
e374d8da |
1061 | |
f12977de |
1062 | An article on file slurping in extras/slurp_article.pod. There is |
1063 | also a benchmarking script in extras/slurp_bench.pl. |
e374d8da |
1064 | |
f12977de |
1065 | =head1 AUTHOR |
e374d8da |
1066 | |
f12977de |
1067 | Uri Guttman, E<lt>uri@stemsystems.comE<gt> |
e374d8da |
1068 | |
f12977de |
1069 | =cut |