Template Toolkit
From the home of
Template Toolkit 2:
The Template Toolkit is a fast, flexible and highly extensible template processing system. It is Free (in both senses: free beer and free speech), Open Source software and runs on virtually every modern operating system known to man. It is mature, reliable and well documented, and is used to generate content for countless web sites ranging from the very small to the very large.
It is written in the Perl programming language but you don't need to know any Perl to use it. In fact, it was specifically created to allow web designers and developers to concentrate on generating web pages without getting bogged down in programming matters. We call this a "Clear Separation of Concerns" and it makes the whole processes of building, updating and maintaining a web site or web application significantly easier.
Examples
Examples taken from
http://template-toolkit.org/docs/manual/Intro.html
-----------------------------------------------------
[% FOREACH section = menu %]
<a href="[% root %]/[% section %]/index.html">[% section %]</a>
[% END %]
<b>Client</a>: [% client.name %] (id: [% client.id %])
-----------------------------------------------------
[% IF shopcart.nitems %]
Your shopping cart contains the following items:
<ul>
[% FOREACH item = shopcart.contents %]
<li>[% item.name %] : [% item.qty %] @ [% item.price %]
[% END %]
</ul>
[% checkout(shopcart.total) %]
[% ELSE %]
No items currently in shopping cart.
[% END %]
-----------------------------------------------------
[% BLOCK tabrow %]
<tr><td>[% name %]</td><td>[% email %]</td></tr>
[% END %]
<table>
[% PROCESS tabrow name="tom" email="tom@here.org" %]
[% PROCESS tabrow name="dick" email="disk@there.org" %]
[% PROCESS tabrow name="larry" email="larry@where.org" %]
</table>
-----------------------------------------------------
[%# this entire directive is ignored no
matter how many lines it wraps onto
%]
-----------------------------------------------------
[% FOREACH item = [ 'foo' 'bar' 'baz' ] %]
* Item: [% item %]
[% END %]
-----------------------------------------------------
[% BLOCK footer %]
Copyright 2000 [% me %]
[% INCLUDE company/logo %]
[% END %]
-----------------------------------------------------
[% SET foo = 10 %]
[% GET foo %]
[% foo = 10 %]
[% foo %]
-----------------------------------------------------
[% title or template.title or 'Default Title' %]
-----------------------------------------------------
[% mode == 'graphics' ? "Graphics Mode Enabled" : "Text Mode" %]
-----------------------------------------------------
[% headtext = PROCESS header title="Hello World" %]
[% people = PROCESS userinfo FOREACH user = userlist %]
[% PROCESS somefile | truncate(100) | html %]
-----------------------------------------------------
[% 15 / 6 %] # 2.5
[% 15 div 6 %] # 2
[% 15 mod 6 %] # 3
-----------------------------------------------------
[% CALL dbi.disconnect %]
[% CALL inc_page_counter(page_count) %]
-----------------------------------------------------
[% foo = 'Foo' %] # literal value 'Foo'
[% bar = foo %] # value of variable 'foo'
[% cost = '$100' %] # literal value '$100'
[% item = "$bar: ${cost}.00" %] # value "Foo: $100.00"
[% copyright = '(C) Copyright' _ year _ ' ' _ author %]
[% copyright = "(C) Copyright $year $author" %]
-----------------------------------------------------
[% DEFAULT
name = 'John Doe'
id = 'jdoe'
%]
-----------------------------------------------------
[% INSERT misc/legalese.txt %]
[% INSERT 'dos98/Program Files/stupid' %]
-----------------------------------------------------
[% SWITCH myvar %]
[% CASE 'value1' %]
...
[% CASE ['value2', 'value3'] %] # multiple values
...
[% CASE myhash.keys %] # ditto
...
[% CASE %] # default
...
[% END %]
-----------------------------------------------------
[% userlist = [
{ id => 'tom', name => 'Thomas' },
{ id => 'dick', name => 'Richard' },
{ id => 'larry', name => 'Lawrence' },
]
%]
[% FOREACH user IN userlist %]
[% user.id %] [% user.name %]
[% END %]
-----------------------------------------------------
[% users = {
tom => 'Thomas',
dick => 'Richard',
larry => 'Lawrence',
}
%]
[% FOREACH u IN users %]
* [% u.key %] : [% u.value %]
[% END %]
-----------------------------------------------------
[% USE giter = iterator(grouplist) %]
[% FOREACH group IN giter %]
[% FOREACH user IN group.userlist %]
user #[% loop.count %] in
group [% giter.count %] is
named [% user.name %]
[% END %]
[% END %]
-----------------------------------------------------
--
Contributors: LesOrchard,
PeterThoeny
Discussion
I've been using the
TemplateToolkit for a few years now, and have been wholly converted to it. IMHO, it is heading toward being The Ultimate Templating System for perl. It allows for a very clean separation between logic and presentation via hash namespaces used in populating the templates. And although extremely flexible out of the box, the system is completely extensible via plugins which add new capabilities into the template environment, provide tags to define filter blocks in which content is processed through code.
There is even a very flexible architecture in how the system finds templates in the first place. The plain vanilia manner, or course, is to read them straight from file storage in a directory. However, one can supply new "Template provider" classes to allow the system to find, compile, and cache templates from database tables, from in-memory hashes, basically from any source you can wrap an object around.
And one more thing: The
TemplateToolkit is not restricted to
HTML, and can be used to generate any text document type. In fact, newer plugins look like generating templated images (ie. via GD image generation libraries) from the template namespace data.
--
LesOrchard - 01 Jun 2001
This has been throw around a bit. I've been looking at it myself, although last time I fiddled with
TemplateToolkit was 12 months ago. I'm not sure what the state of the are is now.
The main thing to consider I see, is defining a clear path for the TWiki syntax rendering to be understood by
TemplateToolkit. If it can be done without forcing a change in the syntax defined
TextFormattingRules that would be great.
--
NicholasLee - 04 Jun 2001
Basically, the
TextFormattingRules could stay the same.
TemplateToolkit has a facility for defining filter tags. So, wherever in a TWiki template that content following the
TextFormattingRules appears might look something like:
[% FILTER TWikiFilter %]
$content
[% END %]
...where $content contains the text of the content, of course. The implementation of a filter plugin is basically some plugin boilerplate surrounding a single sub into which the text inside the [% FILTER %] construct is passed, and the filtered text returned. So, all the regexes implementing the
TextFormattingRules could be collected there.
The only things one might want to have different are things like how
TWikiVariables are included and the other miscellaneous little constructs and function calls in the %...% syntax. They could just be implemented along site the other formatting rules in the filter, but here one might want to take advantage of
TemplateToolkit features here.
For instance,
TemplateToolkit does a very good job of managing access to variables and objects in the template namespace. Plain variables can just be thrown into the namespace hash. So instead of % SERVERTIME%, it would be $SERVERTIME. Or, one could organize all the variables under another namespace key, so maybe $TWiki.SERVERTIME.
As for the programmatic elements, such as % INCLUDE{...}%,
TemplateToolkit also allows access to plugin object methods. So, maybe create a TWiki utility object with a method include. % INCLUDE{..}% could turn into $TWiki.include('filename'). And, in this way, new TWiki functions could be added simply as methods to the hypothetical TWiki utility plugin object. No mussing with regexes to parse all the arguments, etc...
And on top of all of this, you get basic conditional and looping constructs, and only as much system level access as your plugins allow. So, no opening files unless you supply a file access plugin, etc...
--
LesOrchard - 05 Jun 2001
How about turning off access to certain features of TT within the main content body. ie. Otherwise we might create a security hole.
--
NicholasLee - 06 Jun 2001
The toolkit is very powerful and can also be extended with plugins, i.e. the tutorial mentions a DB plugin where you can specify a
SQL query and loop through the rows to display the result.
This is all nice but it probably is not a good fit for TWiki:
- The TemplateToolkit is BIG, only the
lib
directory is over 1 MB. That would mean an increased CPU load and memory load for each topic view.
- The TWiki core should stay lean and not depend on too many external modules. (Plugins are excluded)
- There is an overlap of functionality of the TemplateToolkit and TWiki, i.e. the plugin.
- The syntax is (not surprisingly) not a good fit.
As mentioned in
CommonHeaderFooterTemplate it makes sense to define common patterns just once, i.e. the header and the footer so that it is easy to change them. Since the TemplateToolkit is not suitable we should roll our own
TWikiTemplatingSystem.
--
PeterThoeny - 21 Jul 2001
Further discussion refactored to
BetterTemplateSystem
--
CrawfordCurrie - 2004-10-14