9 =head1 Template::Simple Cookbook
11 This cookbook contains examples of idioms and best practices when
12 using the Template::Simple module. It will illustrate all the the
13 features of this module and show various combinations of code to get
14 the job done. Send any requests for more examples to
15 E<lt>template@stemsystems.comE<gt>. Read the source code to see the
16 working examples or you can run this script to see all the
17 output. Each example has its title printed and rendered templates are
18 printed with a KEY: prefix and delimited with [].
20 By combining these techniques you can create and built complex
21 template applications that can do almost any task other templaters can
22 do. You will be able to share more code logic and templates as they
23 are totally isolated and independent from each other.
25 =head2 Use Scalar References
27 When passing text either as templates or in data tree elements, it is
28 generally faster to use scalar references than plain scalars. T::S can
29 accept text either way so you choose the style you like best. Most of
30 the examples here will use scalar references. Note that passing a
31 scalar reference to the new() constructor as the template will force
32 that to be a template and not a template name so no lookup will
33 occur. T::S always treats all text values as read only and never
34 modifies incoming data.
38 use Template::Simple ;
39 my $ts = Template::Simple->new() ;
43 =head1 Token Expansion
45 The simplest use of templates is replacing single tokens with
46 values. This is vry similar to interpolation of scalar variables in a
47 double quoted string. The difference is that the template text can
48 come from outside the program whereas double quoted strings must be in
49 the code (eval STRING doesn't count).
51 To replace tokens all you need is a template with token markups
52 (e.g. C<[% foo %]>) and a hash with those tokens as keys and the
53 values with which to replace them. Remember the top level template is
54 treated as an unnamed chunk so you can pass a hash reference to
59 print "\n******************\nToken Expansion\n******************\n\n" ;
62 This [% token %] will be replaced as will [%foo%] and [% bar %]
65 my $token_expansion = $ts->render( $template,
69 bar => 'so will this',
73 print "TOKEN EXPANSION: [${$token_expansion}]\n" ;
77 Sometimes you want to delete a token and not replace it with text. All
78 you need to do is use the null string for its data. Altenatively if
79 you are rendering a chunk with a hash (see below for more examples)
80 you can just not have any data for the token and it will also be
81 deleted. Both styles are shown in this example.
85 print "\n******************\nToken Deletion\n******************\n\n" ;
88 This [% token %]will be deleted as will [%foo%]
91 my $token_deletion = $ts->render( $template,
97 print "TOKEN DELETION: [${$token_deletion}]\n" ;
100 =head1 Named Templates
102 You can pass a template directly to the C<render> method or pass in
103 its name. A named template will be searched for in the object cache
104 and then in the C<template_paths> directories. Templates can be loaded
105 into the cache with in the new() call or added later with the
106 C<add_templates> method.
110 print "\n******************\nNamed Templates\n******************\n\n" ;
112 $ts = Template::Simple->new(
115 We have some foo text here with [% data %]
120 my $foo_template = $ts->render( 'foo', { data => 'lots of foo' } ) ;
122 $ts->add_templates( { bar => <<BAR } ) ;
123 We have some bar text here with [% data %]
126 my $bar_template = $ts->render( 'bar', { data => 'some bar' } ) ;
128 print "FOO TEMPLATE: [${$foo_template}]\n" ;
129 print "BAR TEMPLATE: [${$bar_template}]\n" ;
131 =head1 Include Expansion
133 You can build up templates by including other templates. This allows a
134 template to be reused and shared by other templates. What makes this
135 even better, is that by passing different data to the included
136 templates in different renderings, you can get different results. If
137 the logic was embedded in the template you can't change the rendering
138 as easily. You include a template by using the C<[%include name%]>
139 markup. The name is used to locate a template by name and its text
140 replaces the markup. This example shows a single include in the top
145 print "\n******************\nInclude Expansion\n******************\n\n" ;
147 $ts = Template::Simple->new(
150 This top level template includes this <<[% include other %]>>text
153 This is the included text
157 my $include_template = $ts->render( 'top', {} ) ;
159 print "INCLUDE TEMPLATE: [${$include_template}]\n" ;
161 =head1 Template Paths
163 You can search for templates in files with the C<search_dirs> option
164 to the constructor. If a named template is not found in the object
165 cache it will be searched for in the directories listed in the
166 C<search_dirs> option. If it is found there, it will be loaded into
167 the object cache so future uses of it by name will be faster. The
168 default value of C<search_dirs> option is C<templates>. Templates must
169 have a suffix of C<.tmpl>. This example makes a directory called
170 'templates' and a template file named C<foo.tmpl>. The second example
171 makes a directory called C<cookbook> and puts a template in there and
172 sets. Note that the option value must be an array reference.
176 print "\n******************\nSearch Dirs\n******************\n\n" ;
178 my $tmpl_dir = 'templates' ;
180 write_file( "$tmpl_dir/foo.tmpl", <<FOO ) ;
181 This template was loaded from the dir [%dir%]
184 $ts = Template::Simple->new() ;
185 my $foo_file_template = $ts->render( 'foo', { dir => 'templates' } ) ;
187 print "FOO FILE TEMPLATE: [${$foo_file_template}]\n" ;
189 unlink "$tmpl_dir/foo.tmpl" ;
194 my $cook_dir = 'cookbook' ;
196 write_file( "$cook_dir/bar.tmpl", <<BAR ) ;
197 This template was loaded from the $cook_dir [%dir%]
200 $ts = Template::Simple->new( search_dirs => [$cook_dir] ) ;
201 my $bar_file_template = $ts->render( 'bar', { dir => 'directory' } ) ;
203 print "BAR FILE TEMPLATE: [${$bar_file_template}]\n" ;
205 unlink "$cook_dir/bar.tmpl" ;
208 =head1 Named Chunk Expansion
210 The core markup in T::S is called a chunk. It is delimited by paired
211 C<start> and C<end> markups and the text in between them is the
212 chunk. Any chunk can have multiple chunks inside it and they are named
213 for the name in the C<start> and C<end> markups. That name is used to
214 match the chunk with the data passed to render. This example uses the
215 top level template (which is always an unnamed chunk) which contains a
216 nested chunk which has a name. The data passed in is a hash reference
217 which has a key with the chunk name and its value is another hash
218 reference. So the nested chunk match up to the nested hashes.
222 print "\n******************\nNested Chunk Expansion\n******************\n\n" ;
224 $ts = Template::Simple->new(
227 This top level template includes this <<[% include nested %]>> chunk
230 [%START nested %]This included template just has a [% token %] and another [% one %][%END nested %]
235 my $nested_template = $ts->render( 'top',
238 token => 'nested value',
239 one => 'value from the data',
243 print "NESTED TEMPLATE: [${$nested_template}]\n" ;
247 The simplest template decision is when you want to show some text or
248 nothing. This is done with an empty hash reference or a null string
249 value in the data tree. The empty hash reference will cause the text
250 to be kept as is with all markups removed (replaced by the null
251 string). A null string (or a reference to one) will cause the text
256 print "\n******************\nBoolean Text\n******************\n\n" ;
258 $template = \<<TMPL ;
259 [% START boolean %]This is text to be left or deleted[% END boolean %]
262 my $boolean_kept = $ts->render( $template, { boolean => {} } ) ;
263 my $deleted = $ts->render( $template, { default => \'' } ) ;
265 print "KEPT: [${$boolean_kept}]\n" ;
266 print "DELETED: [${$deleted}]\n" ;
268 =head2 Default vs. Overwrite Text
270 The next step up from boolean text is overwriting a default text with
271 another when rendering. This is done with an empty hash reference or a
272 scalar value for the chunk in the data tree. The empty hash reference
273 will cause the default text to be kept as is with all markups removed
274 (replaced by the null string). A scalar value (or a scalar reference)
275 will cause the complete text chunk to be replaced by that value.
279 print "\n******************\nDefault vs. Overwrite Text\n******************\n\n" ;
281 $template = \<<TMPL ;
282 [% START default %]This is text to be left or replaced[% END default %]
285 my $default_kept = $ts->render( $template, { default => {} } ) ;
286 my $overwrite = $ts->render( $template, { default => \<<OVER } ) ;
287 This text will overwrite the default text
290 print "DEFAULT: [${$default_kept}]\n" ;
291 print "OVERWRITE: [${$overwrite}]\n" ;
293 =head2 Conditional Text
295 Instead of having the overwrite text in the data tree, it is useful to
296 have it in the template itself. This is a conditional where one text
297 or the other is rendered. This is done by wrapping each text in its
298 own chunk with unique names. The data tree can show either one by
299 passing an empty hash reference for that data and a null string for
300 the other one. Also you can just not have a value for the text not to
301 be rendered and that will also delete it. Both styles are shown here.
305 print "\n******************\nConditional Text\n******************\n\n" ;
307 $template = \<<TMPL ;
308 [% START yes_text %]This text shown when yes[% END yes_text %]
309 [% START no_text %]This text shown when no[% END no_text %]
312 my $yes_shown = $ts->render( $template, { yes_text => {} } ) ;
313 my $no_shown = $ts->render( $template, {
318 print "YES: [${$yes_shown}]\n" ;
319 print "NO: [${$no_shown}]\n" ;
321 =head1 List Chunk Expansion
323 T::S has no list markup because of the unique way it handles data
324 during rendering. When an array reference is matched to a chunk, the
325 array is iterated and the chunk is then rendered with each element of
326 the array. This list of rendered texts is concatenated and replaces
327 the original chunk in the template. The data and the logic that
328 creates the data controls when a template chunk is repeated. This
329 example shows the top level (unnamed) template being rendered with an
330 array of hashes. Each hash renders the chunk one time. Note that the
331 different results you get based on the different hashes in the array.
335 print "\n******************\nList Chunk Expansion\n******************\n\n" ;
337 $ts = Template::Simple->new(
339 top_array => <<TOP_ARRAY,
341 This is the [%count%] chunk.
342 [%start maybe%]This line may be shown[%end maybe%]
343 This is the end of the chunk line
347 my $top_array = $ts->render( 'top_array', [
361 print "TOP_ARRAY: [${$top_array}]\n" ;
364 =head1 Separated List Expansion
366 A majorly used variation of data lists are list with a separator but
367 not one after the last element. This can be done easily with T::S and
368 here are two techniques. The first one uses a token for the separator
369 in the chunk and passes in a hash with the delimiter string set in all
370 but the last element. This requires the code logic to know and set the
371 delimiter. The other solution lets the template set the delimiter by
372 enclosing it in a chunk of its own and passing an empty hash ref for
373 the places to keep it and nothing for the last element. Both examples
374 use the same sub to do this work for you and all you need to do is
375 pass it the token for the main value and the seperator key and
376 optionally its value. You can easily make a variation that puts the
377 separator before the element and delete it from the first element. If
378 your chunk has more tokens or nested chunks, this sub could be
379 generalized to modify a list of hashes instead of generating one.
383 print "\n******************\nSeparated List Expansion\n******************\n\n" ;
386 sub make_separated_data {
387 my( $token, $data, $delim_key, $delim ) = @_ ;
389 # make the delim set from the template (in a chunk) if not passed in
390 # an empty hash ref keeps the chunk text as is.
394 my @list = map +{ $token => $_, $delim_key => $delim, }, @{$data} ;
396 # remove the separator from the last element
398 delete $list[-1]{$delim_key} ;
403 my @data = qw( one two three four ) ;
405 $ts = Template::Simple->new(
407 sep_tmpl => <<SEP_TMPL,
408 Number [%count%][%sep%]
410 sep_data => <<SEP_DATA,
411 Number [%count%][%start sep%],[%end sep%]
415 my $sep_tmpl = $ts->render( 'sep_tmpl',
416 make_separated_data( 'count', \@data, 'sep', '--' ) ) ;
418 my $sep_data = $ts->render( 'sep_data',
419 make_separated_data( 'count', \@data, 'sep', {} ) ) ;
421 print "SEP_DATA: [${$sep_data}]\n" ;
422 print "SEP_DATA: [${$sep_data}]\n" ;