Template::Alloy(3pm)
โจ Template::Alloy(3pm) โจ
User Contributed Perl Documentation โ bestie, you're in the right place ๐
โจ NAME โจ
Template::Alloy - TT2/3, HT, HTE, Tmpl, and Velocity Engine ๐
๐ SYNOPSIS ๐
okay so here's how you use this thing, bestie. Multiple vibes, same icon behavior. Pick your fighter:
๐ Template::Toolkit style usage ๐
my $t = Template::Alloy->new(
INCLUDE_PATH => ['/path/to/templates'],
);
my $swap = {
key1 => 'val1',
key2 => 'val2',
code => sub { 42 },
hash => {a => 'b'},
};
# print to STDOUT
$t->process('my/template.tt', $swap)
|| die $t->error;
# process into a variable
my $out = '';
$t->process('my/template.tt', $swap, \$out);
### Alloy uses the same syntax and configuration as Template::Toolkit
๐ HTML::Template::Expr style usage ๐
my $t = Template::Alloy->new(
filename => 'my/template.ht',
path => ['/path/to/templates'],
);
my $swap = {
key1 => 'val1',
key2 => 'val2',
code => sub { 42 },
hash => {a => 'b'},
};
$t->param($swap);
# print to STDOUT (errors die)
$t->output(print_to => \*STDOUT);
# process into a variable
my $out = $t->output;
### Alloy can also use the same syntax and configuration as HTML::Template
๐ฆ Text::Tmpl style usage ๐ฆ
my $t = Template::Alloy->new;
my $swap = {
key1 => 'val1',
key2 => 'val2',
code => sub { 42 },
hash => {a => 'b'},
};
$t->set_delimiters('#[', ']#');
$t->set_strip(0);
$t->set_values($swap);
$t->set_dir('/path/to/templates');
my $out = $t->parse_file('my/template.tmpl');
my $str = "Foo #[echo $key1]# Bar";
my $out = $t->parse_string($str);
### Alloy uses the same syntax and configuration as Text::Tmpl
โญ Velocity (VTL) style usage โญ
my $t = Template::Alloy->new;
my $swap = {
key1 => 'val1',
key2 => 'val2',
code => sub { 42 },
hash => {a => 'b'},
};
my $out = $t->merge('my/template.vtl', $swap);
my $str = "#set($foo 1 + 3) ($foo) ($bar) ($!baz)";
my $out = $t->merge(\$str, $swap);
๐ Javascript style usage (requires Template::Alloy::JS) ๐
my $t = Template::Alloy->new;
my $swap = {
key1 => 'val1',
key2 => 'val2',
code => sub { 42 },
hash => {a => 'b'},
};
my $out = '';
$t->process_js('my/template.jstem', $swap, \$out);
my $str = "[% var foo = 1 + 3; write('(' + foo + ') (' + get('key1') + ')'); %]";
my $out = '';
$t->process_js(\$str, $swap, \$out);
๐ DESCRIPTION ๐
"An alloy is a homogeneous mixture of two or more elements" (http://en.wikipedia.org/wiki/Alloy).
Template::Alloy is literally the mixing of features and capabilities from all of the major mini-language based template systems (support for non-mini-language based systems will happen eventually). With Template::Alloy you can use your favorite template interface and syntax and get features from each of the other major template systems. And Template::Alloy is fast โ whether you're using mod_perl, CGI, or running from the commandline. There is even Template::Alloy::JS for getting a little more speed when that is necessary.
Template::Alloy happened by accident (accidentally on purpose). The Template::Alloy (Alloy hereafter) was originally a part of the CGI::Ex suite that performed simple variable interpolation. It used TT2 style variables in TT2 style tags [% foo.bar %]. That was all the original Template::Alloy did. This was fine and dandy for a couple of years. In winter of 2005-2006 Alloy was revamped to add a few features. One thing led to another and soon Alloy provided for most of the features of TT2 as well as some from TT3. Template::Alloy now provides a full-featured implementation of the Template::Toolkit language.
After a move to a new company that was using HTML::Template::Expr and Text::Tmpl templates, support was investigated and interfaces for HTML::Template, HTML::Template::Expr, Text::Tmpl, and Velocity (VTL) were added. All of the various engines offer the same features โ each using a different syntax and interface.
More recently, the Template::Alloy::JS capabilities were introduced to bring Javascript templates to the server side (along with an increase in speed if ran in persistent environments).
Template::Toolkit brought the most to the table. HTML::Template brought the LOOP directive. HTML::Template::Expr brought more vmethods and using vmethods as top level functions. Text::Tmpl brought the COMMENT directive and encouraged speed matching (Text::Tmpl is almost entirely C based and is very fast). The Velocity engine brought AUTO_EVAL and SHOW_UNDEFINED_INTERP.
Most of the standard Template::Toolkit documentation covering directives, variables, configuration, plugins, filters, syntax, and vmethods should apply to Alloy just fine (This pod tries to explain everything - but there is too much). See Template::Alloy::TT for a listing of the differences between Alloy and TT.
Most of the standard HTML::Template and HTML::Template::Expr documentation covering methods, variables, expressions, and syntax will apply to Alloy just fine as well.
Most of the standard Text::Tmpl documentation applies, as does the documentation covering Velocity (VTL).
So should you use Template::Alloy? Well, try it out. It may give you no visible improvement. Or it could. ๐
๐ฅ BACKEND ๐ฅ
Template::Alloy uses a recursive regex based grammar (early versions during the CGI::Ex::Template phase did not). This allows for the embedding of opening and closing tags inside other tags (as in [% a = "[% 1 + 2 %]" ; a|eval %]). The individual methods such as parse_expr and play_expr may be used by external applications to add TT style variable parsing to other applications.
The regex parser returns an AST (abstract syntax tree) of the text, directives, variables, and expressions. All of the different template syntax options compile to the same AST format. The AST is composed only of scalars and arrayrefs and is suitable for sending to JavaScript via JSON or sharing with other languages. The parse_tree method is used for returning this AST.
Once at the AST stage, there are two modes of operation. Alloy can either operate directly on the AST using the Play role, or it can compile the AST to perl code via the Compile role, and then execute the code. To use the perl code route, you must set the COMPILE_PERL flag to 1. If you are running in a cached-in-memory environment such as mod_perl, this is the fastest option. If you are running in a non-cached-in-memory environment, then using the Play role to run the AST is generally faster. The AST method is also more secure as cached AST won't ever eval any "perl" (assuming PERL blocks are disabled - which is the default). ๐
โจ ROLES โจ
okay bestie, here's the tea โ โ Template::Alloy took all its functionality and split it into discrete roles. In Template::Toolkit, that same functionality lives in separate classes. The roles in Template::Alloy just add more methods onto the main class. And when Perl 6 finally arrives? These roles will be translated into true Roles. ๐
The following is a list of roles used by Template::Alloy.
Template::Alloy::Compileโ Compile-to-perl roleTemplate::Alloy::HTEโ HTML::Template::Expr roleTemplate::Alloy::Operatorโ Operator roleTemplate::Alloy::Parseโ Parse-to-AST roleTemplate::Alloy::Playโ Play-AST roleTemplate::Alloy::Streamโ Stream output roleTemplate::Alloy::Tmplโ Text::Tmpl roleTemplate::Alloy::TTโ Template::Toolkit roleTemplate::Alloy::Velocityโ Velocity roleTemplate::Alloy::VMethodโ Virtual methods roleTemplate::Alloy::JSโ Javascript functionality - available separately
Template::Alloy automatically loads the roles when they are needed or requested โ but not sooner (with the exception of the Operator role and the VMethod role which are always needed and always loaded). This is good for a CGI environment. In mod_perl you may want to preload a role to make the most of shared memory. You may do this by passing either the role name or a method supplied by that role. ๐
# import roles necessary for running TT
use Template::Alloy qw(Parse Play Compile TT);
# import roles based on methods
use Template::Alloy qw(parse_tree play_tree compile_tree process);
Note: importing roles by method names does not import them into that namespace โ it is autoloading the role and methods into the Template::Alloy namespace. To help make this more clear you may use the following syntax as well.
# import roles necessary for running TT
use Template::Alloy load => qw(Parse Play Compile TT);
# import roles based on methods
use Template::Alloy load => qw(process parse_tree play_tree compile_tree);
# import roles based on methods
use Template::Alloy
Parse => 1,
Play => 1,
Compile => 1,
TT => 1;
Even with all roles loaded Template::Alloy is still relatively small. You can load all of the roles (except the JS role) by passing "all" to the use statement. โจ
use Template::Alloy 'all';
# or
use Template::Alloy load => 'all';
# or
use Template::Alloy all => 1;
As a final option, Template::Alloy also includes the ability to stand-in for other template modules. It is able to do this because it supports the majority of the interface of the other template systems. You can do this in the following way:
use Template::Alloy qw(Text::Tmpl HTML::Template);
# or
use Template::Alloy load => qw(Text::Tmpl HTML::Template);
# or
use Template::Alloy
'Text::Tmpl' => 1,
'HTML::Template' => 1;
Note that the use statement will die if any of the passed module names are already loaded and not subclasses of Template::Alloy. This will avoid thinking that you are using Template::Alloy when you really aren't. Using the'all'option won't automatically do this โ you must mention the"stood-in"modules by name. ๐
The following modules may be "stood-in" for:
TemplateText::TmplHTML::TemplateHTML::Template::Expr
This feature is intended to make using Template::Alloy with existing code easier. Most cases should work just fine. Almost all syntax will just work (except Alloy may make some things work that were previously broken). However Template::Alloy doesn't support 100% of the interface of any of the template systems. If you are using "features-on-the-edge" then you may need to re-write portions of your code that interact with the template system. ๐ฆ
โจ PUBLIC METHODS โจ
okay bestie this is the big one ๐ the next section is basically the main character of the whole doc โ it lists most of the publicly available methods. a few of the less-commonly-used public ones are hiding further down the page, so don't panic if your fave isn't here yet.
๐ธ new
my $obj = Template::Alloy->new({
INCLUDE_PATH => ['/my/path/to/content', '/my/path/to/content2'],
});
you can pass the arguments as a hash or as a hashref, whichever vibe you're on. either way you get a Template::Alloy object back. ๐ซถ
and here's the chill part: there are currently no errors during Template::Alloy object creation. like, none. zero drama. but heads up โ if you're using the HTML::Template interface, that's different behavior. also the document isn't parsed until you call the output or process methods, so creation is literally just vibes and setup. โจ
๐ฅ process
this is the TT interface for kicking off processing. any errors that stop the template processing get stored, and you can grab them with the ->error method. ๐
my $t = Template::Alloy->new;
$t->process($in, $swap, $out)
|| die $t->error;
process takes three arguments. let's break it down, bestie:
the $in argument
it can be any one of these:
- a string containing the filename of the template to be processed. the filename should be relative to
INCLUDE_PATH(peepINCLUDE_PATH,ABSOLUTE, andRELATIVEconfiguration items). in-memory caching and file-side caching are available for this type ๐ - a reference to a scalar containing the contents of the template to be processed
- a coderef that will be called to return the contents of the template
- an open filehandle that will return the contents of the template when read
the $swap argument
this should be a hashref containing key value pairs that will be available to variables swapped into the template. the values can be hashrefs, hashrefs of hashrefs and so on, arrayrefs, arrayrefs of arrayrefs and so on, coderefs, objects, and simple scalar values such as numbers and strings. ๐ check the section on variables for the full tea.
the $out argument
can be any one of:
undefโ meaning print the completed template toSTDOUT- a string containing a filename. the completed template will be placed in the file
- a reference to a string. the contents will be appended to the scalar reference
- a coderef. the coderef will be called with the contents as a single argument
- an object that can run the method
print. the contents will be passed as a single argument toprint - an arrayref. the contents will be pushed onto the array
- an open filehandle. the contents will be printed to the open handle
bonus round: the $out argument can also be configured using the OUTPUT configuration item. ๐
now, the process method defaults to using the "cet" syntax, which will parse TT3 and most TT2 documents. but if you wanna parse HT or HTE documents, you gotta pass the SYNTAX configuration item to the new method โ then all calls to process would default to HTE syntax.
my $obj = Template::Alloy->new(SYNTAX => 'hte');
๐ process_simple
basically the process method but with some restrictions, bestie. she's on a budget:
- the
$inparameter is limited to a filename or a reference a string containing the contents - the
$outparameter may only be a reference to a scalar string that output will be appended to
plus, these configuration variables get ignored: VARIABLES, PRE_DEFINE, BLOCKS, PRE_PROCESS, PROCESS, POST_PROCESS, AUTO_RESET, OUTPUT. ๐
๐ญ error
if something goes wrong during a process command, you can retrieve the error that occurred via the error method. she's your emotional support diagnostic ๐ซถ
$obj->process('somefile.html', {a => 'b'}, \$string_ref)
|| die $obj->error;
๐ฆ output
this is the HTML::Template way to process a template. the output method requires that a filename, filehandle, scalarref, or arrayref argument was passed to the new method. all of the HT calling conventions for new are supported. the key difference? Alloy will not actually process the template until the output method is called. โญ
my $obj = Template::Alloy->new(filename => 'myfile.html');
$obj->param(\%swap);
print $obj->output;
check the HTML::Template documentation for more info. ๐
output defaults to using the "hte" syntax, which parses HTE and HT documents. to parse TT3 or TT2 documents, you must pass the SYNTAX configuration item to the new method โ then all calls to process would default to TT3 syntax.
my $obj = Template::Alloy->new(SYNTAX => 'tt3');
any errors that occur during the output method will die with the error as the die value. not a vibe, but forewarned is forearmed ๐
๐
param
the HTML::Template way to get or set variable values that will be used by the output method.
my $val = $obj->param('key'); # get one value
$obj->param(key => $val); # set one value
$obj->param(key => $val, key2 => $val2); # set multiple
$obj->param({key => $val, key2 => $val2}); # set multiple
check the HTML::Template documentation for more info. ๐
note: Alloy does not support thedie_on_bad_paramsconfiguration. why? because Alloy doesn't resolve variable names until theoutputmethod is called. so there's nothing to be mad at yet, bestie ๐คทโ๏ธ
๐ define_vmethod
this method is available for defining extra Virtual methods or filters. it's similar to Template::Stash::define_vmethod. slay.
Template::Alloy->define_vmethod(
'text',
reverse => sub { my $item = shift; return scalar reverse $item },
);
โจ register_function
this is the HTML::Template way of defining text vmethods. it's the same as calling define_vmethod with "text" as the first argument. ๐
Template::Alloy->register_function(
reverse => sub { my $item = shift; return scalar reverse $item },
);
๐ฎ define_directive
this method can be used for adding new directives or overriding existing ones. icon behavior fr fr.
Template::Alloy->define_directive(
MYDIR => {
parse_sub => sub {}, # parse additional items in the tag
play_sub => sub {
my ($self, $ref, $node, $out_ref) = @_;
$$out_ref .= "I always say the same thing!";
return;
},
is_block => 1, # is this block like
is_postop => 0, # not a post operative directive
no_interp => 1, # no interpolation in this block
continues => undef, # it doesn't "continue" any other directives
},
);
now with a template like:
my $str = "([% MYDIR %]This is something[% END %])";
Template::Alloy->new->process(\$str);
you will get:
(I always say the same thing!)
we'll add more details in later revisions of this document. stay tuned bestie ๐ซถ
๐ define_syntax
this method can be used for adding another syntax to โ or overriding existing ones in โ the list of choices available in Alloy. the syntax can be chosen by the SYNTAX configuration item.
Template::Alloy->define_syntax(
my_uber_syntax => sub {
my $self = shift;
local $self->{'V2PIPE'} = 0;
local $self->{'V2EQUALS'} = 0;
local $self->{'PRE_CHOMP'} = 0;
local $self->{'POST_CHOMP'} = 0;
local $self->{'NO_INCLUDES'} = 0;
return $self->parse_tree_tt3(@_);
},
);
the subroutine that is used must return an opcode tree (AST) that can be played by the execute_tree method. no AST, no party ๐
๐ define_operator
this method allows for adding new operators or overriding existing ones. go off.
Template::Alloy->define_operator({
type => 'right', # can be one of prefix, postfix, right, left, none, ternary, assign
precedence => 84, # relative precedence for resolving multiple operators without parens
symbols => ['foo', 'FOO'], # any mix of chars can be used for the operators
play_sub => sub {
my ($one, $two) = @_;
return "You've been foo'ed ($one, $two)";
},
});
you can then use it in a template as in the following:
my $str = "[% 'ralph' foo 1 + 2 * 3 %]";
Template::Alloy->new->process(\$str);
you will get:
You've been foo'ed (ralph, 7)
future revisions of this document will include more samples. heads up though: this is an experimental feature and the API will probably change. ๐ง
๐ง dump_parse_tree
this method allows for returning a Data::Dumper dump of a parsed template. it's mainly used for testing. lowkey a debugging girly. ๐
๐ dump_parse_expr
this method allows for returning a Data::Dumper dump of a parsed variable. also mainly used for testing. โจ
๐ import
all of the arguments that can be passed to use โ the ones listed above in the section dealing with ROLES โ can be used with the import method. bestie said "reuse, recycle" ๐
# import by role
Template::Alloy->import(qw(Compile Play Parse TT));
# import by method
Template::Alloy->import(qw(compile_tree play_tree parse_tree process));
# import by "stand-in" class
Template::Alloy->import('Text::Tmpl', 'HTML::Template::Expr');
as mentioned in the ROLE section โ arguments passed to import are not imported into the current namespace. roles and methods are only imported into the Template::Alloy namespace. periodt. ๐
๐ VARIABLES ๐
okay bestie, this whole section is about using variables and expressions in the TT mini-language, and honestly it's not that deep once you catch the vibe โจ
A variable is, like, the simplest little construct you can drop into the TT mini-language. When you write a variable name, it goes looking for the matching value inside Template::Alloy's internal stash of variables โ which is essentially just a hash reference, no cap. That stash gets initially populated either by passing a hashref as the second argument to the process method, or by setting the "VARIABLES" or "PRE_DEFINE" configuration variables. pick your fighter ๐
If you're using either the HT or the HTE syntax, the VAR, IF, UNLESS, LOOP, and INCLUDE directives will accept a NAME attribute โ but it may only be a single level (non-chained) HTML::Template variable name, okay? no chaining, we don't do that here. Or, they may accept an EXPR attribute, which may be any valid TT3 variable or expression. slay. ๐
Here are some sample ways to access variables:
### some sample variables
my %vars = (
one => '1.0',
foo => 'bar',
vname => 'one',
some_code => sub { "You passed me (".join(', ', @_).")" },
some_data => {
a => 'A',
bar => 3234,
c => [3, 1, 4, 1, 5, 9],
vname => 'one',
},
my_list => [20 .. 50],
cet => Template::Alloy->new,
);
### pass the variables into the Alloy process
$cet->process($template_name, \%vars)
|| die $cet->error;
### pass the variables during object creation (will be available to every process call)
my $cet = Template::Alloy->new(VARIABLES => \%vars);
๐ฆ GETTING VARIABLES ๐ฆ
So once you have variables defined, you can just use them directly in the template by using their name in the stash. Or you can use the GET directive. Either way, iconic. ๐
[% foo %]
[% one %]
[% GET foo %]
Would print, when processed:
bar
1.0
bar
To access members of a hashref or an arrayref, you can chain the names together using a .. so cute.
[% some_data.a %]
[% my_list.0] [% my_list.1 %] [% my_list.-1 %]
[% some_data.c.2 %]
Would print:
A
20 21 50
4
If the value of a variable is a code reference, it will be called. You can add a set of parentheses and arguments to pass arguments โ arguments are variables and can be as complex as necessary, bestie, go wild. ๐ธ
[% some_code %]
[% some_code() %]
[% some_code(foo) %]
[% some_code(one, 2, 3) %]
Would print:
You passed me ().
You passed me ().
You passed me (bar).
You passed me (1.0, 2, 3).
If the value of a variable is an object, methods can be called using the . operator. periodt.
[% cet %]
[% cet.dump_parse_expr('1 + 2').replace('\s+', ' ') %]
Would print something like:
Template::Alloy=HASH(0x814dc28)
$VAR1 = [ [ undef, '+', '1', '2' ], 0 ];
Each type of data (string, array and hash) has virtual methods associated with them. Virtual methods let you access functions that are commonly used on those types of data. For the full list of built in virtual methods, please see the section titled VIRTUAL METHODS ๐ซ
[% foo.length %]
[% my_list.size %]
[% some_data.c.join(" | ") %]
Would print:
3
31
3 | 1 | 4 | 5 | 9
It's also possible to "interpolate" variable names using a $. This lets you store the name of a variable inside another variable โ very meta of us, we love her. If a variable name is a little more complex, it can be embedded inside of ${ and }.
[% $vname %]
[% ${vname} %]
[% ${some_data.vname} %]
[% some_data.$foo %]
[% some_data.${foo} %]
Would print:
1.0
1.0
1.0
3234
3234
In Alloy it's also possible to embed any expression (non-directive) in ${ and } and it's possible to use non-integers for array access. (This is not available in TT2) just so we're clear.
[% ['a'..'z'].${ 2.3 } %]
[% {ab => 'AB'}.${ 'a' ~ 'b' } %]
[% color = qw/Red Blue/; FOR [1..4] ; color.${ loop.index % color.size } ; END %]
Would print:
c
AB
RedBlueRedBlue
โจ SETTING VARIABLES. โจ
To define variables during processing, you can use the = operator. In most cases this is the same as using the SET directive.
[% a = 234 %][% a %]
[% SET b = "Hello" %][% b %]
Would print:
234
Hello
It's also possible to create arrayrefs and hashrefs. ๐
[% a = [1, 2, 3] %]
[% b = {key1 => 'val1', 'key2' => 'val2'} %]
[% a.1 %]
[% b.key1 %] [% b.key2 %]
Would print:
2
val1 val2
It's possible to set multiple values in the same SET directive. efficient queen. ๐
[% SET a = 'A'
b = 'B'
c = 'C' %]
[% a %] [% b %] [% c %]
Would print:
A B C
It's also possible to unset variables, or to set members of nested data structures.
[% a = 1 %]
[% SET a %]
[% b.0.c = 37 %]
([% a %])
[% b.0.c %]
Would print
()
37
๐ LITERALS AND CONSTRUCTORS ๐
The following are the types of literals (numbers and strings) and constructors (hash and array constructs) allowed in Alloy. They can be used as arguments to functions, in place of variables in directives, and in place of variables in expressions. And in Alloy it's also possible to call virtual methods on literal values. yeah, we're fancy like that ๐
๐ข Integers and Numbers.
[% 23423 %] Prints an integer.
[% 3.14159 %] Prints a number.
[% pi = 3.14159 %] Sets the value of the variable.
[% 3.13159.length %] Prints 7 (the string length of the number)
Scientific notation is supported.
[% 314159e-5 + 0 %] Prints 3.14159.
[% .0000001.fmt('%.1e') %] Prints 1.0e-07
Hexadecimal input is also supported.
[% 0xff + 0 %] Prints 255
[% 48875.fmt('%x') %] Prints beeb
๐ Single quoted strings.
Returns the string. No variable interpolation happens. (that's literally the whole point, bestie)
[% 'foobar' %] Prints "foobar".
[% '$foo\n' %] Prints "$foo\\n". # the \\n is a literal "\" and an "n"
[% 'That\'s nice' %] Prints "That's nice".
[% str = 'A string' %] Sets the value of str.
[% 'A string'.split %] Splits the string on ' ' and returns the list.
Note: virtual methods can only be used on literal strings in Alloy, not in TT.
You may also embed the current tags in strings (Alloy only).
[% '[% 1 + 2 %]' | eval %] Prints "3"
๐ Double quoted strings.
Returns the string. Variable interpolation happens.
[% "foobar" %] Prints "foobar".
[% "$foo" %] Prints "bar" (assuming the value of foo is bar).
[% "${foo}" %] Prints "bar" (assuming the value of foo is bar).
[% "foobar\n" %] Prints "foobar\n". # the \n is a newline.
[% str = "Hello" %] Sets the value of str.
[% "foo".replace('foo','bar') %] Prints "bar".
Note: virtual methods can only be used on literal strings in Alloy, not in TT.
You may also embed the current tags in strings (Alloy only).
[% "[% 1 + 2 %]" | eval %] Prints "3"
๐ง Array Constructs.
[% [1, 2, 3] %] Prints something like ARRAY(0x8309e90).
[% array1 = [1 .. 3] %] Sets the value of array1.
[% array2 = [foo, 'a', []] %] Sets the value of array2.
[% [4, 5, 6].size %] Prints 3.
[% [7, 8, 9].reverse.0 %] Prints 9.
Note: virtual methods can only be used on array constructs in Alloy, not in TT.
๐ Quoted Array Constructs.
[% qw/1 2 3/ %] Prints something like ARRAY(0x8309e90).
[% array1 = qw{Foo Bar Baz} %] Sets the value of array1.
[% qw[4 5 6].size %] Prints 3.
[% qw(Red Blue).reverse.0 %] Prints Blue.
Note: this works in Alloy and is planned for TT3.
๐ธ Hash Constructs.
[% {foo => 'bar'} %] Prints something like HASH(0x8305880)
[% hash = {foo => 'bar', c => {}} %] Sets the value of hash.
[% {a => 'A', b => 'B'}.size %] Prints 2.
[% {'a' => 'A', 'b' => 'B'}.size %] Prints 2.
[% name = "Tom" %]
[% {Tom => 'You are Tom',
Kay => 'You are Kay'}.$name %] Prints You are Tom
Note: virtual methods can only be used on hash constructs in Alloy, not in TT.
โญ Regex Constructs.
[% /foo/ %] Prints (?-xism:foo)
[% a = /(foo)/i %][% "FOO".match(a).0 %] Prints FOO
Note: this works in Alloy and is planned for TT3.
๐ซถ VIRTUAL METHODS ๐ซถ
Virtual methods (vmethods) are a TT feature that allow for operating on the swapped template variables.
This document shows some samples of using vmethods. For a full listing of available virtual methods, see Template::Alloy::VMethod. go off, king ๐
๐ซ EXPRESSIONS ๐ซ
Expressions are one or more variables or literals joined together with operators. An expression can be used anywhere a variable can be used โ with the exception of the variable name in the SET directive, and the filename of PROCESS, INCLUDE, WRAPPER, and INSERT. (those four said no to expressions, sorry bestie ๐)
For a full listing of operators, see Template::Alloy::Operator.
The following section shows some samples of expressions. For a full list of available operators, please see the section titled OPERATORS.
[% 1 + 2 %] Prints 3
[% 1 + 2 * 3 %] Prints 7
[% (1 + 2) * 3 %] Prints 9
[% x = 2 %] # assignments don't return anything
[% (x = 2) %] Prints 2 # unless they are in parens
[% y = 3 %]
[% x * (y - 1) %] Prints 4
๐ DIRECTIVES ๐
This section contains the alphabetical list of DIRECTIVES available in Alloy. DIRECTIVES are the "functions" and control structures that work in the various mini-languages. For further discussion and examples beyond what's listed below, please refer to the TT directives documentation or to the appropriate documentation for the particular directive.
The examples given in this section are done using the Template::Toolkit syntax, but can be done in any of the various syntax options. See Template::Alloy::TT, Template::Alloy::HTE, Template::Alloy::Tmpl, and Template::Alloy::Velocity.
[% IF 1 %]One[% END %]
[% FOREACH a = [1 .. 3] %]
a = [% a %]
[% END %]
[% SET a = 1 %][% SET a = 2 %][% GET a %]
Okay so real talk โ in TT you can shove multiple directives into the same [% ... %] tag, as long as they're separated by a space or a semicolon (;). (Only the Alloy flavour of Tmpl lets you stack them like that too โ none of the other syntax options do.) And here's the tea: any block directive that could also be a post-operative directive (think IF, WHILE, FOREACH, UNLESS, FILTER, and WRAPPER) has to be separated from whatever came before it with a semicolon when it's being used as a block. Safest move? Just always use the semicolon, bestie. Also fyi, separating by space is an Alloy-only thing but it's a planned TT3 feature. ๐
[% SET a = 1 ; SET a = 2 ; GET a %]
[% SET a = 1
SET a = 2
GET a
%]
[% GET 1
IF 0 # is a post-operative
GET 2 %] # prints 2
[% GET 1;
IF 0 # it is block based
GET 2
END
%] # prints 1
So here's the full directive list, no skips, no crumbs. ๐
BLOCK
Saves a chunk of text under a name so you can pull it back later with PROCESS, INCLUDE, and WRAPPER. Blocks can live anywhere in the template, even after the spot where you use them. Iconic, honestly.
[% BLOCK foo %]Some text[% END %]
[% PROCESS foo %]
Would print
Some text
[% INCLUDE foo %]
[% BLOCK foo %]Some text[% END %]
Would print
Some text
Anonymous BLOCKs? Perfect for capturing. ๐
[% a = BLOCK %]Some text[% END %][% a %]
Would print
Some text
And anonymous BLOCKs can also be used with macros.
BREAK
It's an alias for LAST. Use it to dip out of FOREACH and WHILE loops. ๐ช
CALL
Calls the variable (and any underlying coderefs) exactly like the GET method does โ but it always hands back an empty string. Like, it does the thing, but gives you nothing to show for it. No cap.
CASE
Used together with the SWITCH directive. Go peek at the SWITCH directive. ๐
CATCH
Used together with the TRY directive. Go peek at the TRY directive.
CLEAR
Clears out any content generated so far in the innermost block or template. Super handy when you pair it with the TRY statement โ so if an error pops off later, you can just wipe the stuff that already got generated. ๐งน
COMMENT
Comments out anything sitting between the open and close tags. Heads up though: the stuff in the middle is still parsed and END tags still have to line up โ but the parsed content just gets yeeted. ๐
[% COMMENT %]
This text won't be shown.
[% IF 1 %]And this won't either.[% END %]
[% END %]
CONFIG
Lets you change the value of certain compile-time and runtime configuration options.
[% CONFIG
ANYCASE => 1
PRE_CHOMP => '-'
%]
These compile time configuration options can be set:
ANYCASE
AUTO_EVAL
AUTO_FILTER
CACHE_STR_REFS
ENCODING
INTERPOLATE
POST_CHOMP
PRE_CHOMP
SEMICOLONS
SHOW_UNDEFINED_INTERP
SYNTAX
V1DOLLAR
V2EQUALS
V2PIPE
And these runtime configuration options can be set:
ADD_LOCAL_PATH
CALL_CONTEXT
DUMP
VMETHOD_FUNCTIONS
STRICT (can only be enabled, cannot be disabled)
If you pass non-named parameters, they'll just show you the current configuration:
[% CONFIG ANYCASE, PRE_CHOMP %]
CONFIG ANYCASE = undef
CONFIG PRE_CHOMP = undef
DEBUG
Resets the DEBUG_FORMAT configuration variable, or flips DEBUG statements on and off. Note: this only does anything if the DEBUG_DIRS or DEBUG_ALL flags were handed to the DEBUG configuration variable. โจ
[% DEBUG format '($file) (line $line) ($text)' %]
[% DEBUG on %]
[% DEBUG off %]
DEFAULT
Basically SET's cousin, except it only sets the value if the previous value wasn't defined or was zero-length. So it's the "only if nobody's home" assignment. ๐
[% DEFAULT foo = 'bar' %][% foo %] => 'bar'
[% foo = 'baz' %][% DEFAULT foo = 'bar' %][% foo %] => 'baz'
DUMP
DUMP drops in a Data::Dumper printout of the variable or expression. If you pass it no argument, it dumps the entire contents of the current variable stash (with private keys removed). It also tells you the current file and line number where the DUMP directive got called from. ๐ต๏ธ
Want to customise or control what DUMP shows you? Check the DUMP configuration item.
[% DUMP %] # dumps everything
[% DUMP 1 + 2 %]
ELSE
Used with the IF directive. Go peek at the IF directive.
ELSIF
Used with the IF directive. Go peek at the IF directive.
END
Ends a block directive. The closing credits. ๐ฌ
EVAL
Same thing as the EVALUATE directive.
EVALUATE
Introduced by the Velocity templating language. It parses and processes the contents of whatever you pass it. It's lowkey similar to the eval filter, but Velocity needs an actual directive. You can use named arguments to reconfigure the parser โ literally any of the items you can pass to the CONFIG directive can be passed here too.
[% EVALUATE "[% 1 + 3 %]" %]
[% foo = "bar" %]
[% EVALUATE "<TMPL_VAR foo>" SYNTAX => 'ht' %]
FILTER
Applies different treatments to blocks of text. It can work as a BLOCK directive or as a post operative directive. Alloy supports every filter in Template::Filters. And honestly, the line between scalar virtual methods and filters is blurred (or like, fully nonexistent) in Alloy โ anything that's a scalar virtual method can be used as a FILTER. ๐
TODO - enumerate the at least 7 ways to pass and use filters.
'|'
Alias for the FILTER directive. But careful bestie โ | behaves a lot like the . in Template::Alloy. So in some situations you can't put a pipe directly after a variable name (the pipe will only act on that one variable). That's the TT3 behaviour, periodt. Want the TT2 behaviour for a PIPE? Flip the V2PIPE configuration item.
FINAL
Used with the TRY directive. Go peek at the TRY directive.
FOR
Alias for FOREACH. Short and sweet.
FOREACH
Lets you iterate over the contents of any arrayref. If the variable isn't an arrayref, it just gets automatically promoted into one. ๐
[% FOREACH i IN [1 .. 3] %]
The variable i = [% i %]
[%~ END %]
[% a = [1 .. 3] %]
[% FOREACH j IN a %]
The variable j = [% j %]
[%~ END %]
Would print:
The variable i = 1
The variable i = 2
The variable i = 3
The variable j = 1
The variable j = 2
The variable j = 3
You can also use = instead of IN or in:
[% FOREACH i = [1 .. 3] %]
The variable i = [% i %]
[%~ END %]
Same as before.
Setting into a variable is optional:
[% a = [1 .. 3] %]
[% FOREACH a %] Hi [% END %]
Would print:
hi hi hi
If the thing you're iterating is a hashref and the FOREACH doesn't set into a variable, then the values of the hashref get copied into the variable stash. ๐ซถ
[% FOREACH [{a => 1}, {a => 2}] %]
Key a = [% a %]
[%~ END %]
Would print:
Key a = 1
Key a = 2
The FOREACH process uses the Template::Alloy::Iterator class to handle iterations (it's compatible with Template::Iterator). During the FOREACH loop, an object blessed into the iterator class is stored in the variable loop.
The loop variable gives you all of this during a FOREACH:
index - the current index
max - the max index of the list
size - the number of items in the list
count - index + 1
number - index + 1
first - true if on the first item
last - true if on the last item
next - return the next item in the list
prev - return the previous item in the list
odd - return 1 if the current count is odd, 0 otherwise
even - return 1 if the current count is even, 0 otherwise
parity - return "odd" if the current count is odd, "even" otherwise
So this:
[% FOREACH [1 .. 3] %] [% loop.count %]/[% loop.size %] [% END %]
Would print:
1/3 2/3 3/3
The iterator is also available via a plugin. That's what lets you reach multiple loop variables inside a nested FOREACH directive. ๐คฏ
[%~ USE outer_loop = Iterator(["a", "b"]) %]
[%~ FOREACH i = outer_loop %]
[%~ FOREACH j = ["X", "Y"] %]
[% outer_loop.count %]-[% loop.count %] = ([% i %] and [% j %])
[%~ END %]
[%~ END %]
Would print:
1-1 = (a and X)
1-2 = (a and Y)
2-1 = (b and X)
2-2 = (b and Y)
FOREACH can also be used as a post operative directive. โจ
[% "$i" FOREACH i = [1 .. 5] %] => 12345
GET
Returns the value of a variable or expression.
[% GET a %]
The GET keyword can be omitted entirely:
[% a %]
[% 7 + 2 - 3 %] => 6
Go check the section on VARIABLES.
IF (IF / ELSIF / ELSE)
Does conditional testing. It expects an expression as its only argument. If the expression is true, the contents of its block get processed. If it's false, the processor goes hunting for an ELSIF block โ and if an ELSIF's expression is true, that one gets processed. Finally it looks for an ELSE block, which gets processed if none of the IF or ELSIF expressions were true. ๐
[% IF a == b %]A equaled B[% END %]
[% IF a == b -%]
A equaled B
[%- ELSIF a == c -%]
A equaled C
[%- ELSE -%]
Couldn't determine that A equaled anything.
[%- END %]
IF can also be used as a post operative directive:
[% 'A equaled B' IF a == b %]
Note: If you're working with HTML::Template style documents, theTMPL_IFtag parses using the limited HTML::Template parsing rules. But you can useEXPR=""to embed a TT3 style expression. ๐
INCLUDE
Parses the contents of a file or block and inserts them. Any variables defined, or modifications made to existing variables, get discarded after a template is included. So it's a little self-contained moment โ what happens in the include stays in the include. โจ
[% INCLUDE path/to/template.html %]
[% INCLUDE "path/to/template.html" %]
[% file = "path/to/template.html" %]
[% INCLUDE $file %]
[% BLOCK foo %]This is foo[% END %]
[% INCLUDE foo %]
And bestie, you can hand it args too, like it's ordering for you:
[% INCLUDE "path/to/template.html" a = "An arg" b = "Another arg" %]
Filenames must be relative to INCLUDE_PATH unless the ABSOLUTE or RELATIVE configuration items are set. (yes, that's a real rule, don't come for me)
Want a whole lil lineup of files? Pass multiple filenames separated by a plus, a space, or commas โ and heads up, TT2 doesn't support the comma. Any arguments you supply get used on all the templates, no cap:
[% INCLUDE "path/to/template.html",
"path/to/template2.html" a = "An arg" b = "Another arg" %]
โ ๏ธ On Perl 5.6 on some platforms there may be some issues with the variable localization. There is no problem on 5.8 and greater. (5.6 girlies we love u but pls upgrade ๐)
INSERT
Drop in the contents of a file without template parsing. It's giving "just show me the raw text, don't touch it" energy. โจ
Filenames must be relative to INCLUDE_PATH unless the ABSOLUTE or RELATIVE configuration items are set.
Multiple filenames can be passed by separating them with a plus, a space, or commas (TT2 doesn't support the comma).
[% INSERT "path/to/template.html",
"path/to/template2.html" %]
JS
Only available if the COMPILE_JS configuration item is true (default is false). This requires the Template::Alloy::JS module to be installed. (so likeโฆ install it first, bestie ๐ซถ)
Allow eval'ing the block of text as javascript. The block gets parsed and then eval'ed. ๐ง
[% a = "BimBam" %]
[%~ JS %]
write('The variable a was "' + get('a') + '"');
set('b', "FooBar");
[% END %]
[% b %]
Would print:
The variable a was "BimBam"
FooBar
LAST
Used to exit out of a WHILE or FOREACH loop. Say bye ๐ and dip out of the loop entirely.
LOOP
Okay so this one operates similar to the HTML::Template loop directive. The LOOP directive expects a single variable name, and that variable name should point to an arrayref of hashrefs. The keys of each hashref get added to the variable stash when it's iterated. ๐ฆ
[% var a = [{b => 1}, {b => 2}, {b => 3}] %]
[% LOOP a %] ([% b %]) [% END %]
Would print:
(1) (2) (3)
If Alloy is in HT mode and GLOBAL_VARS is false, the contents of the hashref will be the only items available during the loop iteration.
If LOOP_CONTEXT_VARS is true, and $QR_PRIVATE is false (default when called through the output method), then the variables __first__, __last__, __inner__, __odd__, and __counter__ will be set. See the HTML::Template loop_context_vars configuration item for more information. โจ
MACRO
Takes a directive and turns it into a variable that can take arguments. It's like teaching your template a lil trick ๐
[% MACRO foo(i, j) BLOCK %]You passed me [% i %] and [% j %].[% END %]
[%~ foo("a", "b") %]
[% foo(1, 2) %]
Would print:
You passed me a and b.
You passed me 1 and 2.
Another example:
[% MACRO bar(max) FOREACH i = [1 .. max] %]([% i %])[% END %]
[%~ bar(4) %]
Would print:
(1)(2)(3)(4)
Starting with version 1.012 of Template::Alloy there is also a macro operator. ๐ธ
[% foo = ->(i,j){ "You passed me $i and $j" } %]
[% bar = ->(max){ FOREACH i = [1 .. max]; i ; END } %]
See the Template::Alloy::Operator documentation for more examples.
META
Used to define variables that will be available via either the template or component namespace.
Once defined, they cannot be overwritten. ๐ซ (like, it's locked in fr)
[% template.foobar %]
[%~ META foobar = 'baz' %]
[%~ META foobar = 'bing' %]
Would print:
baz
NEXT
Used to go to the next iteration of a WHILE or FOREACH loop. Not a full exit โ just skipping ahead to the next round. ๐
PERL
Only available if the EVAL_PERL configuration item is true (default is false).
Allow eval'ing the block of text as perl. The block gets parsed and then eval'ed. ๐ช
[% a = "BimBam" %]
[%~ PERL %]
my $a = "[% a %]";
print "The variable \$a was \"$a\"";
$stash->set('b', "FooBar");
[% END %]
[% b %]
Would print:
The variable $a was "BimBam"
FooBar
During execution, anything printed to STDOUT will be inserted into the template. Also, the $stash and $context variables are set and are references to objects that mimic the interface provided by Template::Context and Template::Stash. These are provided for compatibility only. $self contains the current Template::Alloy object. โจ
PROCESS
Parse the contents of a file or block and insert them. Unlike INCLUDE, no variable localization happens โ so variables defined, or modifications made to existing variables, remain after the template is processed. It's giving permanent-marker energy ๐๏ธ
[% PROCESS path/to/template.html %]
[% PROCESS "path/to/template.html" %]
[% file = "path/to/template.html" %]
[% PROCESS $file %]
[% BLOCK foo %]This is foo[% END %]
[% PROCESS foo %]
Arguments may also be passed to the template:
[% PROCESS "path/to/template.html" a = "An arg" b = "Another arg" %]
Filenames must be relative to INCLUDE_PATH unless the ABSOLUTE or RELATIVE configuration items are set.
Multiple filenames can be passed by separating them with a plus, a space, or commas (TT2 doesn't support the comma). Any supplied arguments will be used on all templates.
[% PROCESS "path/to/template.html",
"path/to/template2.html" a = "An arg" b = "Another arg" %]
RAWPERL
Only available if the EVAL_PERL configuration item is true (default is false). Similar to the PERL directive, but you'll need to append to the $output variable rather than just calling PRINT. ๐ซถ
RETURN
Used to exit the innermost block or template and continue processing in the surrounding block or template.
There are two changes from TT2 behavior. First, in Alloy, a RETURN during a MACRO call will only exit the MACRO. Second, the RETURN directive takes an optional variable name or expression โ if passed, the MACRO will return this value instead of the normal text from the MACRO. The process_simple method will also return this value. ๐
You can also use the item, list, and hash return vmethods. ๐
[% RETURN %] # just exits
[% RETURN "foo" %] # return value is foo
[% "foo".return %] # same thing
SET
Used to set variables. Periodt. ๐
[% SET a = 1 %][% a %] => "1"
[% a = 1 %][% a %] => "1"
[% b = 1 %][% SET a = b %][% a %] => "1"
[% a = 1 %][% SET a %][% a %] => ""
[% SET a = [1, 2, 3] %][% a.1 %] => "2"
[% SET a = {b => 'c'} %][% a.b %] => "c"
STOP
Used to exit the entire process method โ out of all blocks and templates. No content will be processed beyond this point. ๐ It's the ultimate "I'm done here" bestie.
SWITCH
Allow for SWITCH and CASE functionality. โจ
[% a = "hi" %]
[% b = "bar" %]
[% SWITCH a %]
[% CASE "foo" %]a was foo
[% CASE b %]a was bar
[% CASE ["hi", "hello"] %]You said hi or hello
[% CASE DEFAULT %]I don't know what you said
[% END %]
Would print:
You said hi or hello
TAGS
Change the type of enclosing braces used to delineate template tags. This remains in effect until the end of the enclosing block or template, or until the next TAGS directive. Either a named set of tags must be supplied, or two tags themselves must be supplied. ๐
[% TAGS html %]
[% TAGS <!-- --> %]
The named tags are (duplicated from TT):
asp => ['<%', '%>' ], # ASP
default => ['\[%', '%\]' ], # default
html => ['<!--', '-->' ], # HTML comments
mason => ['<%', '>' ], # HTML::Mason
metatext => ['%%', '%%' ], # Text::MetaText
php => ['<\?', '\?>' ], # PHP
star => ['\[\*', '\*\]' ], # TT alternate
template => ['\[%', '%\]' ], # Normal Template Toolkit
template1 => ['[\[%]%', '%[%\]]'], # allow TT1 style
tt2 => ['\[%', '%\]' ], # TT2
If custom tags are supplied, by default they are escaped using quotemeta. You may also pass explicitly quoted strings, or regular expressions as arguments as well โ if your regex begins with a ', ", or / you must quote it.
[% TAGS [<] [>] %] matches "[<] tag [>]"
[% TAGS '[<]' '[>]' %] matches "[<] tag [>]"
[% TAGS "[<]" "[>]" %] matches "[<] tag [>]"
[% TAGS /[<]/ /[>]/ %] matches "< tag >"
[% TAGS ** ** %] matches "** tag **"
[% TAGS /**/ /**/ %] Throws an exception.
โ ๏ธ You should be sure that the start tag does not include grouping parens or INTERPOLATE will not function properly. fr fr, no grouping parens ๐
THROW
Allows for throwing an exception. If the exception is not caught via the TRY DIRECTIVE, the template will abort processing of the directive. ๐ญ
[% THROW mytypes.sometime 'Something happened' arg1 => val1 %]
See the TRY directive for examples of usage.
TRY
The TRY block directive will catch exceptions that are thrown while processing its block. (It cannot catch parse errors unless they are in included files or evaltt'ed strings.) The TRY block will then look for a CATCH block that will be processed. While it is being processed, the "error" variable will be set with the thrown exception as the value. After the TRY block โ the FINAL block will be ran whether or not an error was thrown (unless a CATCH block throws an error). ๐ฆ
Note: Parse errors cannot be caught unless they are in anevalFILTER, or are in a separate template beingINCLUDEd orPROCESSed.
[% TRY %]
Nothing bad happened.
[% CATCH %]
Caught the error.
[% FINAL %]
This section runs no matter what happens.
[% END %]
Would print:
Nothing bad happened.
This section runs no matter what happens.
Another example:
[% TRY %]
[% THROW "Something happened" %]
[% CATCH %]
Error: [% error %]
Error.type: [% error.type %]
Error.info: [% error.info %]
[% FINAL %]
This section runs no matter what happens.
[% END %]
And that spits out:
Error: undef error - Something happened
Error.type: undef
Error.info: Something happened
This section runs no matter what happens.
Bestie. You can also hand your error a type and a whole extra pile of info, named arguments included. That stuff straight-up replaces the info property of the exception. ๐
[% TRY %]
[% THROW foo.bar "Something happened" "grrrr" foo => 'bar' %]
[% CATCH %]
Error: [% error %]
Error.type: [% error.type %]
Error.info: [% error.info %]
Error.info.0: [% error.info.0 %]
Error.info.1: [% error.info.1 %]
Error.info.args.0: [% error.info.args.0 %]
Error.info.foo: [% error.info.foo %]
[% END %]
Which prints something along the lines of:
Error: foo.bar error - HASH(0x82a395c)
Error.type: foo.bar
Error.info: HASH(0x82a395c)
Error.info.0: Something happened
Error.info.1: grrrr
Error.info.args.0: Something happened
Error.info.foo: bar
Also also also โ you can give the CATCH block a type to catch, and you can nest TRY blocks like it's nothing. When types are specified, Alloy goes hunting for the closest matching type. And an error object can be re-thrown using $error as the argument to THROW. ๐ฅ
[% TRY %]
[% TRY %]
[% THROW foo.bar "Something happened" %]
[% CATCH bar %]
Caught bar.
[% CATCH DEFAULT %]
Caught default - but re-threw.
[% THROW $error %]
[% END %]
[% CATCH foo %]
Caught foo.
[% CATCH foo.bar %]
Caught foo.bar.
[% CATCH %]
Caught anything else.
[% END %]
Which prints:
Caught default - but re-threw.
Caught foo.bar.
๐ UNLESS ๐
Literally the same as IF but the condition is negated. The vibes are flipped, the logic is not.
[% UNLESS 0 %]hi[% END %] => hi
It can also show up as a post operative directive, because of course it can. โจ
๐ธ USE ๐ธ
This is how you load a Template::Toolkit style plugin, bestie.
[% USE iter = Iterator(['foo', 'bar']) %]
[%~ iter.get_first %]
[% iter.size %]
Which prints:
foo
2
Heads up: you can totally send arguments to the new object constructor. You can also skip naming the variable you're assigning โ in that case, the name of the plugin becomes the variable. ๐ซถ
[% USE Iterator(['foo', 'bar', 'baz']) %]
[%~ Iterator.get_first %]
[% Iterator.size %]
Which prints:
foo
3
Plugins that get loaded are looked up in the namespace listed in the PLUGIN_BASE directive, which defaults to Template::Plugin. So in that last example, if Template::Toolkit were installed, the iter object would be loaded by the class Template::Plugin::Iterator. In Alloy, an effective way to disable plugins is to set the PLUGIN_BASE to a non-existent base such as "_" (over in TT it will still fall back to looking in Template::Plugin).
Note: the iterator plugin will fall back and use Template::Alloy::Iterator if Template::Toolkit is not installed. No other plugins come installed with Template::Alloy.
The names of the Plugin being loaded from PLUGIN_BASE are case insensitive. That said, using case insensitive names is bad, because it requires scanning the @INC directories for any module matching the PLUGIN_BASE and caching the result (OK โ not that bad).
If the plugin isn't found and the LOAD_PERL directive is set, then Alloy will try and load a module by that name (note: this type of lookup is case sensitive and will not scan the @INC dirs for a matching file).
# The LOAD_PERL directive should be set to 1
[% USE ta = Template::Alloy %]
[%~ ta.dump_parse_expr('2 * 3') %]
Which prints:
[[undef, '*', 2, 3], 0];
See the PLUGIN_BASE, and PLUGINS configuration items.
See the documentation for Template::Manual::Plugins.
๐ฆ VIEW ๐ฆ
Implements a TT style view. For more info, go read the Template::View documentation โ this DIRECTIVE will correctly parse the arguments and then pass them along to a freshly created Template::View object. It will fail if Template::View can't be found. ๐ญ
โญ WHILE โญ
Processes a block of code while a condition is true. Classic.
[% WHILE i < 3 %]
[%~ i = i + 1 %]
i = [% i %]
[%~ END %]
Which prints:
i = 1
i = 2
i = 3
You could also do:
[% i = 4 %]
[% WHILE (i = i - 1) %]
i = [% i %]
[%~ END %]
Which prints:
i = 3
i = 2
i = 1
Okay so real talk: (f = f - 1) is a valid expression that returns the value of the assignment. The parentheses are not optional, bestie. Do not come for me. ๐
WHILE has a built in limit of 1000 iterations. That's controlled by the global variable $WHILE_MAX in Template::Alloy.
WHILE may also be used as a post operative directive.
[% "$i" WHILE (i = i + 1) < 7 %] => 123456
๐ WRAPPER ๐
Block directive, icon behavior. It processes the contents of its block and then passes them in the [% content %] variable to the block or filename listed in the WRAPPER tag.
[% WRAPPER foo b = 23 %]
My content to be processed ([% b %]).[% a = 2 %]
[% END %]
[% BLOCK foo %]
A header ([% a %]).
[% content %]
A footer ([% a %]).
[% END %]
This would print.
A header (2).
My content to be processed (23).
A footer (2).
The WRAPPER directive may also be used as a post operative directive.
[% BLOCK baz %]([% content %])[% END -%]
[% "foobar" WRAPPER baz %]
Would print
(foobar)');
(yep, that stray '); is literally what the docs say it prints, iykyk ๐)
Multiple filenames can be passed by separating them with a plus, a space, or commas (TT2 doesn't support the comma). Any supplied arguments will be used on all templates. Wrappers are processed in reverse order, so that the first wrapper listed will surround each subsequent wrapper listed. Variables from inner wrappers are available to the next wrapper that surrounds it. ๐
[% WRAPPER "path/to/outer.html",
"path/to/inner.html" a = "An arg" b = "Another arg" %]
๐ DIRECTIVES (HTML::Template Style) ๐
HTML::Template templates use directives that look similar to the following:
<TMPL_VAR NAME="foo">
<TMPL_IF NAME="bar">
BAR
</TMPL_IF>
The normal set of HTML::Template directives are TMPL_VAR, TMPL_IF, TMPL_ELSE, TMPL_UNLESS, TMPL_INCLUDE, and TMPL_LOOP. These tags should have either a NAME attribute, an EXPR attribute, or a bare variable name that is used to specify the value to be operated on. If a NAME is specified, it may only be a single level value (as opposed to a TT chained variable). In the case of the TMPL_INCLUDE directive, the NAME is the file to be included.
In Alloy, the EXPR attribute can be used with any of these types to specify a TT compatible variable or expression that will be used for the value. โจ
<TMPL_VAR NAME="foo"> Prints the value contained in foo
<TMPL_VAR foo> Prints the value contained in foo
<TMPL_VAR EXPR="foo"> Prints the value contained in foo
<TMPL_VAR NAME="foo.bar.baz"> Prints the value contained in {'foo.bar.baz'}
<TMPL_VAR EXPR="foo.bar.baz"> Prints the value contained in {foo}->{bar}->{baz}
<TMPL_IF foo> Prints FOO if foo is true
FOO
</TMPL_IF
<TMPL_UNLESS foo> Prints FOO unless foo is true
FOO
</TMPL_UNLESS
<TMPL_INCLUDE NAME="foo.ht"> Includes the template in "foo.ht"
<TMPL_LOOP foo> Iterates on the arrayref foo
<TMPL_VAR name>
</TMPL_LOOP>
And here's the slay part: Template::Alloy makes all of the other TT3 directives available in addition to the normal set of HTML::Template directives. So for example, the following is valid in Alloy.
<TMPL_MACRO bar(n) BLOCK>You said <TMPL_VAR n></TMPL_MACRO>
<TMPL_GET bar("hello")>
The TMPL_VAR tag may also include an optional ESCAPE attribute. This specifies how the value of the tag should be escaped prior to substituting into the template. ๐
Escape value | Type of escape
---------------------------------
HTML, 1 | HTML encoding
URL | URL encoding
JS | basic javascript encoding (\n, \r, and \")
NONE, 0 | No encoding (default).
The TMPL_VAR tag may also include an optional DEFAULT attribute that contains a string that will be used if the variable returns false. ๐
<TMPL_VAR foo DEFAULT="Foo was false">
โจ CHOMPING โจ
ok so chomping is literally just the drama around the whitespace sitting right before and right after your template tags ๐ by default, nothing happens to it โ it just sits there being extra. but bestie you can drop modifiers just inside the opening tag and just before the closing tag to tell it what to do.
also you can set the PRE_CHOMP and POST_CHOMP config variables, and those will globally boss around all the chomping behavior for any tags that didn't bring their own chomp modifier. and PRE_CHOMP / POST_CHOMP can be set to any of these values, no cap:
none: 0 + Template::Constants::CHOMP_NONE
one: 1 - Template::Constants::CHOMP_ONE
collapse: 2 = Template::Constants::CHOMP_COLLAPSE
greedy: 3 ~ Template::Constants::CHOMP_GREEDY
CHOMP_NONE
does absolutely nothing, zero chomping, we respect the whitespace here. the + sign is what tells it CHOMP_NONE ๐ธ
Hello.
[%+ "Hi." +%]
Howdy.
would print:
Hello.
Hi.
Howdy.
CHOMP_ONE (formerly known as CHOMP_ALL)
deletes any whitespace up to the adjacent newline. the - is what signals CHOMP_ONE โจ
Hello.
[%- "Hi." -%]
Howdy.
would print:
Hello.
Hi.
Howdy.
CHOMP_COLLAPSE
collapses adjacent whitespace down to a single space. the = is the CHOMP_COLLAPSE signal ๐
Hello.
[%= "Hi." =%]
Howdy.
would print:
Hello. Hi. Howdy.
CHOMP_GREEDY
removes ALL the adjacent whitespace, greedy little thing. the ~ is the CHOMP_GREEDY signal ๐
Hello.
[%~ "Hi." ~%]
Howdy.
would print:
Hello.Hi.Howdy.
๐ CONFIGURATION ๐
here's every config variable we support, listed alphabetically (iykyk, the organization is a love language). note: if you want to go deeper, the TT config documentation has further discussion for you ๐ซถ
items can be passed in upper OR lower case โ if you pass lower case names they get resolved to uppercase during the new method, cute right?
all of the variables in this section can be passed to the new constructor:
my $obj = Template::Alloy->new(
VARIABLES => \%hash_of_variables,
AUTO_RESET => 0,
TRIM => 1,
POST_CHOMP => "=",
PRE_CHOMP => "-",
);
ABSOLUTE
Boolean. default false. it controls whether absolute paths are allowed for included files ๐
ADD_LOCAL_PATH
if true, it allows calls to include_filename to temporarily add the directory of the current template being processed to the INCLUDE_PATHS arrayref. this lets templates refer to files in the local template directory without you having to spell out the local directory as part of the filename. default is 0. if you set it to a negative value, the current directory gets added to the <em>end</em> of the current INCLUDE_PATHS.
this property can also be set inside the template using the CONFIG directive:
[% CONFIG ADD_LOCAL_PATH => 1 %]
ANYCASE
allows directive matching to be case insensitive ๐ฆ
[% get 23 %] prints 23 with ANYCASE => 1
AUTO_RESET
Boolean. default 1. it clears blocks that were set during the process method ๐งน
AUTO_EVAL
Boolean. default 0 (default 1 in Velocity syntax). if set to true, double quoted strings automatically get passed to the eval filter. this config option can also be passed to the CONFIG directive ๐
AUTO_FILTER
can be the name of any filter. default undef. any variable returned by a GET directive (including implicit GET) gets passed to the named filter. this config option can also be passed to the CONFIG directive ๐ธ
# with AUTO_FILTER => 'html'
[% f = "&"; GET f %] prints &
[% f = "&"; f %] prints & (implicit GET)
if a variable already has another filter applied, the AUTO_FILTER is not applied. the none scalar virtual method was added so you can use variables without reapplying filters:
# with AUTO_FILTER => 'html'
[% f = "&"; f | none %] prints &
[% f = "&"; g = f; g %] prints &
[% f = "&"; g = f; g | none %] prints & (because g = f is a SET directive)
[% f = "&"; g = GET f; g | none %] prints & (because the actual GET directive was called)
BLOCKS
only available when using the process interface ๐
a hashref of blocks that can be used by the process method:
BLOCKS => {
block_1 => sub { ... }, # coderef that returns a block
block_2 => 'A String', # simple string
},
heads up bestie: a Template::Document cannot be supplied as a value (TT supports this, we don't). however, it IS possible to supply a value that is equal to the hashref returned by the load_template method ๐
CACHE_SIZE
number of compiled templates to keep in memory. default undef. undefined means allow <em>all</em> templates to cache. a value of 0 forces no caching at all. the cache mechanism will clear templates that haven't been used recently ๐๏ธ
CACHE_STR_REFS
default 1. if set, any string refs get an MD5 sum taken, which is then used for caching the document โ both in memory and on the file system (if configured). this gives a significant speed boost ๐ฅ note that this also affects strings passed to the EVALUATE directive or eval filters. it can be set using the CONFIG directive.
CALL_CONTEXT (Not in TT)
can be one of 'item', 'list', or 'smart'. the default type is 'smart'. the CALL_CONTEXT configuration specifies in what Perl context coderefs and methods used in the processed templates will be called. TT historically avoided the distinction of item (scalar) vs list context. to avoid worrying about this, TT introduced 'smart' context. the @() and $() context specifiers make it easier to use CALL_CONTEXT in some situations.
the following table shows the relationship between the various contexts:
return values smart context list context item context
------------- ------------- ------------ ------------
A 'foo' 'foo' ['foo'] 'foo'
B undef undef [undef] undef
C (no return value) undef [] undef
D (7) 7 [7] 7
E (7,8,9) [7,8,9] [7,8,9] 9
F @a = (7) 7 [7] 1
G @a = (7,8,9) [7,8,9] [7,8,9] 3
H ({b=>"c"}) {b=>"c"} [{b=>"c"}] {b=>"c"}
I ([1]) [1] [[1]] [1]
J ([1],[2]) [[1],[2]] [[1],[2]] [2]
K [7,8,9] [7,8,9] [[7,8,9]] [7,8,9]
L (undef, "foo") die "foo" [undef, "foo"] "foo"
M wantarray?1:0 1 [1] 0
cases F, H, I and M are the common sticking points of the smart context in TT2 ๐ญ note that list context always returns an arrayref from a method or function call. smart context can give confusing results sometimes, especially the I and J cases. case L for smart match is very surprising ๐
the list and item context provide another feature for method calls. in smart context, TT will look for a hash key in the object by the same name as the method, if a method by that name doesn't exist. in item and list context, Alloy will die if a method by that name cannot be found.
the CALL_CONTEXT configuration item can be passed to new, or it can also be set during runtime using the CONFIG directive. the following method call would be in list context:
[% CONFIG CALL_CONTEXT => 'list';
results = my_obj.get_results;
CONFIG CALL_CONTEXT => 'smart'
%]
note that we needed to restore CALL_CONTEXT to the default 'smart' value. Template::Alloy has added the @() (list) and the $() (item) context specifiers. the previous example could be written as:
[% results = @( my_obj.get_results ) %]
to call that same method in item (scalar) context you'd do the following:
[% results = $( my_obj.get_results ) %]
the @() and $() operators are based on the Perl 6 counterpart โญ
COMPILE_DIR
base directory to store compiled templates. default undef. compiled templates only get stored if one of COMPILE_DIR and COMPILE_EXT is set ๐
if set, the AST of parsed documents will be cached. if COMPILE_PERL is set, the compiled perl code will also be stored.
COMPILE_EXT
extension to add to stored compiled template filenames. default undef.
if set, the AST of parsed documents will be cached. if COMPILE_PERL is set, the compiled perl code will also be stored.
COMPILE_JS
default false.
requires installation of Template::Alloy::JS. when enabled, the parsed templates get translated into Javascript and executed using the V8 javascript engine. if compile_dir is also set, this compiled javascript will be cached to disk ๐ฆ
if your templates are short, there's little benefit to using this, other than you can then use the JS directive. if your templates are long, or you're running in a cached environment, this will speed up your templates.
certain limitations exist when COMPILE_JS is set, most notably the USE and VIEW directives are not supported, and method calls on objects passed to the template do not work (code refs passed in DO work however). these limitations are due to the nature of JavaScript::V8 bind and Perl/JavaScript OO differences ๐
COMPILE_PERL
default false.
if set to 1 or 2, will translate the normal AST into a perl 5 code document. this document can then be executed directly, cached in memory, or cached on the file system, depending on the configuration items set ๐
if set to 1, a perl code document will <em>always</em> be generated.
if set to 2, a perl code document will only be generated if an AST has already been cached for the document. this should give a speed benefit and avoid extra compilation unless the document has been used more than once ๐ฅ
Okay so if Alloy is hanging out in a cached environment like mod_perl, then using compile_perl can hand you a lil speed treat and it makes Alloy faster than Text::Tmpl and as fast as HTML::Template::Compiled (except bestie, Alloy has more features ๐
).
But if you're not in a cached environment โ like, say, running from the commandline or from CGI โ it's generally faster to only run from the AST (with COMPILE_PERL => 0). iykyk
โจ CONSTANTS โจ
Hashref, bestie. It's how you define variables that get "folded" into the compiled template. And the ones you define here? They cannot be overridden. Iconic, honestly. ๐
CONSTANTS => {my_constant => 42},
So a template containing this:
[% constants.my_constant %]
โฆwill have the value 42 compiled straight in. Periodt.
Constants defined this way can also be chained, like [% constant.foo.bar.baz %]. Slay.
๐ธ CONSTANT_NAMESPACE ๐ธ
Lets you set the top level of the values you pass in CONSTANTS. Default value is 'constants'.
๐ DEBUG ๐
Takes a list of constants |'ed together that enable different debugging modes. Or you can use the lowercase names instead (multiple values joined by a ",").
The only supported TT values are:
DEBUG_UNDEF (2) - debug when an undefined value is used (now easier to use STRICT)
DEBUG_DIRS (8) - debug when a directive is used.
DEBUG_ALL (2047) - turn on all debugging.
Either of these turns on undef and directive debugging:
DEBUG => 'undef, dirs', # preferred
DEBUG => 2 | 8,
DEBUG => DEBUG_UNDEF | DEBUG_DIRS, # constants from Template::Constants
๐ DEBUG_FORMAT ๐
Changes the format of the messages that get inserted when DEBUG has DEBUG_DIRS switched on. This is essentially the same thing as setting the format with the DEBUG directive. Lowkey the same vibe, different entrance. โจ
๐ฆ DEFAULT ๐ฆ
The name of a default template file to use if the one you passed in isn't found. A lil safety net, fr fr.
๐ DELIMITER ๐
The string used to split INCLUDE_PATH with. Default is :. But honestly bestie, it's more straightforward to just hand INCLUDE_PATH an arrayref of paths. Do that instead. ๐
๐ DUMP ๐
Configures the behavior of the DUMP tag. Can be set to 0, a hashref, or another true value. Default is true.
- If you set it to
0, allDUMPdirectives do absolutely nothing. Super useful if you wanna turn off theDUMPdirectives in certain environments. ๐ - If you set it to a true value (or leave it undefined), then
DUMPdirectives will operate. - If you set it to a hashref, the values of that hash configure how the
DUMPdirectives behave. Here's everything you can set in that hash:
EntireStash โ Default 1. If you set it to 0, then the DUMP directive will not print the entire contents of the stash when a DUMP directive is called without arguments.
handler โ Defaults to an internal coderef. If you set it to a coderef, the DUMP directive passes the arguments to be dumped and expects back a string with the dumped data. This gives you complete control over the whole dump process. ๐ซถ
Note 1: The default handler makes sure that values matching the private variable regex are not included. If you install your own handler, you'll need to take care of these variables yourself if you want them to not be shown. Note 2: If you'd like the name of the variable to be dumped, include the string'$VAR1'and theDUMPdirective will interpolate the value. For example, to dump all output as YAML, you could do the following:
DUMP => {
handler => sub {
require YAML;
return "\$VAR1 =\n".YAML::Dump(shift);
},
}
header โ Default 1. Controls whether a header gets printed for each DUMP directive. The header contains the file and line number the DUMP directive was called from. If you set it to 0, the headers are disabled.
html โ Defaults to 1 if $ENV{'REQUEST_METHOD'} is set โ 0 otherwise. If set to 1, then the output of the DUMP directive gets passed to the html filter and encased in "pre" tags. If set to 0, no html encoding takes place.
Sortkeys, Useqq, Ident, Pad, etc โ Any of the Data::Dumper configuration items may be passed. Go off. ๐ฅ
๐ ENCODING ๐
Default undef. If you set it โ and if the Perl version is greater than or equal to 5.7.3 (that's when Encode.pm was first included) โ then Encode::decode gets called every single time a template file is processed, and it'll be passed the value of ENCODING plus the text from the template.
You can also set this item with [% CONFIG ENCODING => encoding %] before calling INCLUDE or PROCESS directives, so you can change encodings on the fly. โจ
๐ END_TAG ๐
Set a string to use as the closing delimiter for TT. Default is "%]".
๐ ERROR ๐
Used as a fall back when the processing of a template fails. It can either be a single filename that gets used in all cases, or a hashref of options where the keynames represent error types that get handled by the filename in their value. A key named default is used if no other matching keyname can be found. The selection process is similar to that of the TRY/CATCH/THROW directives (go peek at those directives for more info, bestie).
my $t = Template::Alloy->new({
ERROR => 'general/catch_all_errors.html',
});
my $t = Template::Alloy->new({
ERROR => {
default => 'general/catch_all_errors.html',
foo => 'catch_all_general_foo_errors.html',
'foo.bar' => 'catch_foo_bar_errors.html',
},
});
Heads up though: theERRORhandler will only be used for errors during the processing of the main document. It will not catch errors that happen in templates found in thePRE_PROCESS,POST_PROCESS, andWRAPPERconfiguration items. So don't come for it when it misses those. ๐ญ
๐ ERRORS ๐
Same as the ERROR configuration item. Both can be used interchangeably, no cap.
๐ง EVAL_PERL ๐ง
Boolean. Default false. If you set it to a true value, PERL and RAWPERL blocks will be allowed to run.
โ ๏ธ This is a potential security hole, because arbitrary perl can be included in the template. Do not play with this unless you know exactly what you're doing, bestie. ๐
If Template::Toolkit is installed, a true EVAL_PERL value also allows the perl and evalperl filters to be used.
๐ FILTERS ๐
Lets you pass in TT style filters. Obsessed.
my $filters = {
filter1 => sub { my $str = shift; $s =~ s/./1/gs; $s },
filter2 => [sub { my $str = shift; $s =~ s/./2/gs; $s }, 0],
filter3 => [sub { my ($context, @args) = @_; return sub { my $s = shift; $s =~ s/./3/gs; $s } }, 1],
};
my $str = q{
[% a = "Hello" %]
1 ([% a | filter1 %])
2 ([% a | filter2 %])
3 ([% a | filter3 %])
};
my $obj = Template::Alloy->new(FILTERS => $filters);
$obj->process(\$str) || die $obj->error;
Would print:
1 (11111)
2 (22222)
3 (33333)
Filters passed in as an arrayref should contain a coderef and a value indicating if they're dynamic or static (true meaning dynamic). The dynamic filters get passed the pseudo context object and any arguments, and should return a coderef that'll be called as the filter. That filter coderef then gets passed the string. That's the whole loop, periodt. โจ
๐ธ GLOBAL_CACHE ๐ธ
Default 0. If true, documents get cached in $Template::Alloy::GLOBAL_CACHE. It can also be passed a hashref, in which case the documents get cached in that passed hashref instead.
The TT, Tmpl, and velocity interfaces automatically cache documents in the object. The HTML::Template interface uses a new object each time. Setting the HTML::Template's CACHE configuration is the same as setting GLOBAL_CACHE. Same energy, different name. ๐
๐ฆ INCLUDE_PATH ๐ฆ
A string or an arrayref or coderef that returns an arrayref containing directories to look for files included by processed templates. Defaults to "." (the current directory).
โญ INCLUDE_PATHS โญ
Non-TT item. Same as INCLUDE_PATH but only takes an arrayref. If it's not specified, then INCLUDE_PATH gets turned into an arrayref and stored in INCLUDE_PATHS. Overrides INCLUDE_PATH. ๐
๐ INTERPOLATE ๐
Boolean. Specifies whether variables in text portions of the template get interpolated. So like, $variable and ${var.value} would get substituted with the appropriate values from the variable cache (if INTERPOLATE is on).
[% IF 1 %]The variable $variable had a value ${var.value}[% END %]
๐ LOAD_PERL ๐
Indicates if the USE directive can fall back and try to load a perl module if the indicated module wasn't found in the PLUGIN_BASE path. Go see the USE directive. This configuration has no bearing on the COMPILE_PERL directive that's used to indicate using compiled perl documents. Two different things, don't mix them up. ๐
๐ MAX_EVAL_RECURSE (Alloy only) ๐
Will use $Template::Alloy::MAX_EVAL_RECURSE if not present. Default is 50. It prevents runaway on the following:
[% f = "[% f|eval %]" %][% f|eval %]
๐ฅ MAX_MACRO_RECURSE (Alloy only) ๐ฅ
Will use $Template::Alloy::MAX_MACRO_RECURSE if not present. Default is 50. It prevents runaway on the following:
[% MACRO f BLOCK %][% f %][% END %][% f %]
๐ NAMESPACE ๐
No Template::Namespace::Constants support. Hashref of hashrefs representing constants that get folded into the template at compile time.
Template::Alloy->new(NAMESPACE => {constants => {
foo => 'bar',
}});
Is the same as:
Template::Alloy->new(CONSTANTS => {
foo => 'bar',
});
Any number of hashes can be added to the NAMESPACE hash. Stack 'em up. ๐ซถ
๐ NEGATIVE_STAT_TTL (Not in TT) ๐
Defaults to STAT_TTL, which defaults to $STAT_TTL, which defaults to 1.
Similar to STAT_TTL โ but this one represents the time-to-live seconds until a document that was not found gets checked again against the system for modifications. Setting this number higher allows for fewer file system accesses. Setting it to a negative number allows for the file system to be checked on every hit. Every. Single. One. ๐ญ
๐ง NO_INCLUDES ๐ง
Default false. If true, calls to INCLUDE, PROCESS, WRAPPER and INSERT will fail. This option is also available when using the process method. Nope, not today bestie. ๐
โจ OUTPUT โจ
Another way to tell Template::Alloy where the finished template should go. If process doesn't get handed an output argument, bestie, it goes looking right here instead. ๐
Wanna see the full list of possible values? Peep the process method, it's got you. ๐ซถ
๐ธ OUTPUT_PATH ๐ธ
The base path for any files that get written out โ either via the process method, or through the redirect and file filters. ๐
More deets live in the redirect virtual method and the process method. Go look, iykyk. โจ
๐ PLUGINS ๐
A hashref of mappings from plugin names to plugin modules. Obsessed with a tidy lookup table tbh.
PLUGINS => {
Iterator => 'Template::Plugin::Iterator',
DBI => 'MyDBI',
},
See the USE directive for more info. ๐
๐ฆ PLUGIN_BASE ๐ฆ
Default value is Template::Plugin. This is the base module namespace where template plugins get looked for. ๐
See the USE directive for more info. It can be either a single namespace, or an arrayref of namespaces. No cap. ๐
โ๏ธ POST_CHOMP โ๏ธ
Sets the type of chomping at the ending of a tag. The chomping section has the whole story. ๐
๐ POST_PROCESS ๐
Only available when you're using the process interface. Just so you know. ๐
A list of templates to be processed and appended to the content after the main template. While this processing happens, the "template" namespace will contain the name of the main file being processed. ๐
This is the move for adding a global footer to all your templates. Footer girlies, this one's for you. ๐ฆ
โ๏ธ PRE_CHOMP โ๏ธ
Sets the type of chomping at the beginning of a tag. Again, chomping section, go read it. ๐
๐ PRE_DEFINE ๐
Same thing as the VARIABLES configuration item. Literally the same. Periodt. โจ
๐ PRE_PROCESS ๐
Only available when you're using the process interface. ๐ซถ
A list of templates to be processed before and pre-pended to the content before the main template. During this processing the "template" namespace will contain the name of the main file being processed. ๐ธ
Perfect for adding a global header to all your templates. Iconic behaviour, honestly. ๐
๐ฅ PROCESS ๐ฅ
Only available when you're using the process interface. ๐
Specify a file to use as the template instead of the one that got passed in to the ->process method. Sneaky little swap, love that for you. ๐
๐ RECURSION ๐
Boolean. Default false. Says that INCLUDEd or PROCESSed files are allowed to refer to each other in a circular way. ๐
Be careful about recursion. Like, genuinely. Be careful. ๐ญ
๐งญ RELATIVE ๐งญ
Boolean. Default false. If it's true, you can specify filenames that are relative to the currently running process. ๐
๐ SEMICOLONS ๐
Boolean. Default false. If true, the syntax will require that semi-colons separate multiple directives inside the same tag. ๐
Two reasons this slays: it keeps the syntax a lil cleaner, and it helps you troubleshoot certain errors. โจ
๐ SHOW_UNDEFINED_INTERP (Not in TT) ๐
Default false (default true in Velocity). If INTERPOLATE is true, interpolated dollar variables that return undef get removed. With SHOW_UNDEFINED_INTERP set, undef values will leave the variable right there. ๐
[% CONFIG INTERPOLATE => 1 %]
[% SET foo = 1 %][% SET bar %]
($foo)($bar) ($!foo)($!bar)
Would print:
(1)() (1)()
But the following:
[% CONFIG INTERPOLATE => 1, SHOW_UNDEFINED_INTERP => 1 %]
[% SET foo = 1 %][% SET bar %]
($foo)($bar) ($!foo)($!bar)
Would print:
(1)($bar) (1)()
Note that you can use an exclamation point directly after the dollar to make the variable silent. That's similar to how Velocity works. ๐
โญ START_TAG โญ
Set a string or regular expression to use as the opening delimiter for TT. Default is "[%". ๐
You should be sure that the tag does not include grouping parens, or INTERPOLATE will not function properly. Fr fr, watch out. ๐ญ
๐งบ STASH ๐งบ
Template::Alloy manages its own stash of variables, okay? You can pass a Template::Stash or Template::Stash::XS object, but Template::Alloy will copy all of the values out of that object into its own stash. ๐
Template::Alloy won't use any of the methods of the passed STASH object. None of them. Not one. The STASH option is only available when using the process method. ๐
โฑ๏ธ STAT_TTL โฑ๏ธ
Defaults to $STAT_TTL, which defaults to 1. Represents time-to-live seconds until a cached in-memory document is compared to the file system for modifications. ๐ฆ
Bump this number higher and you get fewer file system accesses. Set it to a negative number and the file system gets checked every single hit. Choose your fighter. ๐
๐ STREAM ๐
Defaults to false. If set to true, generated template content gets printed to the currently selected filehandle (default is STDOUT) as soon as it is ready โ there will be no buffering of the output. Zero. None. Straight out the door. ๐จ
The Stream role uses the Play role's directives (non-compiled_perl). ๐
All directives and configuration work, except for the following exceptions:
CLEARdirective โ because the output isn't buffered, theCLEARdirective would have no effect. TheCLEARdirective will throw an error whenSTREAMis on. ๐TRIMconfiguration โ because the output isn't buffered, trim operations cannot be played on the output buffers. ๐ญWRAPPERconfiguration/directive โ theWRAPPERconfiguration and directive items effectively turn offSTREAM, since the WRAPPERS are generated in reverse order and because the content is inserted into the middle of the WRAPPERS. WRAPPERS will still work, they just won't stream. ๐- VARIOUS errors โ because the template is streaming, items that cause errors may result in partially printed pages, since the error would occur part way through the print. ๐
All output is printed directly to the currently selected filehandle (defaults to STDOUT) via the CORE::print function. Any output parameter passed to process or process_simple will be ignored. ๐
If you would like the output to go to another handle, you will need to select that handle, process the template, and re-select STDOUT. That's the whole ritual. ๐ฏ๏ธ
๐จ STRICT ๐จ
Defaults to false. If set to true, any undefined variable that is encountered will cause the processing of the template to abort. This can be caught with a TRY block. ๐ซถ
This is useful for making sure that the template only attempts to use variables that were correctly initialized โ similar in spirit to Perl's use strict. ๐
When this occurs the strict_throw method is called. See the STRICT_THROW configuration for additional options. Similar functionality could be implemented using UNDEFINED_ANY. ๐
The STRICT configuration item can be passed to new or it may also be set during runtime using the CONFIG directive. Once set though, it cannot be disabled for the duration of the current template and sub components. For example, you could call [% CONFIG STRICT => 1 %] in header.tt and strict mode would be enabled for header.tt and any sub templates processed by header.tt. No take-backsies. ๐
๐ฏ STRICT_THROW (not in TT) ๐ฏ
Default undef. Can be set to a subroutine which will be called when STRICT is set and an undefined variable is processed. It will be passed the error type, error message, and a hashref of template information containing the current component being processed, the current outer template being processed, the identity reference for the variable, and the stringified name of the identity. ๐ง
This override can be used for filtering allowable elements. Very "let me decide who gets to slide through" of you. ๐
my $ta = Template::Alloy->new({
STRICT => 1,
STRICT_THROW => sub {
my ($ta, $err_type, $msg, $args) = @_;
return if $args->{'component'} eq 'header.tt'
&& $args->{'template'} eq 'main.html'
&& $args->{'name'} eq 'foo.bar(1)'; # stringified identity name
$ta->throw($err_type, $msg); # all other undefined variables die
},
});
๐ SYNTAX (not in TT) ๐
Defaults to "cet". Indicates the syntax that will be used for parsing included templates or eval'ed strings. You can use the CONFIG directive to change the SYNTAX on the fly (it will not affect the syntax of the document currently being parsed). ๐
The syntax may be passed in upper or lower case. Either one, she doesn't care. ๐
The available choices are:
alloyโ Template::Alloy style - the same as TT3tt3โ Template::Toolkit ver3 - same as Alloytt2โ Template::Toolkit ver2 - almost the same as TT3tt1โ Template::Toolkit ver1 - almost the same as TT2htโ HTML::Template - same as HTML::Template::Expr withoutEXPRhteโ HTML::Template::Exprjsโ JavaScript style - requirescompile_jsto be set.jsrโ JavaScript Raw style - requirescompile_jsto be set.
Passing in a different syntax allows for the process method to use a non-TT syntax, and for the output method to use a non-HT syntax. ๐ค
The following is a sample of HTML::Template interface usage parsing a Template::Toolkit style document. ๐
my $obj = Template::Alloy->new(filename => 'my/template.tt'
syntax => 'cet');
$obj->param(\%swap);
print $obj->output;
The following is a sample of Template::Toolkit interface usage parsing a HTML::Template::Expr style document. ๐ธ
my $obj = Template::Alloy->new(SYNTAX => 'hte');
$obj->process('my/template.ht', \%swap);
You can use the define_syntax method to add another custom syntax to the list of available options. Go off, make your own. โจ
๐ท๏ธ TAG_STYLE ๐ท๏ธ
Lets you set the type of tag delimiters to use for parsing the TT. See the TAGS directive for a listing of the available types. ๐
๐งผ TRIM ๐งผ
Removes leading and trailing whitespace from blocks and templates. This operation is performed after all enclosed template tags have been executed. Order matters, bestie. ๐
โ UNDEFINED_ANY โ
This is not a TT configuration option. Just so we're clear. ๐จ
This option expects to be a code ref that will be called if a variable is undefined during a call to play_expr. It is passed the variable identity array as a single argument. This is most similar to the "undefined" method of Template::Stash. It allows for the "auto-defining" of a variable for use in the template. ๐
It is suggested that UNDEFINED_GET be used instead, as UNDEFINED_ANY is a little too general in defining variables. Lowkey chaotic. ๐
You can also sub class the module and override the undefined_any method. That's another route. ๐ฃ๏ธ
UNDEFINED_GET ๐
Okay so plot twist โ this one is not a TT config option. It's expecting a code ref, and that code ref gets called whenever a variable is undefined during a call to GET. It's handed the variable identity array as a single argument. It's way more useful than UNDEFINED_ANY because it only fires during a GET directive, not in embedded expressions (like [% a || b || c %]). Big difference, bestie. ๐
You can also just subclass the module and override the undefined_get method if that's more your vibe.
V1DOLLAR ๐ฆ
This gives you a lil compatibility moment with TT1 templates. The one real behavior change is that [% $foo %] becomes the same as [% foo %]. Here's the whole breakdown of what changes when you turn V1DOLLAR on:
With V1DOLLAR Equivalent Without V1DOLLAR (Normal default)
"[% foo %]" "[% foo %]"
"[% $foo %]" "[% foo %]"
"[% ${foo} %]" "[% ${foo} %]"
"[% foo.$bar %]" "[% foo.bar %]"
"[% ${foo.bar} %]" "[% ${foo.bar} %]"
"[% ${foo.$bar} %]" "[% ${foo.bar} %]"
"Text: $foo" "Text: $foo"
"Text: ${foo}" "Text: ${foo}"
"Text: ${$foo}" "Text: ${foo}"
V2EQUALS โจ
Defaults to 1 in the TT syntax, and defaults to 0 in the HTML::Template syntax. ๐
If you set it to 1 then == is an alias for eq and != is an alias for ne.
[% CONFIG V2EQUALS => 1 %][% ('7' == '7.0') || 0 %]
[% CONFIG V2EQUALS => 0 %][% ('7' == '7.0') || 0 %]
Prints
0
1
V2PIPE ๐
This one restores the pipe operator's behavior so it's compatible with TT2. Periodt.
With V2PIPE = 1:
[%- BLOCK a %]b is [% b %]
[% END %]
[%- PROCESS a b => 237 | repeat(2) %]
# output of block "a" with b set to 237 is passed to the repeat(2) filter
b is 237
b is 237
With V2PIPE = 0 (the default):
[%- BLOCK a %]b is [% b %]
[% END %]
[% PROCESS a b => 237 | repeat(2) %]
# b set to 237 repeated twice, and b passed to block "a"
b is 237237
VARIABLES ๐
A hashref of variables used to initialize the template stash. These variables are available for use in any of the executed templates. Head over to the VARIABLES section to see the kinds of info you can pass in.
VMETHOD_FUNCTIONS ๐
Defaults to 1. Every scalar virtual method is also available as a top level function. This is not true of TT2, so it's giving Alloy-exclusive. In Template::Alloy these two are literally equivalent:
[% "abc".length %]
[% length("abc") %]
Set VMETHOD_FUNCTIONS to 0 if you wanna turn that behavior off.
WRAPPER ๐ธ
Only available when you're using the process interface, iykyk.
Works similar to the WRAPPER directive. You can give this option a single filename, or an arrayref of filenames that'll be used to wrap the processed content. If you pass an arrayref, the filenames get processed in reverse order โ so the first filename you listed ends up on the outside, surrounding all the other wrappers.
my $t = Template::Alloy->new(
WRAPPER => ['my/wrappers/outer.html', 'my/wrappers/inner.html'],
);
Content generated by PRE_PROCESS and POST_PROCESS comes before and after (respectively) the content generated by the WRAPPER configuration item.
Wanna see more? Check the WRAPPER directive for extra examples of how wrappers are constructed. ๐ซถ
โจ CONFIGURATION (HTML::Template STYLE) โจ
These HTML::Template and HTML::Template::Expr configuration variables are all supported (listed in HTML::Template documentation order). Heads up: for more discussion you can peek at the HT documentation. A lot of the variables mentioned back in the TT CONFIGURATION section apply here too. Unless it says otherwise, these items only apply when you're using the output method.
Items can be passed in upper or lower case โ everything gets resolved to upper case anyway. ๐
These variables should be passed to the new constructor:
my $obj = Template::Alloy->new(
type => 'filename',
source => 'my/template.ht',
die_on_bad_params => 1,
loop_context_vars => 1,
global_vars => 1
post_chomp => "=",
pre_chomp => "-",
);
TYPE ๐ฆ
Can be one of filename, filehandle, arrayref, or scalarref. Tells Alloy what kind of input is sitting in the source configuration item.
SOURCE โญ
Stores where to read the input file from. The type is specified over in the type configuration item.
FILENAME ๐
Indicates a filename to read the template from. Same thing as putting the filename in the source item and setting type to filename.
Must be set to enable caching. ๐ฅ
FILEHANDLE ๐
Should hold an open filehandle to read the template from. Same as putting the filehandle in the source item and setting type to filehandle.
Will not be cached.
ARRAYREF ๐
Should hold an arrayref whose values are the lines of the template. Same as putting the arrayref in the source item and setting type to arrayref.
Will not be cached.
SCALARREF ๐ง
Should hold a reference to a scalar that contains the template. Same as putting the scalar ref in the source item and setting type to scalarref.
Will not be cached.
CACHE ๐
If set to one, Alloy uses a global, in-memory document cache to store compiled templates in between calls. This is generally only useful in a mod_perl environment. The document gets checked for a different modification time on each request.
BLIND_CACHE ๐
Same as having cache enabled, except it won't check whether the document has been modified. Living dangerously, bestie.
FILE_CACHE ๐ธ
If set to 1, it'll cache the compiled document on the file system. If it's true, file_cache_dir must be set.
FILE_CACHE_DIR ๐
The directory where cached documents get stored when file_cache is true. This is similar to the TT compile_dir option.
DOUBLE_FILE_CACHE ๐
Uses a combination of file_cache and cache.
PATH ๐ฆ
Same as INCLUDE_PATH when you're using the process method.
ASSOCIATE โจ
May be a single CGI object or an arrayref of objects. The params from these objects get added to the params during the output call.
CASE_SENSITIVE ๐
Allows passed variables set through the param method, or the associate configuration, to be used case sensitively. Default is off. It is highly suggested that you set this to 1.
LOOP_CONTEXT_VARS ๐ฅ
Default false. When true, calls to the loop directive create the following variables that give you info about the current iteration of the loop:
__first__ - True on first iteration only
__last__ - True on last iteration only
__inner__ - True on any iteration that isn't first or last
__odd__ - True on odd iterations
__counter__ - The iteration count
These variables are also available to LOOPs run under TT syntax if loop_context_vars is set and if QR_PRIVATE is set to 0. (Yes, the period in the original heading is intentional, no cap.)
GLOBAL_VARS. ๐
Default true in HTE mode. Default false in HT. Allows top level variables to be used in LOOPs. When false, only variables defined in the current LOOP iteration hashref will be available.
DEFAULT_ESCAPE ๐
Controls the type of escape used on named variables in TMPL_VAR directives. Can be one of HTML, URL, or JS. The values of TMPL_VAR directives get encoded with this type unless they specify their own type via an ESCAPE attribute.
You can alternately use the AUTO_FILTER directive, which can be any of the item vmethod filters (you must use lower case when specifying the AUTO_FILTER directive). The AUTO_FILTER directive will also be applied to TMPL_VAR EXPR and TMPL_GET items, while DEFAULT_ESCAPE only applies to TMPL_VAR NAME items.
NO_TT ๐ง
Default false in 'hte' syntax. Default true in 'ht' syntax. If true, no extended TT directives will be allowed.
The output method uses 'hte' syntax by default. ๐
๐ SEMI PUBLIC METHODS ๐
Okay bestie, so this next lil list is the semi-public zone โ these are other interesting methods of Alloy that may be re-implemented by subclasses of Alloy. Not like, top-secret secret, but also not the front-door public API. Respect the vibe, yeah? ๐ซถ
exception
Creates an exception object blessed into the package listed in Template::Alloy::Exception. Cute lil error baby, born and raised in the right package. โจ
execute_tree
Executes a parsed tree (returned from parse_tree). You got the tree, now you run it. Go off. ๐ณ
play_expr
Play the parsed expression. Turns a variable identity array into the parsed variable. This method is also responsible for playing operators and running virtual methods and filters. The variable identity array may also contain literal values, or operator identity arrays. So like, it's doing a LOT, and it's doing it flawlessly. Main character energy fr. ๐
include_filename
Takes a file path, and resolves it into the full filename using paths from INCLUDE_PATH or INCLUDE_PATHS. Finder-of-files behavior. ๐ฆ
_insert
Resolves the file passed, and then returns its contents. Yeah, the leading underscore is giving "internal, don't touch" but it's here in the list anyway. ๐
list_filters
Dynamically loads the filters list from Template::Filters when a filter is used that does not have a native implementation in Alloy. Backup filters, arriving right on cue. ๐
load_template
Given a filename or a string reference will return a document hashref hash that contains the parsed tree.
my $doc = $self->load_template($file); # errors die
This method handles the in-memory caching of the document. So it remembers stuff for you. Iconic behavior honestly. โจ
load_tree
Given the document hashref, will either load the parsed AST from file (if configured to do so), or will load the content, parse the content using the Parse role, and will return the tree. File based caching of the parsed AST happens here. Caching in two places, we love a resourceful queen. ๐ธ
load_perl
Only used if COMPILE_PERL is true (default is false).
Given the document hashref, will either load the compiled perl from file (if configured to do so), or will load the AST using load_tree, will compile a new perl code document using the Compile role, and will return the perl code. File based caching of the compiled perl happens here. Compile, cache, serve. Periodt. ๐
parse_tree
Parses the passed string ref with the appropriate template syntax.
See Template::Alloy::Parse for more details.
parse_expr
Parses the passed string ref for a variable or expression.
See Template::Alloy::Parse for more details.
parse_args
See Template::Alloy::Parse for more details. That's it, that's the description, no notes. ๐ญ
set_variable
Used to set a variable. Expects a variable identity array and the value to set. It will autovifiy as necessary. (Yes, the spelling is autovifiy โ we keep it exactly, no correcting the queen. ๐)
strict_throw
Called during processing of template when STRICT configuration is set and an uninitialized variable is met. Arguments are the variable identity reference. Will call STRICT_THROW configuration item if set, otherwise will call throw with a useful message. Strict mode is strict, bestie, that's the whole point. โ ๏ธ
throw
Creates an exception object from the arguments and dies. Dramatic exit, as designed. ๐
undefined_any
Called during play_expr if a value is returned that is undefined. This could be used to magically create variables on the fly. This is similar to Template::Stash::undefined. It is suggested that undefined_get be used instead. Default behavior returns undef. You may also pass a coderef via the UNDEFINED_ANY configuration variable. Also, you can try using the DEBUG => 'undef', configuration option which will throw an error on undefined variables. Lots of options, pick your fighter. โจ
undefined_get
Called when a variable is undefined during a GET directive. This is useful to see if a value that is about to get inserted into the text is undefined. undefined_any is a little too general for most cases. Also, you may pass a coderef via the UNDEFINED_GET configuration variable. More specific than undefined_any, and honestly? She's the recommended one. ๐ซถ
๐ง OTHER UTILITY METHODS ๐ง
The following is a brief list of other methods used by Alloy. Generally, these shouldn't be overwritten by subclasses. Like, hands off, these are doing their job, don't mess. ๐
ast_stringโ Returns perl code representation of a variable.contextโ Used to create apseudocontext object that allows for portability of TT plugins, filters, and perl blocks that need a context object. Uses theTemplate::Alloy::Contextclass. Fake context, real functionality. ๐debug_nodeโ Used to get debug info on a directive ifDEBUG_DIRSis set.get_line_number_by_indexโ Used to turn string index position into line number.interpolate_nodeโ Used for parsing text nodes for dollar variables when interpolate is on. ๐ตplay_operatorโ Provided by the Operator role. Allows for playing an operator AST.
See Template::Alloy::Operator for more details.
apply_precedenceโ Provided by the Parse role. Allows for parsed operator array to be translated to a tree based upon operator precedence._processโ Called by process and thePROCESS,INCLUDEand other directives.slurpโ Reads contents of passed filename - throws file exception on error. Slurp it up, bestie. ๐split_pathsโ Used to splitINCLUDE_PATHor other directives if an arrayref is not passed.tt_var_stringโ Returns a template toolkit representation of a variable._varsโ Return a reference to the current stash of variables. This is currently only used by the pseudo context object and may disappear at some point. โ ๏ธ Yes, "may disappear" โ so don't get too attached. She's ephemeral. ๐
๐ THANKS ๐
Giving credit where credit is due, because we stan supportive community energy:
- Thanks to Andy Wardley for creating Template::Toolkit.
- Thanks to Sam Tregar for creating HTML::Template.
- Thanks to David Lowe for creating Text::Tmpl.
- Thanks to the Apache Velocity guys.
- Thanks to Ben Grimm for a patch to allow passing a parsed document to the ->process method.
- Thanks to David Warring for finding a parse error in HTE syntax.
- Thanks to Carl Franks for adding the base
ENCODINGsupport.
๐ AUTHOR ๐
Paul Seamons <paul@seamons.com>
๐ LICENSE ๐
This module may be distributed under the same terms as Perl itself.
and that's the whole page bestie!! ๐โจ This beauty is perl v5.38.2, dated 2024-03-07, and it's the Template::Alloy(3pm) manpage โ you read the ENTIRE thing, all 12 parts, no skimming, and honestly? That's dedication. Slay. Go build something iconic with it. ๐๐ฆ๐ธ๐
๐ฆ where this page comes from
- debian trixie: libtemplate-alloy-perl 1.022-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libtemplate-alloy-perl 1.022-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libtemplate-alloy-perl 1.022-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms