Modules · Web · 0.13
Template::Stencil
A template engine that compiles once and then renders from C.
One {% %} grammar, compiled once to bytecode and rendered by a C interpreter straight into the scalar it returns. Templates are cached, includes revalidate on their own, and at steady state a render allocates nothing and makes no system call. Every page on this site is rendered by it.
use Template::Stencil;
my $stencil = Template::Stencil->new;
my $page = <<'TMPL';
<h1>{% title | upper %}</h1>
{% if items %}<ul>
{% for item in items %} <li class="{% if loop.odd %}odd{% else %}even{% end %}">{% item.name %}: {% item.price | fmt('$%.2f') %}</li>
{% end %}</ul>{% else %}<p>Nothing yet.</p>{% end %}
TMPL
# compiled once, then rendered from the cache; values are escaped
print $stencil->render($page, {
title => 'Menu',
items => [ { name => 'Tea', price => 1.5 }, { name => 'Cake <3', price => 3 } ],
});
What you get
-
Compiled once
File templates are cached and revalidated by modification time, string templates by a hash of their content.
stat_ttl => -1makes a steady-state render free of system calls. -
A small grammar
Output, filters,
if/elsif/unless,forover arrays and hashes withloop.indexand friends,set,includeand a wrapper. Every block closes with{% end %}. -
Escaped unless you say
Output is HTML-escaped once, after the last filter, and
rawopts out. Filters are C:upper,trim,uri,default, andfmt, whose format is checked when the template compiles. -
Errors with a place
Every error names the file, the line and, when compiling, the column. Under
stricta missing value is an error that names its path. -
Bytes ready to send
A render returns UTF-8 bytes whose
lengthis theContent-Length. The engine does the encoding, so the caller never does.
In use
use Template::Stencil;
use File::Temp qw(tempdir);
my $dir = tempdir(CLEANUP => 1);
for ([ 'layout.tmpl', "<main>{% content %}</main>\n" ],
[ 'card.tmpl', '<b>{% user.name %}</b>' ],
[ 'page.tmpl', '{% for user in users %}{% include card %}{% end %}' ]) {
open my $fh, '>', "$dir/$_->[0]" or die $!;
print {$fh} $_->[1];
}
my $stencil = Template::Stencil->new(template_dir => $dir, wrapper => 'layout.tmpl', strict => 1);
print $stencil->render('page', { users => [ { name => 'ada' }, { name => 'tim' } ] });
# <main><b>ada</b><b>tim</b></main>
eval { $stencil->render('page', { users => [ {} ] }) };
print $@; # names the file and line: card.tmpl:1: undef value for 'user.name'
For C
st_abi.h, resolved at run time through Template::Stencil::_abi_ptr: an XS module renders through the engine with no Perl frame between, and a template error comes back through an out-parameter rather than an exception. Punk renders its views this way.