Introduction to Template::Toolkit
description
Transcript of Introduction to Template::Toolkit
Introduction To Template::Toolkit
IntroductionBasics: Part One
Exercises (Hands On)Basics: Part Two
Exercises (Hands On)References and Further Reading
Introduction
•Who am I?•What level of Perl expertise is required?•What is Template::Toolkit?
Part One
•Simple mail-merge type example
Template for a letter
Dear [% name %], It has come to our attention that your account is in arrears to the sum of [% debt %]. Please settle your account before [% deadline %] or we will be forced to revoke your Licence to Thrill. The Management.
Perl script to call ituse strict;use Template;my $tt = Template->new({ INCLUDE_PATH => '/usr/local/templates', INTERPOLATE => 1,}) || die "$Template::ERROR\n";
my $vars = { name => 'Count Edward van Halen', debt => '3 riffs and a solo', deadline => 'the next chorus', }; $tt->process('letters/overdrawn', $vars) || die $tt->error(), "\n";
Multiple letters
[% FOREACH d IN debtors %]Dear [% d.name %], It has come to our attention that your account is in arrears to the sum of [% d.debt %]. Please settle your account before [% d.deadline %] or we will be forced to revoke your Licence to Thrill. The Management.[% END %]
Perl fragmentmy $vars = { debtors => [ { name => 'Count Edward van Halen', debt => '3 riffs and a solo', deadline => 'the next chorus', }, { name => ‘Baron Eric Clapton', debt => ‘1 badge', deadline => ‘tomorrow', }]}; $tt->process('letters/overdrawn', $vars) || die $tt->error(), "\n";
Multiple letters with logic[% FOREACH d = debtors %]Dear [% d.name %], It has come to our attention that your account is in arrears to the sum of [% d.debt %]. Please settle your account before [% d.deadline %] or we will be forced to revoke your Licence to Thrill.
[% IF d.final %]This is your last chance.[% END %] The Management.[% END %]
Perl fragmentmy $debtors = [ { name => 'Count Edward van Halen', debt => '3 riffs and a solo', deadline => 'the next chorus', }, { name => ‘Baron Eric Clapton', debt => ‘1 badge', deadline => ‘tomorrow', final => 1 }]; $tt->process('letters/overdrawn', $debtors) || die $tt->error(), "\n";
Boolean logic: IF ELSE[% IF age < 10 %][% ELSIF age < 18 %][% ELSE %][% END %]
The following conditional and boolean operators may be used: == != < <= > >= && || ! and or not
Boolean logic: SWITCH
[% SWITCH myvar %][% CASE 'value1' %][% CASE ['value2', 'value3'] %] # multiple values[% CASE myhash.keys %] # ditto[% CASE %] # default[% END %]
Alternative contents[% FOREACH d IN debtors %]Dear [% d.name %], Thank you for your recent payment of [% d.debt %]. Your account is now clear and you may continue to thrill. The Management.[% END %]
Include other templates[% FOREACH d IN debtors %]Dear [% d.name %], [% IF d.angry -%][% INCLUDE angry_letter.tt2 %][% ELSE -%][% INCLUDE grateful_letter.tt2 %][% END -%] The Management.[% END %]
Perl fragmentmy $debtors = [ { name => 'Count Edward van Halen', debt => '3 riffs and a solo', deadline => 'the next chorus', }, { name => ‘Baron Eric Clapton', debt => ‘1 badge', deadline => ‘tomorrow', final => 1, angry => 1, }]; $tt->process('letters/overdrawn', $debtors) || die $tt->error(), "\n";
Exercises
Part Two•Adding a wrapper for the header and footer•Adding simple filters to encoding entities or control case•Using a vmethod to add row numbers•Sorting a select list•Formatting currency
Adding a wrapperContent-Type: text/html; charset=ISO-8859-1
<html><head></head><body><h1>Introduction to TT</h2>
[%# Header and footer will be the same on all pages %]
<table><tr><th>Something</th><th>Something Else</th></tr>[% FOREACH r IN rows %]<tr><td>[% r.something %]</td><td>[% r.something_else %]</td></tr>[% END %]</table>
</body></html>
Move the common content to wrapper.tt
Content-Type: text/html; charset=ISO-8859-1
<html><head></head><body><h1>Introduction to TT</h2>
[% content %]
</body></html>
Tell TT about the wrapper#! /usr/bin/perl
use strict; use warnings; use CGI; use Template;
# Using a wrapper.
my $tt = Template->new( { INCLUDE_PATH => '/home/duncan/tt/htdocs/tt2', INTERPOLATE => 1, WRAPPER => 'wrapper.tt2' }) || die "$Template::ERROR\n";
$tt->process( 's2.tt2', { rows => [ { something => 'apples', something_else => '1 kg' }, { something => 'pears', something_else => '2 kg' } ] }) || die $tt->error() . "\n";
Dodgy datamy $tt = Template->new( { INCLUDE_PATH => '/home/duncan/tt/htdocs/tt2', INTERPOLATE => 1, WRAPPER => 'wrapper.tt2' }) || die "$Template::ERROR\n";
$tt->process( 's2.tt2', { rows => [ { something => 'apples', something_else => '1 kg' }, { something => 'pears', something_else => '2 kg' }, { something => 'turnips > pears > grapes', something_else => '2 & 3 kg' }, { something => '<script type="text/javascript">alert("Hi");</script>', something_else => '2 & 3 kg' }, ] }) || die $tt->error() . "\n";
Encode it!<! [% component.name %] -->
[%# Using a filter to encode entities and control case. %]
<table><tr><th>Something</th><th>Something Else</th></tr>[% FOREACH r IN rows %]<tr><td>[% r.something FILTER html_entity %]</td><td>[% r.something_else FILTER html_entity FILTER upper %]</td></tr>[% END %]</table><!-- End [% component.name %] -->
That’s better<tr><td>apples</td><td>1 KG</td></tr> <tr><td>pears</td><td>2 KG</td></tr>
<tr><td>turnips > pears > grapes</td><td>2 & 3 KG</td></tr>
<tr><td><script type="text/javascript">alert("Hi");</script></td><td>2 & 3 KG</td></tr>
Use a vmethod to add row numbers
<! [% component.name %] -->
[%# Using a vmethod to add row number %]
<table><tr><th>No</th><th>Something</th><th>Something Else</th></tr>[% FOREACH r IN rows %]<tr><td>([% loop.index %])</td><td>[% r.something FILTER html_entity %]</td><td>[% r.something_else FILTER html_entity FILTER upper %]</td></tr>[% END %]</table><!-- End [% component.name %] -->
With row numbers
No Something Something Else
(0) apples 1 KG
(1) pears 2 KG
(2) turnips > pears > grapes 2 & 3 KG
(3) <>peas 2 & 3 KG
(4) apricots 2 & 3 KG
Use a vmethod to do a simple sort on a select list.
my $tt = Template->new( { INCLUDE_PATH => '/home/duncan/tt/htdocs/tt2', INTERPOLATE => 1, WRAPPER => 'wrapper.tt2' }) || die "$Template::ERROR\n";
$tt->process( 's5.tt2', { rows => [ { something => 'apples', something_else => '1 kg' }, { something => 'pears', something_else => '2 kg' }, { something => 'turnips > pears > grapes', something_else => '2 & 3 kg' }, { something => '<>peas', something_else => '2 & 3 kg' }, { something => 'apricots', something_else => '2 & 3 kg' }, ], suppliers => [ 'Fred', 'Alan', 'Joe', 'Bert' ] }) || die $tt->error() . "\n";
Adding the sort vmethod[%# Using a vmethod to do a simple sort on a select list %]
<! [% component.name %] -->
<select>[% FOREACH s IN suppliers.sort %]<option value="s"/>[% s %][% END %]</select>
<table><tr><th>No</th><th>Something</th><th>Something Else</th></tr>[% FOREACH r IN rows %]<tr><td> ([% loop.index %])</td><td>[% r.something FILTER html_entity %]</td><td>[% r.something_else FILTER html_entity FILTER upper %]</td></tr>[% END %]</table><!-- End [% component.name %] -->
Using the Format plugin on currency
No Something Something Else Cost
(0) apples 1 KG £5.67
(1) pears 2 KG £3.33333333333333
(2) turnips > pears > grapes 2 & 3 KG £4.123
(3) <>peas 2 & 3 KG £2
(4) apricots 2 & 3 KG £3
The script with the plugin[% USE money=format('%.2f') -%]
<select>[% FOREACH s IN suppliers.sort %]<option value="s"/>[% s %][% END %]</select>
<table><tr><th>No</th><th>Something</th><th>Something Else</th><th>Cost</ht></tr>[% FOREACH r IN rows %]<tr><td> ([% loop.index %])</td><td>[% r.something FILTER html_entity %]</td><td>[% r.something_else FILTER html_entity FILTER upper %]</td><td>£[% money(r.cost) %]</td></tr>[% END %]</table><!-- End [% component.name %] -->
Further Reading
Template Toolkit [Paperback] •Darren Chamberlain,
•Dave Cross, •Andy Wardley
Also documented on MetaCPAN: https://metacpan.org/
It has its own website: http://www.template-toolkit.org/
226 plugins listed on MetaCPAN