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