NAME

Template::Simple - A simple and very fast template module

VERSION

Version 0.03

SYNOPSIS

    use Template::Simple;

    my $tmpl = Template::Simple->new();

  # here is a simple template store in a scalar
  # the header and footer templates will be included from the cache or files.

    my $template_text = <<TMPL ;
[%INCLUDE header%]
[%START row%]
	[%first%] - [%second%]
[%END row%]
[%INCLUDE footer%]
TMPL

  # this is data that will be used to render that template the keys
  # are mapped to the chunk names (START & END markups) in the
  # template the row is an array reference so multiple rows will be
  # rendered usually the data tree is generated by code instead of
  # being pure data.

    my $data = {
	header	=> {
		date	=> 'Jan 1, 2008',
		author	=> 'Me, myself and I',
	},
	row	=> [
		{
			first	=> 'row 1 value 1',
			second	=> 'row 1 value 2',
		},
		{
			first	=> 'row 2 value 1',
			second	=> 'row 2 value 2',
		},
	],
	footer	=> {
		modified	=> 'Aug 31, 2006',
	},
    } ;

  # this call renders the template with the data tree

    my $rendered = $tmpl->render( \$template_text, $data ) ;

  # here we add the template to the cache and give it a name

    $tmpl->add_templates( { demo => $template_text } ) ;

  # this compiles and then renders that template with the same data
  # but is much faster

    $tmpl->compile( 'demo' ) ;
    my $rendered = $tmpl->render( 'demo', $data ) ;

DESCRIPTION

Template::Simple is a very fast template rendering module with a simple markup. It can do almost any templating task and is extendable with user callbacks. It can render templates directly or compile them for more speed.

CONSTRUCTOR

new

You create a Template::Simple by calling the class method new:

my $tmpl = Template::Simple->new() ;

All the arguments to new() are key/value options that change how the object will render templates.

pre_delim

This option sets the string or regex that is the starting delimiter for all markups. You can use a plain string or a qr// but you need to escape (with \Q or \) any regex metachars if you want them to be plain chars. The default is qr/\[%/.

my $tmpl = Template::Simple->new(
	pre_delim => '<%',
);

my $rendered = $tmpl->render( '<%FOO%]', 'bar' ) ;

post_delim

This option sets the string or regex that is the ending delimiter for all markups. You can use a plain string or a qr// but you need to escape (with \Q or \) any regex metachars if you want them to be plain chars. The default is qr/%]/.

my $tmpl = Template::Simple->new(
	post_delim => '%>',
);

my $rendered = $tmpl->render( '[%FOO%>', 'bar' ) ;

token_re

This option overrides the regular expression that is used match a token or name in the markup. It should be a qr// and you may need to escape (with \Q or \) any regex metachars if you want them to be plain chars. The default is qr/\w+?/.

my $tmpl = Template::Simple->new(
	token_re => qr/[\w-]+?/,
);

my $rendered = $tmpl->render(
	'[% id-with-hyphens %]',
	{ 'id-with-hyphens' => 'bar' }
) ;

greedy_chunk

This boolean option will cause the regex that grabs a chunk of text between the START/END markups to become greedy (.+). The default is a not-greedy grab of the chunk text. (UNTESTED)

templates

This option lets you load templates directly into the cache of the Template::Simple object. See <TEMPLATE CACHE> for more on this.

my $tmpl = Template::Simple->new(
	templates	=> {
		foo	=> <<FOO,
[%baz%] is a [%quux%]
FOO
		bar	=> <<BAR,
[%user%] is not a [%fool%]
BAR
	},
);

search_dirs, include_paths

This option lets you set the directory paths to search for template files. Its value is an array reference with the paths. Its default is 'templates'.

my $tmpl = Template::Simple->new(
		search_dirs => [ qw(
			templates
			templates/deeper
		) ],
) ;

NOTE: This option was called include_paths but since it is used to locate named templates as well as included ones, it was changed to search_dirs. The older name include_paths is still supported but new code should use search_dirs.

METHODS

render

This method is passed a template and a data tree and it renders it and returns a reference to the resulting string.

If the template argument is a scalar reference, then it is the template text to be rendered. A scalar template argument is first assumed to be a template name which is searched for in the template cache and the compiled template caches. If found in there it is used as the template. If not found there, it is searched for in the directories of the search_dirs. Finally if not found, it will be used as the template text.

The data tree argument can be any value allowed by Template::Simple when rendering a template. It can also be a blessed reference (Perl object) since Scalar::Util::reftype is used instead of ref to determine the data type.

