template toolkit remove , from the last entry - perl

I have the following seciton on the template toolkit
names: [[% FOREACH name IN name %] '[% name %]', [% END %]]
which prints something like this :
names : ['name1','name2','name3',]
my question is there an option to tweak the above in order not to print the last comma i.e the result will be
names : ['name1','name2','name3']

Inside every FOREACH loop, you have access to the special loop variable - which is an instance of the Template::Iterator class.
So you can write something like this:
names: [[% FOREACH name IN name %] '[% name %]'[% UNLESS loop.last %],[% END %] [% END %]]

Related

How to check variable type in template toolkit?

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 %]

Text::Xslate returning incorrect value for function call

I'm using Text::Xslate with HTML::FormHandler (HTML::FormHandler is actually used behind the scenes by CatalystX::SimpleLogin, in case that helps). I'm using Text::Xslate's TTerse syntax and trying to show the errors in my template like so:
[% FOR field IN login_form.error_fields %]
[% FOR error IN field.errors %]
<p>[% field.label _ ': ' _ error %]</p>
[% END %]
[% END %]
If I just print out
[% login_form %]
It returns CatalystX::SimpleLogin::Form::Login=HASH(0x7fbb21722a20), which is what I would expect. But then when I call error_fields on it, it just returns a 1. However, when I use Template::Toolkit instead of Text::Xslate, this works properly and the errors show. Does anyone know why error_fields is returning a number and not an array?

Display array in multi-column table using template tookit?

I have an array of phone numbers. I want to display these numbers in a table, 5 numbers per row. Can I do this in Template Toolkit without modifying my data structure?
You can use the plugin Template::Plugin::Table:
[% USE table(phone_numbers, cols=5) %]
[% FOREACH row IN table.rows %]
[% FOREACH item IN row %]
[% item %]
[% END %]
[% END %]
phone_numbers is a reference to the phone number array which should be passed to Template Toolkit. Example:
...
$data->{phone_numbers} = \#phone_numbers;
$template->process('example.tmpl', $data)
|| die "Template processing failed: ", $template->error(), "\n";

error in printing data using template module

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.

How can I delete variable in Template Toolkit?

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 %]