Looking at Template::Manual::VMethods section of the Template Toolkit manual I don't see any method doing this. Also assigning undef to variable doesn't work - variable.defined returns true after the fact.
Well, googling "delete variable" site:mail.template-toolkit.org/pipermail/templates/ brought the question [Templates] Can I “DELETE some_var”? from Felipe Gasper with two answers from Petr Danihlik. Petr suggests:
[% SET foo = 1 %]
[% IF foo.defined %] defined1 [% END %]
[% PERL %]
delete($stash->{foo});
[% END %]
[% IF foo.defined %] defined2 [% END %]
I looked at Catalyst::View:TT code, in order to understand variables context.
The following subroutine, which I summarized a little bit does the rendering work:
sub render {
my ( $self, $c, $template, $args ) = #_;
# [...]
my $output; # Template rendering will end here
# Variables interpolated by TT process() are passed inside an hashref
# as copies.
my $vars = {
( ref $args eq 'HASH' ? %$args : %{ $c->stash() } ),
$self->template_vars( $c )
};
# [...]
unless ( $self->template->process( $template, $vars, \$output ) ) {
# [ ... ]
}
# [ ... ]
return $output;
}
TT process() is called with copies of variables in $c->stash, so why do we need to mess with $c->stash to get rid of a local copy? Maybe we don't.
Moreover, TT define() VMethod, like other methods, seem to have been built for lists. Scalars are auto-promoted to single element list when a VMethod is called on them: maybe for this reason the IF test returns always true.
I did some tests with variables carrying references to DBIx::Class::ResultSet objects, and this seems to work while testing for a variable:
[%- resultset_rs = undef %]
[%- IF ( resultset_rs ) %]
<h3>defined</h3>
[%- END %]
The first line deletes the variable, and the second does proper test.
UPDATE
If you can add EVAL_PERL => 1 flag in your Catalyst View, inside config() argumets,
__PACKAGE__->config({
# ...
EVAL_PERL => 1
});
then you can use [% RAWPERL %] directive in templates, which gives you direct access to the Template::Context object: then you can delete vars and .defined() VMethod does the right thing.
[%- RAWPERL %]
delete $context->stash->{ 'resultset_rs' };
[%- END %]
[%- IF ( resultset_rs.defined ) %]
<h3>defined: [% resultset_rs %]<h3>
[%- ELSE %]
<h3>undefined: [% resultset_rs %]<h3>
[%- END %]
Related
Is there any statement to print variable type in Template Toolkit? This is for debugging purposes.
I was trying to find something like:
type(my_var)
Output:
scalar
Use the PERL directive. Example:
[% PERL %]
print "my_var type: ", ref( $stash->get('my_var') ) || 'scalar';
[% END %]
I have 2 lists with complex (similar) hashes in them and i want to iterate over both lists within a single loop to not duplicate the code (I also do not want to make a block or macro)
testList1 = [0,1,2,3,4,5];
testList2 = [6,7,8,9,10,];
FOREACH item IN [testList1 , testList2]; # <--- ???
doSomething = doSomething _ 'useful ' _ item;
END;
The above statement creates a new list that contains only the references to the lists, but i want a temporary list with their contents.
How can i achieve this without extra manual list building logic. Is there some construct?
The list VMethod merge() will do the job:
[% testList1 = [0,1,2,3,4,5] %]
[% testList2 = [6,7,8,9,10,] %]
[% doSomething = '' %]
[% FOREACH item IN testList1.merge(testList2) %]
[% doSomething = doSomething _ 'useful ' _ item %]
[% END %]
[% doSomething %]
See http://www.template-toolkit.org/docs/manual/VMethods.html#section_merge for more information.
Consider these TT commands (run in order):
[% x = "foo" %] # x == "foo"
[% x = "bar" IF 1 %] # x == "bar"
[% x = "bar" IF 0 %] # x == ""
Why does x get assigned to an empty string in the 3rd statement?
http://template-toolkit.org/docs/manual/Syntax.html#section_Capturing_Block_Output
Note one important caveat of using this syntax in conjunction with side-effect notation. The following directive does not behave as might be expected:
[% var = 'value' IF some_condition %] # does not work
In this case, the directive is interpreted as (spacing added for clarity)
[% var = IF some_condition %]
value
[% END %]
rather than
[% IF some_condition %]
[% var = 'value' %]
[% END %]
The variable is assigned the output of the IF block which returns 'value' if true, but nothing if false. In other words, the following directive will always cause 'var' to be cleared.
[% var = 'value' IF 0 %]
To achieve the expected behaviour, the directive should be written as:
[% SET var = 'value' IF some_condition %]
I have little problem with printing data like this, I have written script like this
[% FOREACH comp IN company %]
[% comp.name %]
[% comp.location%]
employeedata:
[% FOREACH employee IN comp.domain.java.employee %]
[% FOREACH experiance IN employee.experiance %]
[% FOREACH obj IN ObjectDefinition%]
[% FOREACH beha IN obj.experiance %]
[% IF beha.years == experiance.years %]
[% beha.Name %],
[% LAST %]
[% END %]
[% END %]
[% END %]
[% END %]
[% END %]
[% END %]
from above script comparing "years" value in two keys in a hash and if both are same print the employee name. Its working and it printing like this as show below.
if three names is there it printing like this.
clar, larson, per,
if two names is there it printing like this.
clar, larson,
but I need to print like this
if three names is there
clar, larson or per.
if two names is there like this
clar, larson.
if only one name is there like this
clar.
I have maximum number of names is three only. I need to print like this help me how to print like this. if any mistakes is there excuse me please.
I tried like this also
[% FOREACH employee IN comp.domain.java.employee %]
[% FOREACH experience IN employee.experience %]
[% FOREACH obj IN ObjectDefinition%]
[% FOREACH beha IN obj.experience %]
[% IF beha.years == experience.years %]
[% IF employee.experience.size == 1 %]
[% beha.Name %].
[% ELSIF employee.experience.size == 2 %]
[% beha.Name %],[% beha.Name %].
[% ELSIF employee.experience.size == 3 %]
[% beha.Name %],[% beha.Name %]or[% beha.Name %].
[% END %]
[% END %]
[% END %]
[% END %]
[% END %]
[% END %]
but it printing when we have one name. if we have two names it printing like this
clar,clar.
larson,larson.
if we have three names it printing like this
clar,clar or clar.
larson,larson or larson.
per,per or per.
what is wrong with my script I cant solve this problem can any body help me please.
The second attempt is definitely closer to what you're going to need. But the order of the loops doesn't look right. beha.Name is only ever going to have the value of the current record.
I think you want something like this:
[% SET staff = []; # empty list
FOREACH beha IN obj.experience;
staff.push(beha) IF beha.years == experience.years;
END; %]
[% IF staff.size == 1;
staff.0.Name;
ELSIF staff.size == 2;
"$staff.0.Name, $staff.1.Name";
ELSIF staff.size >= 3;
"$staff.0.Name, $staff.1.Name or $staff.2.Name";
END %]
The IF-ELSIF loop is not very pretty, but there's no obvious staff.join() construction that's going to do what you need with that mix of commas and text separators and a limit of 3 elements.
UPDATE
As requested, an example using .join:
If you had an arbitrary length list of names, you might want to present them as name, name, [name, ...] or name:
ELSIF staff.size >= 3;
SET lastname = staff.pop; #remove last person from list
staff.join(', '); " or $lastname";
END;
But as I said previously, with a maximum of 3 names, this is overkill.
Template-Toolkit seems to want to always interpolate undef to the empty string. So a template like this:
Result is [% some_object.some_method (1, undef, 2) %]
or this:
Result is [% ttvar %]
[% some_object.some_method (1, ttvar, 2) %]
produces a call to Perl like:
some_object->some_method (1, '', 2)
when what I want is:
some_object->some_method (1, undef, 2)
Is there any way to pass undef instead of an empty string?
I've added another answer to show an example of how EVAL_PERL works in TT:
use Template;
use DateTime;
my $tt = Template->new( EVAL_PERL => 1 );
my $vars = { foo => 'DateTime', bar => DateTime->now, p => 'print' };
my $file = q{
[% SET hello = 'Hello world' %]
[% PERL %]
print "[% hello %]\n";
print [% foo %]->now, "\n";
[% p %] $stash->get( 'bar' )->ymd;
[% END %]
};
$tt->process( \$file, $vars );
The above outputs the following:
Hello world
2009-11-03T15:31:50
2009-11-03
Because TT is acting as a pre-processor and produces the following Perl code to interpret:
print "hello world\n";
print DateTime->now, "\n";
print $stash->get( 'bar' )->ymd;
NB. $stash in above line is provided by TT and is a reference to the top level stash object.
/I3az/
How about using [% PERL %]?
[% PERL %]
[% my_perl_code %]
[% END %]
This is a design decision with Template Toolkit. From page 50 of the Perl Template Toolkit "Badger book":
The Template Toolkit won't complain if it encounters a variable for which it doesn't have a value defined. Instead, it will quietly use an empty string (i.e., nothing at all) for the value of the variable and continue to process the reminder of the template.
However what you can do is make TT provide a warning when it sees an undef by using the DEBUG option. See the SO question Can Perl’s Template Toolkit warn on undefined values? for more info.
/I3az/