Note that the author recommends against passing in an object as this breaks encapsulation and forces your object to be (most likely) a hash. It would be better to create a simple method that copies the object contents to a hash reference and pass that. But other current templaters allow passing in objects so that is supported here as well.

my $rendered = $tmpl->render( $template, $data ) ;

compile

This method takes a template and compiles it to make it run much faster. Its only argument is a template name and that is used to locate the template in the object cache or it is loaded from a file (with the same search technique as regular rendering). The compiled template is stored in its own cache and can be rendered by a call to the render method and passing the name and the data tree.

$tmpl->compile( 'foo' ) ;
my $rendered = $tmpl->render( 'foo', $data ) ;

There are a couple of restrictions to compiled templates. They don't support code references in the data tree (that may get supported in the future). Also since the include expansion happens one time during the compiling, any changes to the template or its includes will not be detected when rendering a compiled template. You need to re-compile a template to force it to use changed templates. Note that you may need to delete templates from the object cache (with the delete_templates method) to force them to be reloaded from files.

add_templates

This method adds templates to the object cache. It takes a list of template names and texts just like the templates constructor option. These templates are located by name when compiling or rendering.

$tmpl->add_templates( 
	{
		foo	=> \$foo_template,
		bar	=> '[%include bar%]',
	}
) ;

delete_templates

