Chapter 4. Template Directives
Templates consist of a combination of fixed text and template directives. The template directives are recognized by the Template Toolkit and are expanded in a processor’s output. In this chapter, we will take a close look at all of the directives that the Template Toolkit provides. We’ve already seen examples of many of them in previous chapters, but now we’ll go back and fill in all of the details.
The Template Toolkit has directives for common presentation tasks. There are directives for accessing and setting variables, loading and using both external and local templates, repetition, conditional processing, flow control, and exception handling. Directives are also provided to define macros and access template metadata. If that’s not enough for you, you can extend the functionality of the Template Toolkit using filters, plugins, or even inline Perl code.
Accessing Variables
The Template Toolkit allows you to define variables in your templates. In this section, we will look at the various directives that the Template Toolkit provides for manipulating template variables.
GET
The GET
directive retrieves and outputs the value of the named
variable:
[% GET foo %]
The GET
keyword is optional.
A variable can be specified in a directive tag by itself:
[% foo %]
The variable name can have an unlimited number of elements, each separated by a . (dot). Each element can have arguments specified within parentheses:
[% foo %] [% bar.baz %] [% biz.baz(10) %]
See Chapter 3 for a full discussion of template variables.
The GET
directive can also
take an expression as an argument:
[% GET total + tax %] [% GET length * breadth * height %]
Expressions can use any of the mathematical operators +
, -
,
*
, /
, mod
,
div
, and %
. They can be combined using the logical
operators and
, or
, and not
. &&
, ||
, and !
are provided as aliases for and
,
or
, and not
.
[% GET golgafrincham.answer or 42 %]
The mod
, div
, and %
operators carry out integer division.
div
returns the result of the
division and mod
returns the
modulus (or remainder) from the division:
[% SET people = 4 pies = 10 %] [% pies %] pies shared between [% people %] people is [% pies div people %] pies each (and [% pies mod people %] pies left over)
The %
operator is a synonym
for mod
.
The logical operator ?
: is
also available:
[% pies > people * 2 ? 'everyone happy' : 'not enough pies' %]
This operator works by evaluating the expression that comes
before the question mark to see if it is true or false. If it is true,
the operator returns the expression that comes before the : character.
If it is false, the operator returns the expression that follows the :
character. In the example, status
is set to either everyone happy
or
not enough pies
depending on
whether we have at least two pies for everyone.
The comparison operators = =
,
!=
, <
, <=
, >
, and >=
are also provided. Note that they
always compare their operands as strings.
[% GET name = = 'Zaphod' ? 'Greetings Mr. President' : 'Hello Monkey' %]
SET
The SET
directive allows
you to assign new values to existing variables or to create new
temporary variables:
[% SET title = 'Hello World' %]
The SET
keyword is optional
when it is unambiguous:
[% title = 'Hello World' %]
Variables may be assigned the values of other variables,
unquoted numbers (digits), literal text (single quotes), or quoted
text (double quotes). In the latter case, any variable references
within the text will be interpolated when the string is evaluated.
Variables should be prefixed by $
,
using curly braces to explicitly scope the variable name where
necessary.
[% foo = 'Foo' %] # literal value 'Foo' [% bar = foo %] # value of variable 'foo' [% cost = '$100' %] # literal value '$100' [% item = "$bar: ${cost}.00" %] # value "Foo: $100.00"
Multiple variables may be assigned in the same directive and are evaluated in the order specified. Thus, the previous example could have been written:
[% foo = 'Foo' bar = foo cost = '$100' item = "$bar: ${cost}.00" %]
Simple expressions can also be used, as they can with GET
:
[% ten = 10 twenty = 20 thirty = twenty + ten forty = 2 * twenty fifty = 100 div 2 six = twenty mod 7 %]
You can concatenate strings together using the underscore
(_
) operator. In Perl 5, the . is
used for string concatenation, but in Perl 6, as in the Template
Toolkit, the . will be used as the method-calling operators and the
underscore (_
) operator will be
used for string concatenation.[7] Note that the operator must be specified with
surrounding whitespace that, as Larry says, is construed as a
feature:
[% copyright = '(C) Copyright ' _ year _ ' ' _ author %]
You can, of course, achieve a similar effect with double-quoted string interpolation:
[% copyright = "(C) Copyright $year $author" %]
The SET
directive can also
take arguments that are expressions in exactly the same way as the
GET
directive:
[% total = price + (price * tax_rate) %]
CALL
The CALL
directive is similar to GET
in evaluating the variable named, but
doesn’t print the result returned. This can be useful when a variable
is bound to a subroutine or object method that you want to call but
whose returned value you aren’t interested in.
[% CALL dbi.disconnect %] [% CALL inc_page_counter(page_count) %]
DEFAULT
The DEFAULT
directive is
similar to SET
but updates only
variables that are currently undefined or have no “true” value (in the
Perl sense):
[% DEFAULT name = 'John Doe' id = 'jdoe' %]
This can be particularly useful in common template components to ensure that some sensible default is provided for otherwise undefined variables. If a true value is provided for variables with DEFAULT values, the provided value will be used; otherwise, the default value will be used.
[% DEFAULT title = 'Hello World' bgcol = '#ffffff' %] <html> <head> <title>[% title %]</title> </head> <body bgcolor="[% bgcol %]">
DEFAULT
can also take an
expression as an argument in exactly the same way as GET
:
[% DEFAULT pies = 3 * people %]
DEFAULT
has no effect on
variables that already have values.
Accessing External Templates and Files
Variables are for storing little bits of data. Templates are for writing larger chunks of content. As with variables, it is often useful to be able to reuse the contents of a template. For example, the output of a template will often actually be composed of the output of a number of lower-level templates. These lower-level templates can be reused in other templates. This is very similar to the modular approach to writing programs that encourages code reuse.
The Template Toolkit provides a number of directives for
manipulating templates. The first three of these all work in a very
similar way. INSERT
, PROCESS
, and INCLUDE
all insert the contents of another
named template into the current template. The basic syntax for these
directives looks like this:
[% INCLUDE filename %]
You may optionally include arguments (in a name = value
format) that define variables to
use while processing the included template:
[% INCLUDE filename title = "la la la" moonphase = "waxing" %]
With all of these directives, the results of processing the
template are included in the output in place of the directive. The
WRAPPER
directive works a little
differently. It is a block directive and it allows you to define a
template that is wrapped around the block of content. The content of the
block is made available to the wrapper template in
a special variable called content
.
[% WRAPPER layout %] blah blah [% END %]
We discuss the directives for manipulating templates in the next four sections.
INSERT
The INSERT
directive is
used to insert the contents of an external file at the current
position:
[% INSERT myfile %]
No attempt to parse or process the file is made. The contents, possibly including any embedded template directives, are inserted intact.
The filename specified should be relative to one of the INCLUDE_PATH
directories. Absolute (i.e.,
starting with /
) and relative
(i.e., starting with .) filenames may be used if the ABSOLUTE
and RELATIVE
options are set, respectively. Both
of these options are disabled by default.
my $tt = Template->new({ INCLUDE_PATH => '/here:/there:/every/where', }); $tt->process('myfile');
The contents of myfile are:
[% INSERT foo %] # looks for /here/foo then /there/foo [% INSERT /etc/passwd %] # file error: ABSOLUTE not set [% INSERT ../secret %] # file error: RELATIVE not set
For convenience, the filename does not need to be quoted as long as it contains only alphanumeric characters, underscores, dots, or forward slashes. Names containing any other characters should be quoted.
[% INSERT misc/legalese.txt %] [% INSERT 'dos98/Program Files/foobar' %]
To evaluate a variable to specify a filename, you should
explicitly prefix it with a $
or
use double-quoted string interpolation:
[% language = 'en' legalese = 'misc/legalese.txt' %] [% INSERT $legalese %] # 'misc/legalese.txt' [% INSERT "$language/$legalese" %] # 'en/misc/legalese.txt'
Multiple files can be specified using +
as a delimiter. All files should be
unquoted names or quoted strings. Any variables should be interpolated
into double-quoted strings.
[% INSERT legalese.txt + warning.txt %] [% INSERT "$legalese" + warning.txt %] # requires quoting
INCLUDE
The INCLUDE
directive is
used to process and include the output of another template file or
block:
[% INCLUDE header %]
If a BLOCK
of the specified
name is defined in the same file or in a file from which the current
template has been called (i.e., a parent template), it will be used in
preference to any file of the same name.
[% INCLUDE table %] # uses BLOCK defined below [% BLOCK table %] <table> ... </table> [% END %]
If a BLOCK
definition is not
currently visible, the template name should be a file relative to one
of the INCLUDE_PATH
directories, or
an absolute or relative filename if the ABSOLUTE
/ RELATIVE
options are appropriately enabled.
The INCLUDE
directive automatically
quotes the filename specified, as per INSERT
described earlier. When a variable
contains the name of the template for the INCLUDE
directive, it should be explicitly
prefixed by $
or
double-quoted:
[% myheader = 'my/misc/header' %] [% INCLUDE myheader %] # 'myheader' [% INCLUDE "myheader" %] # 'myheader' [% INCLUDE $myheader %] # 'my/misc/header' [% INCLUDE "$myheader" %] # 'my/misc/header'
Any template directives embedded within the file will be processed accordingly. All variables currently defined will be visible and accessible from within the included template.
[% title = 'Hello World' %] [% INCLUDE header %] <body> ...
Therefore, this header template:
<html> <title>[% title %]</title>
provides the following output:
<html> <title>Hello World</title> <body> ...
Local variable definitions may be specified after the template name, temporarily masking any existing variables. Insignificant whitespace is ignored within directives, so you can add variable definitions on the same line, on the next line, or split across several lines with comments interspersed, if you prefer.
[% INCLUDE table %] [% INCLUDE table title="Active Projects" %] [% INCLUDE table title = "Active Projects" bgcolor = "#80ff00" # chartreuse border = 2 %]
The INCLUDE
directive
localizes (i.e., copies) all variables before processing the template.
Any changes made within the included template will not affect
variables in the including template.
[% foo = 10 %] foo is originally [% foo %] [% INCLUDE bar %] foo is still [% foo %] [% BLOCK bar %] foo was [% foo %] [% foo = 20 %] foo is now [% foo %] [% END %]
The preceding example produces the following output:
foo is originally 10 foo was 10 foo is now 20 foo is still 10
Tip
The localization of the stash (that is, the process by which
variables are copied before an INCLUDE
to prevent being overwritten) is
only skin-deep. The top-level variable namespace (hash) is copied,
but no attempt is made to perform a deep-copy of other structures
(hashes, arrays, objects, etc.). Therefore, a foo
variable referencing a hash will be
copied to create a new foo
variable that points to the same hash array. Thus, if you update
compound variables (e.g., foo.bar
), you will change the original
copy, regardless of any stash localization. If you’re not worried
about preserving variable values, or you trust the templates you’re
including, you might prefer to use the PROCESS
directive, which is faster by
virtue of not performing any localization.
You can specify dotted variables as “local” variables to an
INCLUDE
directive. However, be
aware that because of the localization issues explained earlier (if
you skipped the previous Note, you might want to go back and read it,
or else skip this section too), the variables might not actually be
“local.” If the first element of the variable name already references
a hash array, the variable update will affect the original
variable.
[% foo = { bar = 'Baz' } %] [% INCLUDE somefile foo.bar='Boz' %] [% foo.bar %] # Boz
This behavior can be a little unpredictable (and may well be
improved upon in a future version). If you know what you’re doing with
it and you’re sure that the variables in question are defined (nor
not) as you expect them to be, you can rely on this feature to
implement some powerful “global” data-sharing techniques. Otherwise,
you might prefer to steer clear and always pass simple (undotted)
variables as parameters to INCLUDE
and other similar directives.
If you want to process several templates simultaneously, you can
specify each of their names (quoted or unquoted names only, no
unquoted $variables
) joined
together by +
. The INCLUDE
directive will then process them in
order.
[% INCLUDE html/header + "site/$header" + site/menu title = "My Groovy Web Site" %]
The variable stash is localized once and then the templates
specified are processed in order, all within that same variable
context. This makes it slightly faster than specifying several
separate INCLUDE
directives
(because you clone the variable stash only once instead of
n times), but it’s not quite as “safe” because
any variable changes in the first file will be visible in the second,
third, and so on. This might be what you want, of course, but then
again, it might not.
PROCESS
The PROCESS
directive is similar to INCLUDE
but does not perform any
localization of variables before processing the template. Any changes
made to variables within the included template will be visible in the
including template. For example, this code:
[% foo = 10 %] foo is [% foo %] [% PROCESS bar %] foo is [% foo %] [% BLOCK bar %] [% foo = 20 %] changed foo to [% foo %] [% END %]
produces this output:
foo is 10 changed foo to 20 foo is 20
Parameters may be specified in the PROCESS
directive, but these too will become
visible changes to current variable values. As such, the following
code:
[% foo = 10 %] foo is [% foo %] [% PROCESS bar foo = 20 %] foo is [% foo %] [% BLOCK bar %] this is bar, foo is [% foo %] [% END %]
produces the following output:
foo is 10 this is bar, foo is 20 foo is 20
The PROCESS
directive is
slightly faster than the INCLUDE
directive because it avoids the need to localize (i.e., copy) the
variable stash before processing the template. As with INSERT
and INCLUDE
, the first parameter does not need
to be quoted as long as it contains only alphanumeric characters,
underscores, periods, or forward slashes. A $
prefix can be used to explicitly indicate
a variable that should be interpolated to provide the template
name:
[% myheader = 'my/misc/header' %] [% PROCESS myheader %] # 'myheader' [% PROCESS $myheader %] # 'my/misc/header'
As with INCLUDE
, multiple
templates can be specified, delimited by +
, and are processed in order:
[% PROCESS html/header + my/header %]
WRAPPER
It’s not unusual to find yourself adding common headers and footers to pages or sub-sections within a page. For example:
[% INCLUDE section/header title = 'Quantum Mechanics' %] Quantum mechanics is a very interesting subject which should prove easy for the layman to fully comprehend. [% PROCESS section/footer %] [% INCLUDE section/header title = 'Desktop Nuclear Fusion for Under $50' %] This describes a simple device that generates significant sustainable electrical power from common tap water via the process of nuclear fusion. [% PROCESS section/footer %]
The individual template components being included might look like the folowing examples:
section/header:
<p> <h2>[% title %]</h2>
section/footer:
</p>
The WRAPPER
directive
provides a way of simplifying this a little. It encloses a block to a
matching END
directive, which is
first processed to generate some output. This is then passed to the
named template file or BLOCK
as the
content
variable.
[% WRAPPER section title = 'Quantum Mechanics' %] Quantum mechanics is a very interesting subject which should prove easy for the layman to fully comprehend. [% END %] [% WRAPPER section title = 'Desktop Nuclear Fusion for Under $50' %] This describes a simple device that generates significant sustainable electrical power from common tap water via the process of nuclear fusion. [% END %]
The single section template can then be defined as:
<p> <h2>[% title %]</h2> [% content %] </p>
Like other block directives, it can be used in side-effect notation:
[% INSERT legalese.txt WRAPPER big_bold_table %]
It’s also possible to specify multiple templates to a WRAPPER
directive. The specification order
indicates outermost to innermost wrapper templates. For example, given
the following template block definitions:
[% BLOCK bold %]<b>[% content %]</b>[% END %] [% BLOCK italic %]<i>[% content %]</i>[% END %]
the directive:
[% WRAPPER bold + italic %]Hello World[% END %]
would generate the following output:
<b><i>Hello World</i></b>
Defining Local Template Blocks
Sometimes, particularly in a project that involves a large number of
small templates, it doesn’t seem very efficient to create an external
file for every template that you need. The BLOCK
..
.
END
construct can be used to avoid
this. It allows you to define template component blocks that can be
processed with the INCLUDE
, PROCESS
, and WRAPPER
directives.
[% BLOCK tabrow %] <tr><td>[% name %]<td><td>[% email %]</td></tr> [% END %] <table> [% PROCESS tabrow name='Fred' email='fred@nowhere.com' %] [% PROCESS tabrow name='Alan' email='alan@nowhere.com' %] </table>
A BLOCK
definition can be used
before it is defined, as long as the definition resides in the same
file. The block definition itself does not generate any output.
[% PROCESS tmpblk %] [% BLOCK tmpblk %] This is OK [% END %]
You can use an anonymous BLOCK
to capture the output of a template fragment:
[% julius = BLOCK %] And Caesar's spirit, ranging for revenge, With Ate by his side come hot from hell, Shall in these confines with a monarch's voice Cry 'Havoc', and let slip the dogs of war; That this foul deed shall smell above the earth With carrion men, groaning for burial. [% END %]
Like a named block, an anonymous block can contain any other
template directives that are processed when the block is defined. The
output generated by the block is then assigned to the variable julius
.
Anonymous BLOCK
s can also be
used to define block macros. The enclosing block is processed each time
the macro is called.
[% MACRO locate BLOCK %] The [% animal %] sat on the [% place %]. [% END %] [% locate(animal='cat', place='mat') %] # The cat sat on the mat [% locate(animal='dog', place='log') %] # The dog sat on the log
Loops
It is very common to want to repeat parts of a template. You
might want to produce similar output for every item in a list, or you
might want to repeat a piece of content a set number of times. The
Template Toolkit provides two loop directives that deal with both of
these situations—FOREACH
(also
spelled FOR
) and WHILE
.
Use FOREACH
in cases where you
know the size of the data set over which you are iterating, or in cases
where you need access to loop metadata, such as the next or previous
element, the index of the iteration, or the size of the data set.
WHILE
is useful for performing an
action until a condition is true, for looping over a very large data
set, or when termination of the loop depends on a condition external to
the data set. Both directives are discussed in the sections that
follow.
FOREACH
The FOREACH
directive
defines a block, up to the corresponding END
tag, that is processed repeatedly for
each item in a list. The basic syntax is:
[% FOREACH item IN list %] # content of block [% END %]
You can also use =
in place
of IN
if you find that more
natural:
[% FOREACH item = list %] # content of block [% END %]
FOREACH
loops over each
element in a list and creates an alias to the current item:
[% numbers = [ 1 .. 5 ] %] [% FOREACH num IN numbers %] * [% num %] [% END %]
In this example, numbers
is
an array of five elements, the numbers 1 through 5. In the FOREACH
loop, these elements are assigned to
num
, one at a time, in the order
that they occur in numbers
:
* 1 * 2 * 3 * 4 * 5
Complex data
The elements of the array can be any kind of complex data:
[% fabfour = [ { name = "John Lennon" instrument = "guitar" } { name = "Paul McCartney" instrument = "bass guitar" } { name = "George Harrison" instrument = "lead guitar" } { name = "Ringo Starr" instrument = "drums" } ] %] [% FOREACH beatle IN fabfour -%] [% beatle.name %] played [% beatle.instrument %]. [% END %]
The beatle
variable is
aliased to each hash in the fabfour
list, and through it we can access
the various elements:
John Lennon played guitar. Paul McCartney played bass guitar. George Harrison played lead guitar. Ringo Starr played drums.
The original array is not modified, but the elements of the
array can be modified within the FOREACH
loop.
Importing hash array items
When the FOREACH
directive
is used without specifying a target variable, any iterated values
that are hash references will be automatically imported:
[% FOREACH fabfour -%] [% name %] played [% instrument %]. [% END %]
This particular usage creates a localized variable context to
prevent the imported hash keys from overwriting any existing
variables. The imported definitions and any other variables defined
in such a FOREACH
loop will be
lost at the end of the loop, when the previous context and variable
values are restored.
Iterating over entries in a hash array
The FOREACH
directive can also be used to iterate over the entries
in a hash array. Each entry in the hash is returned in sorted order
(based on the key) as a hash array containing “key” and “value”
items.
[% users = { tom = 'Thomas' dick = 'Richard' larry = 'Lawrence' } %] [% FOREACH user IN users %] * [% user.key %] : [% user.value %] [% END %]
The previous example generates the following output:
* dick : Richard * larry : Lawrence * tom : Thomas
To iterate over the keys of a hash, use the keys
virtual method on the hash:
[% FOREACH key IN hash.keys %] * [% key %] : [% hash.$key %] [% END %]
The loop iterator object
The underlying implementation of the FOREACH
directive involves the creation of
a special object called an iterator, which
maintains metadata about the data set being processed. This object
can be accessed within the body of the FOREACH
using the special variable
loop
:
[% FOREACH item IN items %] [% IF loop.first %] <ul> [% END %] <li>[% item %] ([% loop.count %] of [% loop.size %])</li> [% IF loop.last %] </ul> [% END %] [% END %]
The iterator defines several useful methods that return information about the current loop:
- size
Returns the size of the data set, or returns
undef
if the dataset has not been defined- max
Returns the maximum index number (i.e., the index of the last element), which is equivalent to
size
-1
- index
Returns the number of the current item, in the range
0
tomax
- count
Returns the current iteration count in the range
1
tosize
, equivalent toindex
+ 1- first
Returns a Boolean value to indicate whether the iterator is currently on the first iteration of the set
- last
Returns a Boolean value to indicate whether the iterator is currently on the last iteration of the set
- prev
Returns the previous item in the data set, or returns
undef
if the iterator is on the first item- next
Returns the next item in the data set, or
undef
if the iterator is on the last item
An iterator
plugin is
available that enables you to control how an iterator is created; if
an iterator object is passed to a FOREACH
loop, it is used as is (a new
iterator is not created).
[% USE all_data = iterator(list_one.merge(list_two)) %] [% FOREACH datum = all_data %] ... [% END %]
Nested FOREACH loops
Nested loops will work as expected, with the loop
variable correctly referencing the
innermost loop and being restored to any previous value (i.e., an
outer loop) at the end of the loop:
[% FOREACH group IN grouplist; # loop => group iterator "Groups:\n" IF loop.first; FOREACH user IN group.userlist; # loop => user iterator "$loop.count: $user.name\n"; END; # loop => group iterator "End of Groups\n" IF loop.last; END %]
The iterator
plugin can
also be used to explicitly create an iterator object. This can be
useful within nested loops where you need to keep a reference to the
outer iterator within the inner loop. The iterator
plugin effectively allows you to
create an iterator by a name other than loop
. See the manpage for Template::Plugin::Iterator
for further
details.
[% USE giter = iterator(grouplist) %] [% FOREACH group IN giter %] [% FOREACH user IN group.userlist %] user #[% loop.count %] in group [% giter.count %] is named [% user.name %] [% END %] [% END %]
WHILE
WHILE
loops are used to repeatedly process a template block. This
block is enclosed within [% WHILE (test) %]
... [% END %]
blocks and can be arbitrarily complex. The
test condition follows the same rules as those for IF
blocks.
[% total = 0; WHILE total <= 100 %] Total: [% total; total = total + 1; END; %]
An assignment can be enclosed in parentheses to evaluate the assigned value:
[% WHILE (user = next_user) %] [% user.name %] [% END %]
The Template Toolkit uses a fail-safe counter to limit the
number of loop iterations to prevent runaway loops that never
terminate. If the loop exceeds 1,000 iterations, an undef
exception will be thrown, reporting
the error:
WHILE loop terminated (> 1000 iterations)
This number can be adjusted from within Perl by setting the
$Template::Directive::WHILE_MAX
variable.
Flow control: NEXT and LAST
The NEXT
directive starts the next iteration in a FOREACH
or WHILE
loop:
[% FOREACH user IN userlist %] [% NEXT IF user.isguest %] Name: [% user.name %] Email: [% user.email %] [% END %]
The LAST
directive can be
used to prematurely exit the loop. BREAK
is also provided as an alias for
LAST
.
[% FOREACH match IN results.nsort('score').reverse %] [% LAST IF match.score < 50 %] [% match.score %] : [% match.url %] [% END %]
See the section titled Section 4.11 later in this chapter for more details.
Conditionals
Often you don’t know exactly what output is required until you process the template. Perhaps your web site should be orange on certain days of the week, or maybe negative numbers should be displayed in red. The Template Toolkit has a number of conditional directives that allow your template to make decisions about what path to take.
A conditional controls execution of a block
of code, based on the value of a variable. In the Template Toolkit,
there are two main conditional directives: IF
and SWITCH
. In addition, there is the UNLESS
directive, which is a negated IF
.
IF, ELSIF, ELSE, and UNLESS
The primary directive for conditional
execution is the IF
statement. The basic syntax is:
[% IF test %] action [% END %]
where action
is executed only
if test
is true (the Template
Toolkit’s definition of “truth” is explained later in this section).
IF
statements allow for an optional
ELSE
clause, which is executed if
test
is not true. There can be
multiple test/action pairs as well; these are written using the ELSIF
statement:
[% IF today = = "friday" %] Yay! It's Friday! [% ELSIF today = = "monday" %] Yuck. It's Monday. [% ELSE %] ... [% END %]
There can be any number of ELSIF
clauses, including none. The ELSE
clause is also
optional. Because the IF
directive
defines a block, the END
token is
not optional.
The test
clause can be any
statement, even just a single variable name; the extreme case is a
test clause of 1
—i.e., always true.
If the result of this statement is 0
or “” (the empty string), test
is considered to be false; everything
else is true. Variables that have not been assigned a value, either
with DEFAULT
or SET
, are considered to be false (the value
of an undefined variable is an empty string).
More complex statements are possible, such as the earlier
example. test
can be arbitrarily
complex. Other than simple variable value, another common test is
equality or comparison: what value does a variable contain? The
notation = =
is used to compare
strings because =
is used for
assignment—it is an error to try to assign to a variable in an
IF
statement, to prevent subtle
errors and hard-to-diagnose problems. Comparison operators
include:
= = Test for equality != Test for inequality < Less than <= Less than or equal to > Greater than >= Greater than or equal to &&, AND grouping ||, OR grouping !, NOT negation
Some of these make sense only for numbers, such as >
, >=
, <
, and <=
. NOT
is used to reverse the meaning of a
test:
[% IF NOT today %] Error! 'today' not defined! [% END %]
There is a special version of IF
that does exactly this: UNLESS
.
[% UNLESS today %] ...
UNLESS
is exactly equivalent
to IF NOT
, and often clarifies the
intent of the condition (but can be more confusing when combined with
ELSIF
clauses, even though this is
a syntactically legal thing to do).
AND
and OR
can be used to construct compound
statements that might otherwise require nested IF
blocks:
[% IF today = = "Friday" AND time >= 1700 %] Go home! It's the weekend! [% END %]
Without grouping, this would need to be:
[% IF today = = "Friday" %] [% IF time >= 1700 %] Go home! It's the weekend! [% END %] [% END %]
As you can imagine, this would get very tedious for blocks with many options.
SWITCH and CASE
The SWITCH
directive makes writing long IF
/ ELSIF
/ ELSE
statements easier when the test
condition needs to be compared to a
number of possible outcomes. SWITCH
consists of a single statement, which is evaluated once, and a number
of CASE
statements,
against which the evaluated value is compared. For example:
[% SWITCH today %] [% CASE "Monday" %] Hi ho, hi ho, it's off to work we go. [% CASE "Friday" %] Friday's here, almost time for the weekend! [% CASE [ "Saturday" "Sunday" ] %] It's the weekend! Party! [% CASE %] Ho hum, just another workday... [% END %]
The value in today
is
compared against each successive CASE
statement until a match is found; the
contents of the matching CASE
statement are processed, or the contents of the default CASE
statement are processed if no match is
found (if there is a default CASE
statement, of course). An equivalent IF
/ ELSIF
/ ELSE
block would look like this:
[% IF today = = "Saturday" OR today = = "Sunday" %] It's the weekend! Party! [% ELSIF today = = "Monday" %] Hi ho, hi ho, it's off to work we go. [% ELSIF today = = "Friday" %] Friday's here, almost time for the weekend! [% ELSE %] Ho hum, just another workday... [% END %]
The SWITCH
statement is
cleaner and there is less syntax to maintain. Most important, however,
is that if the test statement
requires computation instead of just variable comparison, the SWITCH
will be more efficient and has less
potential for side effects.
Filters
One of the problems with templates is that you can never be
completely sure what content will be produced at the end. This is
particularly true if you are pulling in some of your data from an
external source. Perhaps you are producing an HTML page from news
stories that have been entered into a database by reporters. You can’t
be sure the stories don’t contain characters such as <
or &
that should be plain text but will be
interpreted as HTML. Or perhaps you have room for only a certain number
of characters and you don’t know how long a story will be.
The Template Toolkit provides filters to deal with these cases. A
filter can be applied to part of a template and will postprocess those
parts in a defined manner. For example, the html
filter converts troublesome characters to
their equivalent HTML entities, and the truncate
filter will truncate text to a given
length.
The FILTER
directive introduces
a filter, which operates on a block:
[% FILTER html %] HTML text may have < and > characters embedded that you want converted to the correct HTML entities. [% END %]
The previous example produces the following output:
HTML text may have < and > characters embedded that you want converted to the correct HTML entities.
The FILTER
directive can
also follow various other nonblock directives. For example:
[% INCLUDE mytext FILTER html %]
The |
character can also be
used as an alias for FILTER
:
[% INCLUDE mytext | html %]
Multiple filters can be chained together and will be called in sequence:
[% INCLUDE mytext FILTER html FILTER html_para %]
or:
[% INCLUDE mytext | html | html_para %]
A number of standard filters are provided with the Template Toolkit; these are detailed in Chapter 5.
Plugins
It is obviously impossible for the Template Toolkit to do everything that everyone might want to do with it. For one thing, we haven’t heard of every possible piece of software that you might want to talk to, and for another, no one would want a template processor that is infinite in size! Instead, we provided the plugin mechanism, which makes it possible to write extensions to the Template Toolkit. This is a far saner solution.
Plugins are externally defined extensions that can be dynamically loaded into templates to provide functionality. A plugin is a regular Perl module that conforms to a particular object-oriented interface, allowing it to be loaded into and used automatically by the Template Toolkit. The next subsections discuss directives for working with plugins.
USE
The USE directive loads and initializes “plugin” extension modules:
[% USE date %]
This makes a date
plugin
object available to the template, which can be used by referencing the
variable date
:
Today is [% date.format(date.now, "%A") %].
which might return:
Today is Monday.
The plugin name is case sensitive and will be appended to the
PLUGIN_BASE value (which defaults to Template::Plugin) to construct a full module
name. Any periods (i.e., .), in the name will be converted to :
:.
[% USE MyPlugin %] # => Template::Plugin::MyPlugin [% USE Foo.Bar %] # => Template::Plugin::Foo::Bar
Various standard plugins are included with the Template Toolkit (see Chapter 6). These can be specified in lowercase and are mapped to the appropriate name:
[% USE cgi %] # => Template::Plugin::CGI [% USE table %] # => Template::Plugin::Table
Any additional parameters supplied in parentheses after the
plugin name also will be passed to the new(
) constructor. A reference to the current Template::Context
object is always passed as
the first parameter. Thus:
[% USE MyPlugin('foo', 123) %]
is equivalent to:
Template::Plugin::MyPlugin->new($context, 'foo', 123);
Named parameters may also be specified. These are collated into a hash that is passed by reference as the last parameter to the constructor, as per the general code-calling interface. Thus:
[% USE url('/cgi-bin/foo', mode='submit', debug=1) %]
is equivalent to:
Template::Plugin::URL->new($context, '/cgi-bin/foo', { mode => 'submit', debug => 1 });
The plugin may represent any data type—a simple variable, hash, list, or code reference—but in general it will be an object reference. Methods can be called on the object (or on the relevant members of the specific data type) in the usual way:
[% USE table(mydata, rows=3) %] [% FOREACH row = table.rows %] <tr> [% FOREACH item = row %] <td>[% item %]</td> [% END %] </tr> [% END %]
A plugin can be referenced by an alternative name:
[% USE scores = table(myscores, cols=5) %] [% FOREACH row = scores.rows %] ... [% END %]
You can use this approach to create multiple plugin objects with
different configurations. This example shows how the format
plugin is used to create subroutines
bound to variables for formatting text as per printf( ).
[% USE bold = format('<b>%s</b>') %] [% USE ital = format('<i>%s</i>') %] [% bold('This is bold') %] [% ital('This is italic') %]
The previous example generates the following output:
<b>This is bold</b> <i>This is italic</i>
This next example shows how the URL plugin can be used to build dynamic URLs from a base part and optional query parameters:
[% USE mycgi = URL('/cgi-bin/foo.pl', debug=1) %] <a href="[% mycgi %]">... <a href="[% mycgi(mode='submit') %]"...
The previous example generates the following output:
<a href="/cgi-bin/foo.pl?debug=1">... <a href="/cgi-bin/foo.pl?mode=submit&debug=1">...
The LOAD_PERL option
(disabled by default) provides a further way by which external Perl
modules may be loaded. If a regular Perl module (i.e., not a Template::Plugin::*
or other module relative
to some PLUGIN_BASE) supports an object-oriented interface and a
new( ) constructor, it can be
loaded and instantiated automatically. The following trivial example
shows how the IO::File
module might
be used:
[% USE file = IO.File('/tmp/mydata') %] [% WHILE (line = file.getline) %] <!-- [% line %] --> [% END %]
Chapter 6 discusses plugins in excruciating detail.
Macros
Sometimes Template Toolkit code can get very complicated. You can
often have complex pieces of code that get repeated a number of times
throughout your template. One solution to this problem is to extract the
code into another template and call it with PROCESS
whenever it is needed:
[% PROCESS my/gnarly/code day='Monday' %] ...later... [% PROCESS my/gnarly/code day='Tuesday' %]
This idea works well for larger chunks of code, but it can be a little unwieldy if used often. A far better idea is to define a macro. A macro is a piece of arbitrary Template Toolkit code that is given a name, enabling you to call it later in the template. For example:
[% USE date -%] [% MACRO now GET date.format(date.now, '%H:%M:%S') -%] [% MACRO today GET date.format(date.now, '%Y-%m-%d') -%]
This defines two macros called now
and today
that will output the current time and
date whenever they are called in the template:
[% now %] [% today %]
The following subsection introduces the directive for working with macros.
MACRO
The MACRO
directive
allows you to define a directive or directive block that is evaluated
each time the macro is called:
[% MACRO header INCLUDE header %]
Calling the macro as:
[% header %]
is then equivalent to:
[% INCLUDE header %]
Macros can be passed named parameters when called. These values remain local to the macro. Therefore, calling the macro as:
[% header(title='Hello World') %]
is equivalent to:
[% INCLUDE header title='Hello World' %]
A MACRO definition may include parameter names. Values passed to the macros are then mapped to these local variables. Other named parameters may follow these.
[% MACRO header(title) INCLUDE header %] [% header('Hello World') %] [% header('Hello World', bgcol='#123456') %]
There are equivalent to:
[% INCLUDE header title='Hello World' %] [% INCLUDE header title='Hello World' bgcol='#123456' %]
Here’s another example, defining a macro for display numbers in comma-delimited groups of three, using the chunk and join virtual method:
[% MACRO number(n) GET n.chunk(-3).join(',') %] [% number(1234567) %] # 1,234,567
A MACRO may precede any directive, including block directives, but must conform to the structure of the directive:
[% terms = { sass = 'know, be aware of, meet, have sex with', hoopy = 'really together guy', frood = 'really, amazingly together guy' }; MACRO explain(term) IF (explanation = terms.$term); "$term ($explanation)"; ELSE; term; END; %]
Here we define the explain(term)
macro as an IF
/ ELSE
directive. It consults a hash table to locate an explanation for the
term passed as an argument. It generates a string containing the term
and explanation, or the term by itself if no explanation is
found.
Hey you [% explain('sass') %] that [% explain('hoopy') %] Ford Prefect? There's a [% explain('frood') %] who really knows where his towel is.
This generates the following output:
Hey you sass (know, be aware of, meet, have sex with) that hoopy (really together guy) Ford Prefect? There's a frood (really, amazingly together guy) who really knows where his towel is.
A MACRO can also be defined as an anonymous BLOCK. The block will be evaluated each time the macro is called.
[% MACRO translate(text) BLOCK; words = [ ]; FOREACH word IN text.split; IF (explanation = terms.$word); words.push("$word ($explanation)"); ELSE; words.push(word); END; END; words.join(' '); END %]
This macro splits the text passed as an argument into words, attempts to explain them, and then joins them back up into a single piece of text:
[% translate( "Hey you sass that hoopy Ford Prefect? There's a frood who really knows where his towel is." ) %]
This is the output generated by the previous template fragment:
Hey you sass (know, be aware of, meet, have sex with) that hoopy (really together guy) Ford Prefect? There's a frood (really, amazingly together guy) who really knows where his towel is.
A MACRO
can also be defined
as a PERL
block, but will require
the EVAL_PERL
option to be
set:
[% MACRO triple(n) PERL %] my $n = $stash->get('n'); print $n * 3; [% END -%]
The PERL
and RAWPERL
directives are covered at the end of this
chapter.
Template Metadata
The Template Toolkit compiles a template into a Perl object
(an instance of the class Template::Document
). This object contains Perl
code that reproduces the required behavior of the template. You can
access the data in this object via the template
variable.
The Template::Document
has
access to various items of metadata about the template that you can
access via template
. This always
includes the name of the template and the last modification time, so it
is always possible to include things such as this in your
template:
[% USE date(format => '%Y-%m-%d %H:%M:%S') %] [% template.name %] Last modified: [% date.format(template.modtime) %]
Further metadata items can be added using the META
directive, discussed next. These new
items will also be available through the template
variable.
[% META moon_phase = 'first quarter' -%] Phase of moon: [% template.moon_phase %]
META
The META directive allows simple metadata items to be defined within a template. These are evaluated when the template is parsed, and as such may contain only simple values (e.g., it’s not possible to interpolate other variable values into META variables).
[% META title = 'The Cat in the Hat' author = 'Dr. Seuss' version = 1.23 %]
The template variable contains a reference to the main template being processed. These metadata items may be retrieved as attributes of the template.
<h1>[% template.title %]</h1> <h2>[% template.author %]</h2>
The name and modtime metadata items are automatically defined for each template to contain its name and modification time in seconds since the epoch:
[% USE date %] # use Date plugin to format time ... [% template.name %] last modified at [% date.format(template.modtime) %]
The PRE_PROCESS and POST_PROCESS options allow common headers and footers to be added to all templates. The template reference is correctly defined when these templates are processed, allowing headers and footers to reference metadata items from the main template:
$tt = Template->new({ PRE_PROCESS => 'header', POST_PROCESS => 'footer', }); $tt->process('cat_in_hat');
header:
<html> <head> <title>[% template.title %]</title> </head> <body>
cat_in_hat:
[% META title = 'The Cat in the Hat' author = 'Dr. Seuss' version = 1.23 year = 2000 %] The cat in the hat sat on the mat.
footer:
<hr /> © [% template.year %] [% template.author %] </body> </html>
The output generated from the preceeding example is:
<html> <head> <title>The Cat in the Hat</title> </head> <body> The cat in the hat sat on the mat. <hr /> © 2000 Dr. Seuss </body> </html>
Exception Handling
No matter how careful you are, things always go wrong. Errors are a
fact of life. Your templates could contain bad code and fail to compile.
Or you could get an error thrown from the Template Toolkit—maybe it
can’t find the header file you asked for. Or your back-end code could
raise an error—you failed to connect to the required database. The
Template Toolkit wouldn’t be of much use if common errors such as these
caused it to keel over and die. That’s why it provides an
exception-handling mechanism in the form of TRY
...CATCH
.
Exceptions are just a fancy way of saying
errors. They’re structured as objects so that an error can have a type
(just a word to identify the kind of error that occurred, such as
database
, user
, or file
) and an info field that provides further
information about the specifics of the error. They get thrown just like
regular errors, via Perl’s die, but
rather than saying die 'bad apple
',
we say THROW bad apple
.
You don’t have to explicitly add code to handle errors. If you don’t and an error occurs, it gets reported in the usual way. But if you know that errors might occur and you have a sensible way of recovering from them, it’s good to add TRY...CATCH to do that.
Using the exception mechanism doesn’t force you to worry about all errors that might occur. You can filter on the type of error and just look out for your one custom error code to catch, letting everything else pass through. Exceptions can also be nested, so you can catch them at the most appropriate level in your template.
TRY / THROW / CATCH / FINAL
The Template Toolkit supports fully functional, nested exception handling. The TRY directive introduces an exception-handling scope that continues until the matching END directive. Any errors that occur within that block will be caught and can be handled by one of the CATCH blocks defined.
[% TRY %] ...blah...blah... [% CALL somecode %] ...etc... [% INCLUDE someblock %] ...and so on... [% CATCH %] An error occurred! [% END %]
Errors are raised as exceptions (objects of the Template::Exception
class) and contain two
fields, type and info. The exception type can be any string containing letters,
numbers, “_” or “.”, and is used to indicate the kind of error that
occurred. The info field contains
an error message indicating what actually went wrong. Within a
CATCH block, the exception object
is aliased to the error variable.
You can access the type and
info fields directly.
[% mydsn = 'dbi:MySQL:foobar' %] ... [% TRY %] [% USE DBI(mydsn) %] [% CATCH %] ERROR! Type: [% error.type %] Info: [% error.info %] [% END %]
The previous example generates the following output (assuming a
nonexistent database called foobar
):
ERROR! Type: DBI Info: Unknown database "foobar"
The error
variable can
also be specified by itself and will return a string of the form
$type error - $info
:
... [% CATCH %] ERROR: [% error %] [% END %]
The previous example generates the following output:
ERROR: DBI error - Unknown database "foobar"
Each CATCH block may be
specified with a particular exception type denoting the kind of error
that it should catch. Multiple CATCH blocks can be provided to handle
different types of exceptions that may be thrown in the TRY block. A CATCH block specified without any type, as
in the previous example, is a default handler that will catch any
otherwise uncaught exceptions. This also can be specified as [% CATCH DEFAULT %]
.
[% TRY %] [% INCLUDE myfile %] [% USE DBI(mydsn) %] [% CALL somecode %] ... [% CATCH file %] File Error! [% error.info %] [% CATCH DBI %] [% INCLUDE database/error.html %] [% CATCH %] [% error %] [% END %]
Remember that you can specify multiple directives within a
single tag, each delimited by ;
.
Thus, you might prefer to write your simple CATCH blocks more succinctly as:
[% TRY %] ... [% CATCH file; "File Error! $error.info" %] [% CATCH DBI; INCLUDE database/error.html %] [% CATCH; error %] [% END %]
or even:
[% TRY %] ... [% CATCH file ; "File Error! $error.info" ; CATCH DBI ; INCLUDE database/error.html ; CATCH ; error ; END %]
The DBI plugin throws exceptions of the DBI type (in case that wasn’t already obvious). The other specific exception caught here is of the file type.
A file error is
automatically thrown by the Template Toolkit when it can’t find a
file, or fails to load, parse, or process a file that has been
requested by an INCLUDE, PROCESS, INSERT, or WRAPPER directive. If myfile
can’t be found in the previous
example, the [% INCLUDE myfile %]
directive will raise a file
exception, which is then caught by the [%
CATCH file %]
block, generating the output:
File Error! myfile: not found
Note that the DEFAULT option
(disabled by default) allows you to specify a default file to be used
any time a template file can’t be found. This will prevent file
exceptions from ever being raised when a nonexistent file is requested
(unless, of course, the DEFAULT
file doesn’t exist). Errors encountered once the file has been found
(i.e., read error, parse error) will be raised as file exceptions as
per usual.
Uncaught exceptions (i.e., the TRY block doesn’t have a type-specific or
default CATCH handler) may be
caught by enclosing TRY blocks that
can be nested indefinitely across multiple templates. If the error
isn’t caught at any level, processing will stop and the Template
process( ) method will return a
false value to the caller. The relevant Template::Exception
object can be retrieved
by calling the error( )
method.
[% TRY %] ... [% TRY %] [% INCLUDE $user.header %] [% CATCH file %] [% INCLUDE header %] [% END %] ... [% CATCH DBI %] [% INCLUDE database/error.html %] [% END %]
In this example, the inner TRY block is used to ensure that the first
INCLUDE directive works as
expected. We’re using a variable to provide the name of the template
we want to include, user.header,
and it’s possible this contains the name of a nonexistent template, or
perhaps one containing invalid template directives. If the INCLUDE fails with a file
error, we CATCH it in the inner block and INCLUDE the default header
file instead. Any DBI errors that
occur within the scope of the outer TRY block will be caught in the relevant
CATCH block, causing the database/error.html template to be
processed. Note that included templates inherit all currently defined
template variables, so these error
files can quite happily access the error
variable to retrieve information about
the currently caught exception. For example:
database/error.html:
<h2>Database Error</h2> A database error has occurred: [% error.info %]
You can also specify a FINAL block. This is always processed regardless of the outcome of the TRY and/or CATCH block. If an exception is uncaught, the FINAL block is processed before jumping to the enclosing block or returning to the caller.
[% TRY %] ... [% CATCH this %] ... [% CATCH that %] ... [% FINAL %] All done! [% END %]
The output from the TRY block is left intact up to the point where an exception occurs. For example, this template:
[% TRY %] This gets printed [% THROW food 'carrots' %] This doesn't [% CATCH food %] culinary delights: [% error.info %] [% END %]
generates the following output:
This gets printed culinary delights: carrots
The CLEAR directive can be used in a CATCH or FINAL block to clear any output created in the TRY block. For example, this template:
[% TRY %] This gets printed [% THROW food 'carrots' %] This doesn't [% CATCH food %] [% CLEAR %] culinary delights: [% error.info %] [% END %]
generates the following output:
culinary delights: carrots
Exception types are hierarchical, with each level being
separated by the familiar dot operator. A DBI.connect
exception is a more specific
kind of DBI error. Similarly, a
myown.error.barf
is a more specific
kind of myown.error
type, which
itself is also a myown
error. A
CATCH handler that specifies a
general exception type (such as DBI
or myown.error
) will also catch
more specific types that have the same prefix as long as a more
specific handler isn’t defined. Note that the order in which CATCH handlers are defined is irrelevant; a
more specific handler will always catch an exception in preference to
a more generic or default one.
[% TRY %] ... [% CATCH DBI ; INCLUDE database/error.html ; CATCH DBI.connect ; INCLUDE database/connect.html ; CATCH ; INCLUDE error.html ; END %]
In this example, a DBI.connect
error has its own handler, a
more general DBI block is used for
all other DBI or DBI.* errors, and a default handler catches
everything else.
Exceptions can be raised in a template using the THROW directive. The first parameter is the exception type, which doesn’t need to be quoted (but can be, it’s the same as INCLUDE), followed by the relevant error message, which can be any regular value such as a quoted string, variable, etc.
[% THROW food "Missing ingredients: $recipe.error" %] [% THROW user.login 'no user id: please login' %] [% THROW $myerror.type "My Error: $myerror.info" %]
It’s also possible to specify additional positional or named
parameters to the THROW directive
if you want to pass more than just a simple message back as the error
info
field:
[% THROW food 'eggs' 'flour' msg='Missing Ingredients' %]
In this case, the error info
field will be a hash array containing the named arguments—in this case
msg => 'Missing Ingredients
'—and
an args
item that contains a list
of the positional arguments—in this case eggs
and flour
. The error type
field remains unchanged; here it is set
to food
.
[% CATCH food %] [% error.info.msg %] [% FOREACH item = error.info.args %] * [% item %] [% END %] [% END %]
This produces the output:
Missing Ingredients * eggs * flour
In addition to specifying individual positional arguments as
[% error.info.args.n %]
, the
info
hash contains keys directly
pointing to the positional arguments, as a convenient shortcut:
[% error.info.0 %] # same as [% error.info.args.0 %]
Exceptions can also be thrown from Perl code that you’ve bound
to template variables, or defined as a plugin or other extension. To
raise an exception, call die( ) passing a
reference to a Template::Exception
object as the argument. This will then be caught by any enclosing
TRY blocks from where the code was
called.
use Template::Exception; ... my $vars = { foo => sub { # ... do something ... die Template::Exception->new('myerr.naughty', 'Bad, bad error'); }, };
Therefore, this template:
[% TRY %] ... [% foo %] ... [% CATCH myerr ; "Error: $error" ; END %]
produces the following output:
Error: myerr.naughty error - Bad, bad error
The info
field can also be a
reference to another object or data structure, if required:
die Template::Exception->new('myerror', { module => 'foo.pl', errors => [ 'bad permissions', 'naughty boy' ], });
Later, it can be used in a template:
[% TRY %] ... [% CATCH myerror %] [% error.info.errors.size or 'no'; error.info.errors.size = = 1 ? ' error' : ' errors' -%] in [% error.info.module %]: [% error.info.errors.join(', ') %]. [% END %]
generating the output:
2 errors in foo.pl: bad permissions, naughty boy.
You can also call die( ) with
a single string, as is common in much existing Perl code. This will
automatically be converted to an exception of the undef type (that’s the literal string
`undef', not the undefined value). If the string isn’t terminated with
a newline, Perl will append the familiar at
$file line $line
message.
sub foo { # ... do something ... die "I'm sorry, Dave, I can't do that\n"; }
If you’re writing a plugin, or some extension code that has the
current Template::Context
in scope
(you can safely skip this section if this means nothing to you), you
can also raise an exception by calling the context throw( ) method. You can pass it a
Template::Exception
object
reference, a pair of ($type, $info)
parameters, or just a $info string
to create an exception of undef
type.
$context->throw($e); # exception object $context->throw('Denied'); # 'undef' type $context->throw('user.passwd', 'Bad Password');
CLEAR
The CLEAR directive can be used to clear the output buffer for the current enclosing block. It is most commonly used to clear the output generated from a TRY block up to the point where the error occurred.
[% TRY %] blah blah blah # this is normally left intact [% THROW some 'error' %] # up to the point of error ... [% CATCH %] [% CLEAR %] # clear the TRY output [% error %] # print error string [% END %]
Flow Control
Flow control is about making unexpected changes to the execution
order of a template. This can be as simple as ending a FOREACH
loop early, or as significant as
ending the entire template processing process. These are generally
exceptional cases, so you probably won’t need to use flow-control
directives that often, but we discuss them here just in case.
RETURN
The RETURN directive can be used to stop processing the current template and return to the template from which it was called, resuming processing at the point immediately after the INCLUDE, PROCESS, or WRAPPER directive. If there is no enclosing template, the Template process( ) method will return to the calling code with a true value.
Before [% INCLUDE half_wit %] After [% BLOCK half_wit %] This is just half... [% RETURN %] ...a complete block [% END %]
The previous example produces the following output:
Before This is just half... After
STOP
The STOP directive can be used to indicate that the processor should stop gracefully without processing any more of the template document. This is a planned stop, and the Template process( ) method will return a true value to the caller. This indicates that the template was processed successfully according to the directives within it.
[% IF something.terrible.happened %] [% INCLUDE fatal/error.html %] [% STOP %] [% END %] [% TRY %] [% USE DBI(mydsn) %] ... [% CATCH DBI.connect %] <p>Cannot connect to the database: [% error.info %]</p> <br> We apologize for the inconvenience. The cleaning lady has removed the server power to plug in her vacuum cleaner. Please try again later. </p> [% INCLUDE footer %] [% STOP %] [% END %]
Debugging
It’s possible that you won’t get everything just right in your templates
the first time you write them. If you have problems working out what
exactly is going on as the Template Toolkit is processing your template,
the DEBUG
directive can help
you.
The DEBUG
directive enables and
disables directive debug messages within a template. It is used with an
on
or off
parameter to enable or disable directive
debugging messages from that point forward. When enabled, the output of
each directive in the generated output will be prefixed by a comment
indicating the file, line, and original directive text.
[% DEBUG on %] directive debugging is on (assuming DEBUG option is set to true) [% DEBUG off %] directive debugging is off
The format parameter can be used to change the format of the debugging message:
[% DEBUG format '<!-- $file line $line : [% $text %] -->' %]
The DEBUG
configuration option
must be set to include DEBUG_DIRS
for
the DEBUG
directives to have any
effect. If DEBUG_DIRS
is not set, the
parser will automatically ignore and remove any DEBUG
directives.
Perl Blocks
The Template Toolkit directives that we have seen up to now together define a presentation language that allows you to do just about anything you need to in order to control the display of your data. This is in keeping with the Template Toolkit philosophy of separating processing from presentation.
However, there may be times when you want to go beyond what
Template Toolkit offers you. Very occasionally you might need the power
of a full programming language within your templates. When nothing else
will do, the Template Toolkit also gives you the option of embedding
Perl directly in your templates in PERL
and RAWPERL
directive blocks.
Using PERL
and RAWPERL
blocks isn’t something that is widely
encouraged because it tends to make templates messy and hard to read. It
also leads to a poor separation of concerns when you mix application
code with presentation templates. However, the Template Toolkit doesn’t
enforce this separation, so you can embed Perl code inside your
templates if you really want to. Because we don’t encourage it, this
feature is disabled by default. You will have to enable the EVAL_PERL
configuration option to embed Perl
code.
PERL
The PERL
directive allows you to embed a block of Perl code in a
template. It looks like this:
[% PERL %] print "Hello world\n" [% END %]
The EVAL_PERL
configuration
option must be enabled in order to use PERL
blocks. If you try to use a PERL
block when EVAL_PERL
is disabled, a perl
exception will be thrown with the
message `EVAL_PERL
not set’:
my $template = Template->new({ EVAL_PERL => 1, });
The Template Toolkit evaluates Perl code in the Template::Perl
package. A number of special
variables are predefined, providing access to various Template Toolkit
objects.
The $context
package variable
contains a reference to the current Template::Context
object. This can be used
to access the functionality of the Template Toolkit to process other
templates, and load plugins, filters, etc.:
[% PERL %] print $context->include('myfile'); [% END %]
The $stash
variable contains
a reference to the top-level stash object, which manages template
variables. Through this, variable values can be retrieved and
updated.
[% PERL %] $stash->set(foo => 'bar'); print "foo value: ", $stash->get('foo'); [% END %]
The previous example generates the following output:
foo value: bar
Output is generated from the PERL
block by calling print
. Before evaluating the code, a
filehandle called Template::Perl::PERLOUT
is set up and
selected as the default output filehandle. This will be connected to
whatever output device was defined in the call to process
. Your code should use this
filehandle instead of STDOUT.
[% PERL %] print "foo\n"; # OK print PERLOUT "bar\n"; # OK, same as above print Template::Perl::PERLOUT "baz\n"; # OK, same as above print STDOUT "qux\n"; # WRONG! [% END %]
The PERL
block may contain
other template directives. These are processed before the Perl code is
evaluated.
[% name = 'Fred Smith' %] [% PERL %] print "[% name %]\n"; [% END %]
Thus, the Perl code in the previous example is evaluated as:
print "Fred Smith\n";
Exceptions may be thrown from within PERL
blocks via die
, and will be correctly caught by
enclosing TRY blocks:
[% TRY %] [% PERL %] die "nothing to live for\n"; [% END %] [% CATCH %] error: [% error.info %] [% END %]
The previous example generates the following output:
error: nothing to live for
RAWPERL
The Template Toolkit parser reads a source template and generates
the text of a Perl subroutine as output. It then uses eval( ) to evaluate it into a subroutine
reference. This subroutine is then called to process the template,
passing a reference to the current Template::Context
object through which the
functionality of the Template Toolkit can be accessed. The subroutine
reference can be cached, allowing the template to be processed
repeatedly without requiring any further parsing.
For example, a template such as:
[% PROCESS header %] The [% animal %] sat on the [% location %] [% PROCESS footer %]
is converted into the following Perl subroutine definition:
sub { my $context = shift; my $stash = $context->stash; my $output = ''; my $error; eval { BLOCK: { $output .= $context->process('header'); $output .= "The "; $output .= $stash->get('animal'); $output .= " sat on the "; $output .= $stash->get('location'); $output .= $context->process('footer'); $output .= "\n"; } }; if ($@) { $error = $context->catch($@, \$output); die $error unless $error->type eq 'return'; } return $output; }
To examine the Perl code generated, such as in the previous
example, set the $Template::Parser::DEBUG
package variable to
any true value. You can also set the $Template::Directive::PRETTY
variable to
true to have the code formatted in a readable manner for human
consumption. The source code for each generated template subroutine
will be printed to STDERR on compilation (i.e., the first time a
template is used).
$Template::Parser::DEBUG = 1; $Template::Directive::PRETTY = 1; ... $tt->process($file, $vars) || die $tt->error( ), "\n";
The PERL
..
. END
construct allows Perl code to be embedded into a template (when the
EVAL_PERL option is set), but it is
evaluated at “runtime” using eval(
) each time the template subroutine is called. This is
inherently flexible but not as efficient as it could be, especially in
a persistent server environment where a template may be processed many
times.
The RAWPERL directive allows you to write Perl code that is integrated directly into the generated Perl subroutine text. It is evaluated once at compile time and is stored in cached form as part of the compiled template subroutine. This makes RAWPERL blocks more efficient than PERL blocks.
The downside is that you must code much closer to the metal.
Within PERL blocks, you can call
print( ) to generate some output.
RAWPERL blocks don’t afford such
luxury. The code is inserted directly into the generated subroutine
text and should conform to the convention of appending to the $output
variable.
[% PROCESS header %] [% RAWPERL %] $output .= "Some output\n"; ... $output .= "Some more output\n"; [% END %]
The critical section of the generated subroutine for this example would then look something like this:
... eval { BLOCK: { $output .= $context->process('header'); $output .= "\n"; $output .= "Some output\n"; ... $output .= "Some more output\n"; $output .= "\n"; } }; ...
As with PERL blocks, the
$context
and $stash
references are predefined and
available for use within RAWPERL
code.
Only very advanced Template Toolkit users will ever need to use a RAWPERL block.
[7] Larry has since changed his mind and it looks as if the
~
will be the Perl 6 string
concat operator. As always, this is all subject to change.
Get Perl Template Toolkit now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.