use Template::Stash; my $stash = Template::Stash->new({ pi => 3.14, msg => 'Hello World', user => { name => 'Andy Wardley', email => 'abw@kfs.org' }, items => [ 'foo', 'bar', 'baz' ], mysub => sub { local $" = ', '; return "called mysub(@_)"; }, myobj => MyObject->new(), }); # [% pi %] print $stash->get('pi'); # [% msg %] print $stash->get('msg'); # [% user.name %] print $stash->get([ user => 0, name => 0 ]); # [% items.0 %] print $stash->get([ items => 0, 0 => 0 ]); # [% mysub %] print $stash->get('mysub'); # [% mysub(10, 20) %] print $stash->get([ mysub => [ 10, 20 ] ]) # [% myobj.method(10, 20) %] print $stash->get([ myobj => 0, method => [ 10, 20 ] ]) # [% pi = 3 %] $stash->set( pi => 3 ); # [% msg = 'Goodbye Cruel World' %] $stash->set( msg => 'Goodbye Cruel World' ); # [% user.name = 'Larry Wall' %] $stash->set([ user => 0, name => 0 ], 'Larry Wall'); # [% items.0 = 'foo' %] $stash->set([ items => 0, 0 => 0 ], 'foo' ); # [% myobj.method(10, 20) = 30 %] $stash->set([ myobj => 0, method => [ 10, 20 ] ], 30 )
The Stash has been totally re-written from the ground up for version 3. It implements a new internal dispatch mechanism which permits the lookahead required to implement several new postfix virtual methods such as LIST, ITEM, CODEREF and REF. This was inspired by Craig Barratt's recent work on implementing this feature in the v2 parser (Template::Stash::Context in v2.03).
By adding a few well-chosen virtual methods like these we can greatly extend the capability of the Stash operations permissible. LIST, HASH and ITEM act as explicit conversion filters to allow you to switch between types.
[% item = item.ITEM %] === [% item %] [% item = list.ITEM %] === [% list.0 %] [% item = list.ITEM(n) %] === [% list.$n %] [% item = hash.ITEM(key) %] === [% hash.$key %] [% list = list.LIST %] === [% list %] [% list = item.LIST %] === [% [ item ] %] [% list = hash.LIST %] === [% [ a => b, c => d, ... ] %] [% list = hash.LIST('keys') %] === [% [ a, c, ... ] %] [% list = hash.LIST('values) %] === [% [ b, d, ... ] %] [% hash = item.HASH %] === [% { 'item' => item } %] [% hash = hash.HASH %] === [% hash %] [% hash = list.HASH %] === [% { a => b, c => d, ... } %] ...etc...
In addition, they also allow the calling context of a subroutine or object method to be explicitly stated.
# postfix vmeth indicates expected result and thus # determines calling context of code [% result = mycode.LIST %] # explicit list context (default) [% result = mycode.ITEM %] # scalar context # same for object methods [% result = myobj.method(10, 20).LIST %] [% result = myobj.method(10, 20).ITEM %]
REF returns a string indicating the reference type of an object, e.g. 'LIST, 'HASH', 'CODE'. Code references and object methods are not called. Object methods return 'CODE' as a reference type.
[% myitem.REF %] # nothing (should return 'ITEM' perhaps?) [% mylist.REF %] # LIST [% myhash.REF %] # HASH [% mycode.REF %] # CODE [% myobj.REF %] # MyObject [% myobj.method.REF %] # CODE
CODEREF returns a closure which can be used to subsequently evaluate a variable in a lazy fashion. This works for any data types, including object methods. Parameters specified with the node at the CODEREF point are correctly merged with those specified when the closure is called.
[% myref = foo.bar.CODEREF %] [% myref %] # same as [% foo.bar %] [% myref = foo.bar(10).CODEREF %] [% myref(20) %] # same as [% foo.bar(10, 20) %]
There is also full support for objects to provide their own virtual method implementations. If an object implements the TT_ITEM method, for example, then any calls to:
[% myobject.ITEM('foo') %]will be translated to calls of the form:
$myobject->TT_ITEM('foo');
On the subject of case, this implementation has virtual methods in UPPER CASE by default. I'm inclined to make this the default for v3 in a move to make all Template Toolkit "builtin" commands, variables, etc., UPPER CASE, and all user data in lower case. However, it should be possible to set a parser option which does automatic case folding for directives and/or virtual methods so that will almost certainly be a user option.
One of the important differences between virtual methods from version 2 is that there is just one virtual method which applies to each and every data type. If a virtual method expects a list and receives an item, for example, then it automatically applies the LIST virtual method to first create a list representation of the item. This makes the use of virtual methods much more consistent and guarantees some correct result for any data type (for various definitions of "correct" which doesn't necessariy imply "useful").
Another new feature is support for inplace pre and post
increment/decremement operations. Although the parser
doesn't yet parse it at the time of writing, the Stash
supports operations of the form [% a++ %]
,
[% a = b++ %]
, [% c += d %]
,
etc.
Reference to a hash array defining virtual methods.
use Template::Stash; $Template::Stash::VMETHS->{ BLAM } = \&blam; sub blam { my ($stash, $root, $args, $nodes) = @_; # .... return $result; }
[% myitem.BLAM(3.14, 2.718).blah(99) %]
blam($stash, $myitem, [ 3.14, 2.718 ], [ blah => [ 99 ] ]);
The first argument passed is a reference to the Stash object. The second is the value that the 'myitem' variable was evaluated to by the Stash. This may be a reference (e.g. to a list, hash, etc) or a simple scalar value. If the 'myitem' variable resolved to a CODE ref then the Stash will already have called the code to resolve a value for 'myitem'. Thus, in the general case, $myitem won't contain a CODE reference, but there's nothing to stop a subroutine returning a subroutine reference so don't rule it out. The third item argument contains a reference to a list of any parameters specified with the virtual method. This value may be undefined or set to 0 to indicate no parameters.
The last argument, $nodes, is a reference to the list of variable nodes remaining after the current virtual method node. The subroutine may inspect or shift items off this list but should always do so in pairs of ($name, $args)). Items removed from the $nodes list will NOT be subsequently evaluated by the Stash so it is assumed you know what you're doing if you do this.
=>
in a => b, c => d
.
$Template::Stash::HASH_EQUALS = ' => '; # default
,
in a => b, c => d
. Named after a
favourite pastime of the author :-)
$Template::Stash::HASH_JOINT = ', '; # default
,
in a, b, c, d
.
$Template::Stash::LIST_JOINT = ', '; # default
$Template::Stash::DEBUG = 1;
$Template::Stash::WARNINGS = 1;
new( \%vars )
Constructor method implemented by Template::Base.
use Template::Stash; my $stash = Template::Stash->new({ pi => 3.14, msg => 'Hello World', ... });
init( \%config )
Initialiser method called by base class new() constructor method.
clone( \%newvars )
Clones the current Stash to create a new copy which contains the
current values supplemented and possibly temporarily masked by
new values passed as a hash reference.
declone()
eturns the parent Stash that created the current Stash via the
clone()
method.
operate( $var )
The operate()
method is an alias for
get()
(or rather, get()
is
an alias for operate()
, but it's all the same
thing). However, we generally think of get()
as implementing an interface compatible with v2, whereas
operate()
offers extended support for doing
more gnarly operations on variables.
get( $var )
The get() method evaluates and returns the value of a variable
in the Stash. The variable name can be specified as a single
string for simple variables, e.g. 'foo'
, or as
a reference to a list of ($node, \@args) pairs for complex
(dotted) variables. In the latter case, the argument list
for variable nodes without arguments can be specified as 0.
# general form of [% xxx(a, b).yyy(c, d) %] $stash->get([ xxx => [ a, b ], yyy => [ c, d ] ]); # short form of [% xxx.yyy %] $stash->get([ xxx => 0, yyy => 0 ]); # short form of [% xxx %] $stash->get('xxx');
set( $var, $value )
The set() method is used to update a variable value. The first
argument specifies the variable name as per get()
and the second specifies the new value.
# general form of [% xxx(a, b).yyy(c, d) = value %] $stash->set([ xxx => [ a, b ], yyy => [ c, d ] ], value); # short form of [% xxx.yyy = value %] $stash->set([ xxx => 0, yyy => 0 ], value); # short form of [% xxx = value %] $stash->set( xxx => value );
pre_inc( $var, $inc )
This method can be called to increment a variable value in place
and then return the new result. The default increment is 1.
Thus the following:
$stash->pre_inc('foo');
[% ++foo %]
$stash->pre_inc('foo', 10);
post_inc( $var, $inc )
As per pre_inc()
but returning the value of
the variable from before it was incremented.
$stash->post_inc('foo');
[% foo++ %]An increment other than 1 can be specifed.
$stash->post_inc('foo', 10);
pre_dec( $var, dec )
Not yet implemented.
post_dec( $var, dec )
Not yet implemented.
The virtual methods have all been re-written such that any method can be applied to any data type with the correct promotion or demotion between scalars and lists being handled automatically. In other words, if you call item.FIRST, you get the item back because a single item is considered to be a one-element list. Some methods just Do The Right Thing for different types. For example, list.LENGTH returns the number of items in a list whereas item.LENGTH returns the length of the item string. Conversely, list.SIZE return the same as list.LENGTH but item.SIZE returns 1 because that virtual method treats a single item as a one-element list.
The JOIN and SORT virtual methods make particular use of the ability to work across different data types. Calling list.JOIN return a string of the form "a, b, c, d, ..." whereas hash.JOIN returns "a = b, c = d, ...". You can use the LIST, HASH and ITEM methods to explicitly convert between "types", e.g. list.HASH.JOIN converts 'list' to a hash and then performs a hash join on it, returning "a = b, c = d, ...". The JOIN method, in addition to its own parameters for specifying joining string, accepts arguments for sorting which are delegated to the SORT method. This means you can do things like:
[% hash.JOIN( order='number', item='values' ) %]to sort the hash items numerically by value (default: alphanumerically by key) and return a string of the form "a = b, c = d, ...".. List of Virtual Methods:
vmeth_ref( $root, \@args, \@nodes )
Returns a string indicating the type of data it was called
against (e.g. LIST
, HASH
,
CODE
, MyObject
. Returns an
empty string if the item is not a reference.
vmeth_item( $root, \@args, \@nodes )
Returns a single item which is either the item itself
or a member of an item (e.g. element in a list or hash
reference) identified by an argument.
against (e.g. LIST
, HASH
,
CODE
, MyObject
. Returns an
empty string if the item is not a reference.
vmeth_list( $root, \@args, \@nodes )
Coerce item to a list. Implemented but not yet documented.
vmeth_hash( $root, \@args, \@nodes )
Coerce item to a hash. Implemented but not yet documented.
vmeth_length( $root, \@args, \@nodes )
Return length of string, number of element in a list or number
of key => value pairs in a hash. Implemented but not yet
documented.
vmeth_size( $root, \@args, \@nodes )
Returns the same as vmeth_length()
for lists and hash
references. Returns 1 for single items. Implemented but not yet
documented.
vmeth_max( $root, \@args, \@nodes )
Returns the maximum index number (e.g.
) for
lists and hashes. Returns 0 for single items.
Implemented but not yet documented.
vmeth_first( $root, \@args, \@nodes )
Returns the first item in a list/hash or returns a single
item as is. Implemented but not yet documented.
vmeth_last( $root, \@args, \@nodes )
Returns the last item in a list/hash or returns a single
item as is. Implemented but not yet documented.
vmeth_join( $root, \@args, \@nodes )
Returns a string representing the item or concatentated
elements of a complex item (e.g. a list or hash). Uses the
$LIST_JOINT
value to join list items, and the
$HASH_JOINT
and
$HASH_EQUALS
variables to join hash items.
The
[% list.JOIN(' + ') %] [% list.JOIN( joint => ' + ' ) %] [% hash.JOIN( ', ', ' => ' ) %] [% hash.JOIN( joint => ', ', equals => ' => ' ) %]
vmeth_sort( $root, \@args, \@nodes )
Sort the items in a list or hash. Implemented but not yet
documented.
vmeth_reverse( $root, \@args, \@nodes )
Reverse the items in a list. Implemented but not yet documented.
vmeth_repeat( $root, \@args, \@nodes )
Repeat a single item (string repeat) or list/hash of items
(list repeat). Implemented but not yet documented.