The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

Template::Simple Cookbook

This cookbook contains examples of idioms and best practices when using the Template::Simple module. It will illustrate all the the features of this module and show various combinations of code to get the job done. Send any requests for more examples to <template@stemsystems.com>. Read the source code to see the working examples or you can run this script to see all the output. Each example has its title printed and rendered templates are printed with a KEY: prefix and delimited with [].

By combining these techniques you can create and built complex template applications that can do almost any task other templaters can do. You will be able to share more code logic and templates as they are totally isolated and independent from each other.

Use Scalar References

When passing text either as templates or in data tree elements, it is generally faster to use scalar references than plain scalars. T::S can accept text either way so you choose the style you like best. Most of the examples here will use scalar references. Note that passing a scalar reference to the new() constructor as the template will force that to be a template and not a template name so no lookup will occur. T::S always treats all text values as read only and never modifies incoming data.

Token Expansion

The simplest use of templates is replacing single tokens with values. This is vry similar to interpolation of scalar variables in a double quoted string. The difference is that the template text can come from outside the program whereas double quoted strings must be in the code (eval STRING doesn't count).

To replace tokens all you need is a template with token markups (e.g. [% foo %]) and a hash with those tokens as keys and the values with which to replace them. Remember the top level template is treated as an unnamed chunk so you can pass a hash reference to render.

Token Deletion

Sometimes you want to delete a token and not replace it with text. All you need to do is use the null string for its data. Altenatively if you are rendering a chunk with a hash (see below for more examples) you can just not have any data for the token and it will also be deleted. Both styles are shown in this example.

Named Templates

You can pass a template directly to the render method or pass in its name. A named template will be searched for in the object cache and then in the template_paths directories. Templates can be loaded into the cache with in the new() call or added later with the add_templates method.

Include Expansion

You can build up templates by including other templates. This allows a template to be reused and shared by other templates. What makes this even better, is that by passing different data to the included templates in different renderings, you can get different results. If the logic was embedded in the template you can't change the rendering as easily. You include a template by using the [%include name%] markup. The name is used to locate a template by name and its text replaces the markup. This example shows a single include in the top level template.

Template Paths

You can search for templates in files with the search_dirs option to the constructor. If a named template is not found in the object cache it will be searched for in the directories listed in the search_dirs option. If it is found there, it will be loaded into the object cache so future uses of it by name will be faster. The default value of search_dirs option is templates. Templates must have a suffix of .tmpl. This example makes a directory called 'templates' and a template file named foo.tmpl. The second example makes a directory called cookbook and puts a template in there and sets. Note that the option value must be an array reference.

Named Chunk Expansion

The core markup in T::S is called a chunk. It is delimited by paired start and end markups and the text in between them is the chunk. Any chunk can have multiple chunks inside it and they are named for the name in the start and end markups. That name is used to match the chunk with the data passed to render. This example uses the top level template (which is always an unnamed chunk) which contains a nested chunk which has a name. The data passed in is a hash reference which has a key with the chunk name and its value is another hash reference. So the nested chunk match up to the nested hashes.

Boolean Chunk

The simplest template decision is when you want to show some text or nothing. This is done with an empty hash reference or a null string value in the data tree. The empty hash reference will cause the text to be kept as is with all markups removed (replaced by the null string). A null string (or a reference to one) will cause the text chunk to be deleted.

Default vs. Overwrite Text

The next step up from boolean text is overwriting a default text with another when rendering. This is done with an empty hash reference or a scalar value for the chunk in the data tree. The empty hash reference will cause the default text to be kept as is with all markups removed (replaced by the null string). A scalar value (or a scalar reference) will cause the complete text chunk to be replaced by that value.

Conditional Text

Instead of having the overwrite text in the data tree, it is useful to have it in the template itself. This is a conditional where one text or the other is rendered. This is done by wrapping each text in its own chunk with unique names. The data tree can show either one by passing an empty hash reference for that data and a null string for the other one. Also you can just not have a value for the text not to be rendered and that will also delete it. Both styles are shown here.

List Chunk Expansion

T::S has no list markup because of the unique way it handles data during rendering. When an array reference is matched to a chunk, the array is iterated and the chunk is then rendered with each element of the array. This list of rendered texts is concatenated and replaces the original chunk in the template. The data and the logic that creates the data controls when a template chunk is repeated. This example shows the top level (unnamed) template being rendered with an array of hashes. Each hash renders the chunk one time. Note that the different results you get based on the different hashes in the array.

Separated List Expansion

A majorly used variation of data lists are list with a separator but not one after the last element. This can be done easily with T::S and here are two techniques. The first one uses a token for the separator in the chunk and passes in a hash with the delimiter string set in all but the last element. This requires the code logic to know and set the delimiter. The other solution lets the template set the delimiter by enclosing it in a chunk of its own and passing an empty hash ref for the places to keep it and nothing for the last element. Both examples use the same sub to do this work for you and all you need to do is pass it the token for the main value and the seperator key and optionally its value. You can easily make a variation that puts the separator before the element and delete it from the first element. If your chunk has more tokens or nested chunks, this sub could be generalized to modify a list of hashes instead of generating one.