This method takes a list of template names and will delete them from the template cache in the object. If you pass no arguments then all the cached templates will be deleted. This can be used when you know a template file has been updated and you want to get it loaded back into the cache.

    # this deletes only the foo and bar templates from the object cache

	$tmpl->delete_templates( qw( foo bar ) ;

    # this deletes all of templates from the object cache

	$tmpl->delete_templates() ;

get_source

$tmpl->get_source( 'bar' ) ;

This method is passed a compiled template name and returns the generated Perl source for a compiled template. You can compile a template and paste the generated source (a single sub per template) into another program. The sub can be called and passed a data tree and return a rendered template. It saves the compile time for that template but it still needs to be compiled by Perl. This method is also useful for debugging the template compiler.

TEMPLATE CACHE

This cache is stored in the object and will be searched to find any template by name. It is initially loaded via the templates option to new and more can be added with the add_templates method. You can delete templates from the cache with the delete_templates method. Compiled templates have their own cache in the module. Deleting a template also deletes it from the compiled cache.

INCLUDE EXPANSION

Before a template is either rendered or compiled it undergoes include expansion. All include markups are replaced by a templated located in the cache or from a file. Included templates can include other templates. This expansion keeps going until no more includes are found.

LOCATING TEMPLATES

When a template needs to be loaded by name (when rendering, compiling or expanding includes) it is first searched for in the object cache (and the compiled cache for compiled templates). If not found there, the templates_paths are searched for files with that name and a suffix of .tmpl. If a file is found, it used and also loaded into the template cache in the object with the searched for name as its key.

MARKUP

All the markups in Template::Simple use the same delimiters which are [% and %]. You can change the delimiters with the pre_delim and post_delim options in the new() constructor.

Tokens

A token is a single markup with a \w+ Perl word inside. The token can have optional whitespace before and after it. A token is replaced by a value looked up in a hash with the token as the key. The hash lookup keeps the same case as parsed from the token markup. You can override the regular expression used to match a token with the token_re option.

[% foo %] [%BAR%]

Those will be replaced by $href-{foo}> and $href-{BAR}> assuming $href is the current data for this rendering. Tokens are only parsed out during hash data rendering so see Hash Data for more.

Chunks

Chunks are regions of text in a template that are marked off with a start and end markers with the same name. A chunk start marker is [%START name%] and the end marker for that chunk is [%END name%]. name is matched with \w+? and that is the name of this chunk. The whitespace between START/END and name is required and there is optional whitespace before START/END and after the name. START/END are case insensitive but the name's case is kept. Chunks are the primary way to markup templates for structures (sets of tokens), nesting (hashes of hashes), repeats (array references) and callbacks to user code. By default a chunk will be a non-greedy grab but you can change that in the constructor by enabling the greedy_chunk option. You can override the regular expression used to match the chunk name with the token_re option.

    [%Start FOO%]
	[% START bar %]
		[% field %]
	[% end bar %]
    [%End FOO%]

Includes

When a markup [%include name%] is seen, that text is replaced by the template of that name. name is matched with \w+? which is the name of the template. You can override the regular expression used to match the include name with the token_re option.

See INCLUDE EXPANSION for more on this.

RENDERING RULES

Template::Simple has a short list of rendering rules and they are easy to understand. There are two types of renderings, include rendering and chunk rendering. In the render method, the template is an unnamed top level chunk of text and it first gets its INCLUDE markups rendered. The text then undergoes a chunk rendering and a scalar reference to that rendered template is returned to the caller.

Include Rendering

All include file rendering happens before any other rendering is done. After this phase, the rendered template will not have [%include name%] markups in it.

Chunk Rendering

A chunk is the text found between matching START and END markups and it gets its name from the START markup. The top level template is considered an unamed chunk and also gets chunk rendered.

The data for a chunk determines how it will be rendered. The data can be a scalar or scalar reference or an array, hash or code reference. Since chunks can contain nested chunks, rendering will recurse down the data tree as it renders the chunks. Each of these renderings are explained below. Also see the IDIOMS and BEST PRACTICES section for examples and used of these renderings.

Hash Data Rendering

If the current data for a chunk is a hash reference then two phases of rendering happen, nested chunk rendering and token rendering. First nested chunks are parsed of of this chunk along with their names. Each parsed out chunk is rendered based on the value in the current hash with the nested chunk's name as the key.

If a value is not found (undefined), then the nested chunk is replaced by the empty string. Otherwise the nested chunk is rendered according to the type of its data (see chunk rendering) and it is replaced by the rendered text.

Chunk name and token lookup in the hash data is case sensitive.

Note that to keep a plain text chunk or to just have the all of its markups (chunks and tokens) be deleted just pass in an empty hash reference {} as the data for the chunk. It will be rendered but all markups will be replaced by the empty string.

The second phase is token rendering. Markups of the form [%token%] are replaced by the value of the hash element with the token as the key. If a token's value is not defined it is replaced by the empty string. This means if a token key is missing in the hash or its value is undefined or its value is the empty string, the [%token%] markup will be deleted in the rendering.

Array Data Rendering

If the current data for a chunk is an array reference it will do a full chunk rendering for each value in the array. It will replace the original chunk text with the concatenated list of rendered chunks. This is how you do repeated sections in Template::Simple and why there is no need for any loop markups. Note that this means that rendering a chunk with $data and [ $data ] will do the exact same thing. A value of an empty array [] will cause the chunk to be replaced by the empty string.

Scalar Data Rendering

If the current data for a chunk is a scalar or scalar reference, the entire chunk is replaced by the scalar's value. This can be used to overwrite one default section of text with from the data tree.

Code Data Rendering

If the current data for a chunk is a code reference (also called anonymous sub) then the code reference is called and it is passed a scalar reference to the that chunk's text. The code must return a scalar or a scalar reference and its value replaces the chunk's text in the template. If the code returns any other type of data it is a fatal error. Code rendering is how you can do custom renderings and plugins. A key idiom is to use closures as the data in code renderings and keep the required outside data in the closure.

DESIGN GOALS

  • High speed

    When using compiled templates T::S is one of the fastest template tools around. There is a benchmark script in the extras/ directory comparing it to Template `Toolkit and Template::Teeny

  • Support most common template operations

    It can recursively include other templates, replace tokens (scalars), recursively render nested chunks of text and render lists. By using simple idioms you can get conditional renderings.

  • Complete isolation of template from program code

    Template design and programming the data logic can be done by different people. Templates and data logic can be mixed and matched which improves reuse and flexibility.

  • Very simple template markup (only 4 markups)

    The only markups are INCLUDE, START, END and token. See MARKUP for more.

  • Easy to follow rendering rules

    Rendering of templates and chunks is driven from a data tree. The type of the data element used in an rendering controls how the rendering happens. The data element can be a scalar, scalar reference, or an array, hash or code reference.

  • Efficient template rendering

    Rendering is very simple and uses Perl's regular expressions efficiently. Because the markup is so simple less processing is needed than many other templaters. You can precompile templates for even faster rendering but with some minor restrictions in flexibility

  • Easy user extensions

    User code can be called during an rendering so you can do custom renderings and plugins. Closures can be used so the code can have its own private data for use in rendering its template chunk.

BUGS

Please report any bugs or feature requests to bug-template-simple at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Template-Simple. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

ACKNOWLEDGEMENTS

I wish to thank Turbo10 for their support in developing this module.

LICENSE

Same as Perl.

COPYRIGHT

Copyright 2011 Uri Guttman, all rights reserved.

SEE ALSO

An article on file slurping in extras/slurp_article.pod. There is also a benchmarking script in extras/slurp_bench.pl.

AUTHOR

Uri Guttman, <uri@stemsystems.com>