GT::Template - simple template parsing module
use GT::Template;
my $var = GT::Template->parse('file.txt', { key => 'value' });
...
print $var;
or
use GT::Template;
GT::Template->parse_print('file.txt', { key => 'value' });
GT::Template provides a simple way (one line) to parse a template (which can be either a file or a string) and make sophisticated replacements.
It supports simple replacements, conditionals, function calls, including other templates, and more.
Additionally, through using pre-compiled files, subsequent parses of a template will be very fast.
The template parser replaces tags with content. By default a tag is anything
enclosed between <% and %>. These can be changed by specifying
a value to the begin() and end() methods.
You are <%age%> years old.
where age would be replaced with a value.
<%set Title = 'Login'%>
and now <%Title%> will be equal to Login. This is especially useful for
includes, where you could, for example, set a Title variable to a string
that will be displayed in an included template.
You can also set one variable to the value of another, such as:
<%set title = $return_title%>
This will set the variable ``title'' with the value of the variable ``return_title.''
For example, if the 'age' variable is 15, the following tag:
<%age + 10%>
will display 25 in the template. Besides addition there are the following operators, which work as expected: - * / % (remainder) ^ (raised to the power of)
The following operators are also worth explaining:
i/
/N
~ (Remainder difference)
x (String multiplier)
i/ performs integral division between the two numbers. For example, '4' i/ 3 will result in 1. '100' i/ 3 would result in 33, etc.
/N does not actually use a literal N, instead N should be replaced by a number. The result will be formatted (and rounded) to N decimal places. For example, '4' /3 3 would result in: 1.333, while '5' /3 3 would give you: 1.667. '3' /3 3 would be 1.000.
Note that i/ and /0 are not the same, as can be illustrated here: 38 i/ '3.8' => 12 - becomes 38 i/ 3 38 /0 '3.8' => 10 - 38 / 3.8 is calculated, then rounded with 0 decimal place precision.
You should be sure of which one you mean to use, or you may end up with unexpected results.
~ is used to get a remainder difference. Where 8 % 5 would return 3, 8 ~ 5 will return 2. This is calculated as the divisor (5) minus the remainder (3). This is useful when generating tables in a loop - when you hit the end of the loop, you want to be able to put an empty cell with a colspan of however many rows are left. Something like: <%row_num ~ 5%> will give you the proper value.
As mentioned, there is also one string operator, 'x'. When you use 'x', the variable (or value as we'll see in a second) will be displayed ``n'' times, where ``n'' is the integral value of the right hand side.
Assuming that the 'name' variable is 'Jason', this tag:
<%name x 2%>
will display JasonJason in the parsed template. Like this, it isn't all that
useful because you could simply put <%name%><%name%> in your
template. However, the right hand side may instead use the value of a variable,
such as in this example:
<%name x $print%>
Assuming that 'name' is still 'Jason', and that 'print' is 3, this would display:
JasonJasonJason
Though this is useful as is, this is taken a step furthur: the first does not always have to be a variable. By using 'single quotation marks' or ``double quotation marks'' we can display fixed text a variable number of times.
For example:
<%'My Text' x $print%>
Again assuming that the variable print is 3, this will print:
My TextMy TextMy Text
this comes in handy when doing things like indentation.
Note that what we want to use for ``My Text'' might contain `` or ' characters. If it only contains '', and not ', it is advisible to use ' instead of `` as the string delimiter. If, however, you need to use the same quotes inside the string as you use to delimit the string, you should precede the quotes with a blackslash (\) and any backslashes with a backslash. For example, if you wanted to display the three characters \''' thirty times, you would have to write it as one of the following two lines:
<%"\\'\"" x 30%>
<%'\\\'"' x 30%>
Hopefully such occurances are rare, but not impossible; hence the support for using either ' or `` as the delimiting character.
<%set variable += 3%>
+= can be changed to the following:
+= - Adds to a variable
-= - Subtracts from a variable
*= - Multiplies a variable
/= - Divides a variable
%= - Set a variable to a remainder
^= - Raise a variable to a power
.= - Appends to a string
x= - "Multiplies" a string - "ab" x 3 is "ababab"
if, ifnot (or unless), elseif, and else
as in:
<%if age%>
You are <%age%> years old.
<%elseif sex%>
You are <%sex%>.
<%else%>
I know nothing about you!
<%endif%>
<%ifnot login%>
You are not logged in!
<%endif%>
<%unless age%>
I don't know how old you are!
<%endif%>
If you like you may use elsif instead of elseif (drop the 'e').
unless and endunless are aliases for ifnot and endif, respectively,
and may be used interchangeably.
All conditionals must be ended with an endif tag, although may contain any
number of elseif conditionals and/or a single else conditional between
the if and endif tags.
Conditionals may be nested within each other, to arbitrary depth:
<%if age%>
You are <%age%> years old
<%if sex%>
and you are <%sex%>
<%endif%>
<%endif%>
<, >, <=, >=,
==, !=, lt, gt, le, ge, eq, ne, contains, starts,
and ends. This allows you to do things like:
<%if age == 15%>
You're 15!
<%endif%>
where the == can be replaced with any operator listed above. If the right hand side of the equation starts with a '$', the string will be interpolated as a variable. If you wish to use a string starting with a literal $, you can avoid this interpolation by adding quotes around the right hand value. The left hand side is always a variable.
lt, gt, le, ge, eq, and ne are he alphabetical equivelants of
<, >, <=, >=, ==, and !=, respectively. In
terms of less-than and greater-than comparisons, the comparison is similar to a
dictionary: aa is less than b, but greater than a; 10 is greater
than 1, but less than 2; Z is less than a, due to capitalization
(unless using ilt, ige, etc.). contains will be true if the variable
contains the right-hand side. starts and ends will be true if the
variable starts with, or ends with, respectively, the right-hand value.
There are also case-insensitive versions of the string comparisons - they are:
ilt, igt, ile, ige, ieq, ine, icontains, istarts, and
iends. These comparisons work exactly like the versions _without_ the i
except that the comparison is case-insensitive.
start, istart, end, and iend are aliases for the comparison with an
added s. like and ilike are deprecated aliases for contains and
icontains and should no longer be used.
or and and. For example:
<%if age and sex and color%>
I know your age, sex and hair color.
<%else%>
I don't have enough information about you!
<%endif%>
<%if age < 10 or age > 90 or status eq banned%>
You are not permitted to view this page.
<%endif%>
It should be noted that it is currently not possible to mix both or and
and in a single if statement - you may, however, use the same boolean
multiple times in a single statement. (Brackets) are also not currently
supported.
Internally, if statements will be short-circuited as soon as possible. That means that for the following tag: <%if foo = 1 or foo = 2 or foo = 3%> the following will occur: First, variable ``foo'' will be tested to see if it is numerically equal to 1. If it is, the rest of the checks are aborted since the if will pass regardless. If it is not, foo = 2 will be checked, and if true, will abort the next check, and so on until a condition is true or the end of the list of statements is encountered.
Likewise with and, except that with and the parser will stop checking as
soon as the first false value is encountered (since a false value means the
entire condition will be false).
For example:
<%loop people%>
<%if name eq 'Jason'%>
I have <%color%> hair.
<%else%>
<%name%> has <%color%> hair.
<%endif%>
<%endloop%>
would loop through all values of pens, and for each one would print the sentence substituting the color of the pen. Also, inside your loop you can use the following tags:
<%row_num%> - a counter for what row is being looped, starts at 1.
<%first%> - boolean value that is true if this is the first row, false otherwise.
<%last%> - boolean value that is true if this is the last row, false otherwise.
<%inner%> - boolean value that is true if this is not first and not last.
<%even%> - boolean value is true if row_num is even.
<%odd%> - boolean value is true if row_num is odd.
You could use even and odd tags to produce alternating colors like:
<%loop results%>
<tr><td bgcolor="<%if even%>white<%else%>silver<%endif%>">..</td></tr>
<%endloop%>
Also, you can use <%lastloop%> to abort the loop and skip straight to the current loop's <%endloop%> tag, and <%nextloop%> to load the next loop variables and jump back to the beginning of the current loop.
The 6 built-in variables (row_num, first, last, ...) and any variables set via the loop variable will only be available for the current loop iteration, after which the variables of the next loop iteration will be set, or, for variables that exist in one iteration but not the next, the variables that existed prior to the loop being called will be restored.
<%escape_url somevar%>
<%escape_html somevar%>
<%escape_js somevar%>
<%if info%>
<%include info.txt%>
<%else%>
<%include noinfo.txt%>
<%endif%>
will include either the file info.txt (if info is true) or noinfo.txt (if info is false or not set). It must be in the template's root directory which is defined using $obj->root, or '.' by default.
A useful application of the include tag is to include files inside a loop, as in:
<%loop people%>
<%include person.txt%>
<%endloop%>
Another useful example is in including a common header or footer to all pages.
If, for example, you have a header.htm that you wish to be included, but it
needs a variable title, you could combine the include with a set, such
as:
<%set Title = 'Login'%>
<%include header.htm%>
and then in your header.htm:
<html>
<head>
<title><%Title%>
</title>
</head>
This would allow you to have different titles, but still include the same header template on each page.
A script header normally looks like <%CGI::header%>
which would call &CGI::header(). You can pass arguments to this as in:
A script header normally looks like <%CGI::header ('text/html')%>.
Also, you can pass any currently available template variable to the function using:
<%CGI::header ($variable)%>
Multiple arguments may be passed by comma separating the arguments, as in: <%Mypackage::mysub($age, 'Title')%>
If a function returns a hash reference, those values will be added to the current substitution set. Suppose you have a function:
package Mypackage;
sub load_globals {
..
return { age => 15, color => red };
}
You could then do:
<%Mypackage::load_globals%>
You are <%age%> years old, with <%color%> hair!
Functions are loaded while parsing, so calling the function with different arguments (to set your variables to different values) is possible.
Since package names can make functions rather long and ugly, you can call
->parse() with an ``alias'' key in the options hash. This key should contain
shortcut => function pairs. For example, if you want to call Foo::Bar::blah() in
your template, you could pass: asdf => 'Foo::Bar::blah', and when <%asdf%> or
<%asdf(...)%> is encountered, Foo::Bar::blah will be called.
<%if age == My::years_old%>
You are the same age as me!
<%endif%>
which would call My::years_old() and compare the return value to the value of the ``age'' variable.
<%set age = Mypackage::age%>
Arguments passed are the same as the arguments to a regular function.
The third argument to parse is an optional hash of options. Valid options include:
The forth option to parse is an optional hash of aliases to set up for functions. The key should be the function call to alias and the value should be the function aliased. For example:
print GT::Template->parse(
'file.htm',
{ key => 'value' },
{ compress => 1 },
{ myfunc => 'Long::Package::Name::To::myfunc' }
);
Now in your template you can do:
<%myfunc('argument')%>
Which will call Long::Package::Name::To::myfunc.
Some examples to get you going:
# Parse a string in $template and replace <%key%> with 'value'.
print GT::Template->parse('stringname', { key => 'value' }, { string => $template });
# Compress output of template, print it as it is parsed, not after entirely parsed.
GT::Template->parse_print('file.txt', { key => 'value' }, { compress => 1 });
# Don't display warnings on invalid keys.
print GT::Template->parse('file.txt', { key => 'value' }, { strict => 0 });
# Create a template object using custom settings.
my $obj = new GT::Template({
root => '/path/to/templates',
compress => 0,
strict => 0,
begin => '<!',
end => '!>'
});
my $replace = {
a => 'b',
c => 'd',
e => 'f'
};
$obj->parse_print('file2.txt', $replace);
Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. http://www.gossamer-threads.com/
Revision: $Id: Template.pm,v 2.109 2004/05/05 00:57:47 jagerman Exp $