/usr/lib/perl5/Template/Manual/Internals.pod is in libtemplate-perl 2.22-0.1build2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | #============================================================= -*-perl-*-
#
# Template::Manual::Internals
#
# AUTHOR
# Andy Wardley <abw@wardley.org>
#
# COPYRIGHT
# Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
#
# This module is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
#========================================================================
=head1 NAME
Template::Manual::Internals - Template Toolkit internals
=head1 Introduction
This section of the documentation is aimed at developers wishing to
know more about how the Template Toolkit works on the inside in order
to extend or adapt it to their own needs.
If that doesn't sound like you then you probably don't need to read this.
There is no test afterwards.
=head1 Outside Looking In
The L<Template> module is simply a front end module which creates and
uses a L<Template::Service> and pipes the output wherever you want it to
go (C<STDOUT> by default, or maybe a file, scalar, etc). The
C<Apache::Template> module (available separately from CPAN) is another
front end. That creates a C<Template::Service::Apache> object, calls on
it as required and sends the output back to the relevant
C<Apache::Request> object.
These front-end modules are really only there to handle any specifics
of the environment in which they're being used. The C<Apache::Template>
front end, for example, handles C<Apache::Request> specifics and
configuration via the F<httpd.conf>. The regular L<Template> front-end
deals with C<STDOUT>, variable refs, etc. Otherwise it is
L<Template::Service> (or subclass) which does all the work.
The L<Template::Service> module provides a high-quality template
delivery service, with bells, whistles, signed up service level
agreement and a 30-day no quibble money back guarantee. "Have
a good time, all the time", that's our motto.
Within the lower levels of the Template Toolkit, there are lots of messy
details that we generally don't want to have to worry about most of the time.
Things like templates not being found, or failing to parse correctly, uncaught
exceptions being thrown, missing plugin modules or dependencies, and so on.
L<Template::Service> hides that all away and makes everything look simple to
the outsider. It provides extra features, like C<PRE_PROCESS>, C<PROCESS> and
C<POST_PROCESS>, and also provides the error recovery mechanism via C<ERROR>.
You ask it to process a template and it takes care of everything for you. The
C<Template::Service::Apache> module goes a little bit further, adding some extra
headers to the L<Apache::Request>, setting a few extra template variables, and so
on.
For the most part, the job of a service is really just one of scheduling and
dispatching. It receives a request in the form of a call to its
L<process()|Template::Service#process()> method and schedules the named
template specified as an argument, and possibly several other templates
(C<PRE_PROCESS>, etc) to be processed in order. It doesn't actually process
the templates itself, but instead makes a
L<process()|Template::Context#process()> call against a L<Template::Context>
object.
L<Template::Context> is the runtime engine for the Template Toolkit -
the module that hangs everything together in the lower levels of the
Template Toolkit and that one that does most of the real work, albeit
by crafty delegation to various other friendly helper modules.
Given a template name (or perhaps a reference to a scalar or file
handle) the context process() method must load and compile, or fetch a
cached copy of a previously compiled template, corresponding to that
name. It does this by calling on a list of one or more
L<Template::Provider> objects (the C<LOAD_TEMPLATES> posse) who themselves
might get involved with a L<Template::Parser> to help turn source
templates into executable Perl code (but more on that later).
Thankfully, all of this complexity is hidden away behind a simple
L<template()|Template::Context#template()> method. You call it passing a
template name as an argument, and it returns a compiled template in the form
of a L<Template::Document> object, or otherwise raises an exception.
A L<Template::Document> is a thin object wrapper around a compiled template
subroutine. The object implements a L<process()|Template::Document#process()>
method which performs a little bit of housekeeping and then calls the template
subroutine. The object also defines template metadata (defined in C<[% META
... %]> directives) and has a L<block()|Template::Document#block()> method
which returns a hash of any additional C<[% BLOCK xxxx %]> definitions found
in the template source.
So the context fetches a compiled document via its own
L<template()|Template::Context#template()> method and then gets ready to
process it. It first updates the stash (the place where template variables get
defined - more on that shortly) to set any template variable definitions
specified as the second argument by reference to hash array. Then, it calls
the document L<process()|Template::Document#process()> method, passing a
reference to itself, the context object, as an argument. In doing this, it
provides itself as an object against which template code can make callbacks to
access runtime resources and Template Toolkit functionality.
What we're trying to say here is this: not only does the L<Template::Context>
object receive calls from the I<outside>, i.e. those originating in user
code calling the process() method on a Template object, but it also
receives calls from the I<inside>, i.e. those originating in template
directives of the form C<[% PROCESS template %]>.
Before we move on to that, here's a simple structure diagram showing
the outer layers of the Template Toolkit heading inwards, with pseudo
code annotations showing a typical invocation sequence.
,--------.
| Caller | use Template;
`--------' my $tt = Template->new( ... );
| $tt->process($template, \%vars);
| Outside
- - - | - - - - - - - - - - - - - - - - - - - - - - - - - - - - T T
| package Template; Inside
V
+----------+ sub process($template, \%vars) {
| Template | $out = $self->SERVICE->process($template, $vars);
+----------+ print $out or send it to $self->OUTPUT;
| }
|
| package Template::Service;
|
| sub process($template, \%vars) {
| try {
+----------+ foreach $p in @self->PRE_PROCESS
| Service | $self->CONTEXT->process($p, $vars);
+----------+
| $self->CONTEXT->process($template, $vars);
|
| foreach $p @self->POST_PROCESS
| $self->CONTEXT->process($p, $vars);
| }
| catch {
| $self->CONTEXT->process($self->ERROR);
| }
| }
|
V package Template::Context;
+----------+
| Context | sub process($template, \%vars) {
+----------+ # fetch compiled template
| $template = $self->template($template)
| # update stash
| $self->STASH->update($vars);
| # process template
| $template->process($self)
| }
V
+----------+ package Template::Document;
| Document |
+----------+ sub process($context) {
$output = &{ $self->BLOCK }($context);
}
=head1 Inside Looking Out
To understand more about what's going on in these lower levels, we
need to look at what a compiled template looks like. In fact, a
compiled template is just a regular Perl sub-routine. Here's a very
simple one.
sub my_compiled_template {
return "This is a compiled template.\n";
}
You're unlikely to see a compiled template this simple unless you
wrote it yourself but it is entirely valid. All a template subroutine
is obliged to do is return some output (which may be an empty of
course). If it can't for some reason, then it should raise an error
via C<die()>.
sub my_todo_template {
die "This template not yet implemented\n";
}
If it wants to get fancy, it can raise an error as a
L<Template::Exception> object. An exception object is really just a
convenient wrapper for the 'C<type>' and 'C<info>' fields.
sub my_solilique_template {
die (Template::Exception->new('yorrick', 'Fellow of infinite jest'));
}
Templates generally need to do a lot more than just generate static output or
raise errors. They may want to inspect variable values, process another
template, load a plugin, run a filter, and so on. Whenever a template
subroutine is called, it gets passed a reference to a L<Template::Context>
object. It is through this context object that template code can access the
features of the Template Toolkit.
We described earlier how the L<Template::Service> object calls on
L<Template::Context> to handle a L<process()|Template::Context#process()>
request from the I<outside>. We can make a similar request on a context to
process a template, but from within the code of another template. This is a
call from the I<inside>.
sub my_process_template {
my $context = shift;
my $output = $context->process('header', { title => 'Hello World' })
. "\nsome content\n"
. $context->process('footer');
}
This is then roughly equivalent to a source template something
like this:
[% PROCESS header
title = 'Hello World'
%]
some content
[% PROCESS footer %]
Template variables are stored in, and managed by a L<Template::Stash> object.
This is a blessed hash array in which template variables are defined. The
object wrapper provides L<get()|Template::Stash#get()> and
L<set()|Template::Stash#set()> method which implement all the
I<magical.variable.features> of the Template Toolkit.
Each context object has its own stash, a reference to which can be returned by
the appropriately named L<stash()|Template::Context#stash()> method. So to
print the value of some template variable, or for example, to represent the
following source template:
<title>[% title %]</title>
we might have a subroutine definition something like this:
sub {
my $context = shift;
my $stash = $context->stash();
return '<title>' . $stash->get('title') . '</title>';
}
The stash L<get()|Template::Stash#get()> method hides the details of the
underlying variable types, automatically calling code references, checking
return values, and performing other such tricks. If 'C<title>' happens to be
bound to a subroutine then we can specify additional parameters as a list
reference passed as the second argument to get().
[% title('The Cat Sat on the Mat') %]
This translates to the stash call:
$stash->get([ 'title', ['The Cat Sat on the Mat'] ]);
Dotted compound variables can be requested by passing a single
list reference to the C<get()> method in place of the variable
name. Each pair of elements in the list should correspond to the
variable name and reference to a list of arguments for each
dot-delimited element of the variable.
[% foo(1, 2).bar(3, 4).baz(5) %]
is thus equivalent to
$stash->get([ foo => [1,2], bar => [3,4], baz => [5] ]);
If there aren't any arguments for an element, you can specify an
empty, zero or null argument list.
[% foo.bar %]
$stash->get([ 'foo', 0, 'bar', 0 ]);
The L<set()|Template::Stash#set()> method works in a similar way. It takes a
variable name and a variable value which should be assigned to it.
[% x = 10 %]
$stash->set('x', 10);
[% x.y = 10 %]
$stash->set([ 'x', 0, 'y', 0 ], 10);
So the stash gives us access to template variables and the context provides
the higher level functionality.
Alongside the L<process()|Template::Context#process()> method lies the
L<include()|Template::Context#include()> method. Just as with the C<PROCESS> /
C<INCLUDE> directives, the key difference is in variable localisation. Before
processing a template, the C<process()> method simply updates the stash to set
any new variable definitions, overwriting any existing values. In contrast,
the C<include()> method creates a copy of the existing stash, in a process known
as I<cloning> the stash, and then uses that as a temporary variable store. Any
previously existing variables are still defined, but any changes made to
variables, including setting the new variable values passed aas arguments will
affect only the local copy of the stash (although note that it's only a
shallow copy, so it's not foolproof). When the template has been processed,
the C<include()> method restores the previous variable state by I<decloning> the
stash.
The context also provides an L<insert()|Template::Context#insert()> method to
implement the C<INSERT> directive, but no C<wrapper()> method. This functionality
can be implemented by rewriting the Perl code and calling C<include()>.
[% WRAPPER foo -%]
blah blah [% x %]
[%- END %]
$context->include('foo', {
content => 'blah blah ' . $stash->get('x'),
});
Other than the template processing methods C<process()>, C<include()> and
C<insert()>, the context defines methods for fetching plugin objects,
L<plugin()|Template::Context#plugin()>, and filters,
L<filter()|Template::Context#filter()>.
# TT USE directive
[% USE foo = Bar(10) %]
# equivalent Perl
$stash->set('foo', $context->plugin('Bar', [10]));
# TT FILTER block
[% FILTER bar(20) %]
blah blah blah
[% END %]
# equivalent Perl
my $filter = $context->filter('bar', [20]);
&$filter('blah blah blah');
Pretty much everything else you might want to do in a template can be done in
Perl code. Things like C<IF>, C<UNLESS>, C<FOREACH> and so on all have direct
counterparts in Perl.
# TT IF directive
[% IF msg %]
Message: [% msg %]
[% END %];
# equivalent Perl
if ($stash->get('msg')) {
$output .= 'Message: ';
$output .= $stash->get('msg');
}
The best way to get a better understanding of what's going on underneath
the hood is to set the C<$Template::Parser::DEBUG> flag to a true value
and start processing templates. This will cause the parser to print the
generated Perl code for each template it compiles to C<STDERR>. You'll
probably also want to set the C<$Template::Directive::PRETTY> option to
have the Perl pretty-printed for human consumption.
use Template;
use Template::Parser;
use Template::Directive;
$Template::Parser::DEBUG = 1;
$Template::Directive::PRETTY = 1;
my $template = Template->new();
$template->process(\*DATA, { cat => 'dog', mat => 'log' });
__DATA__
The [% cat %] sat on the [% mat %]
The output sent to C<STDOUT> remains as you would expect:
The dog sat on the log
The output sent to C<STDERR> would look something like this:
compiled main template document block:
sub {
my $context = shift || die "template sub called without context\n";
my $stash = $context->stash;
my $output = '';
my $error;
eval { BLOCK: {
$output .= "The ";
$output .= $stash->get('cat');
$output .= " sat on the ";
$output .= $stash->get('mat');
$output .= "\n";
} };
if ($@) {
$error = $context->catch($@, \$output);
die $error unless $error->type eq 'return';
}
return $output;
}
=head1 Hacking on the Template Toolkit
Please feel free to hack on the Template Toolkit. If you find a bug
that needs fixing, if you have an idea for something that's missing,
or you feel inclined to tackle something on the TODO list, then by all
means go ahead and do it!
If you're contemplating something non-trivial then you'll probably
want to bring it up on the mailing list first to get an idea about the
current state of play, find out if anyone's already working on it, and
so on.
When you start to hack on the Template Toolkit, please make sure you
start from the latest developer release. Stable releases are uploaded
to CPAN and have all-numerical version numbers, e.g. 2.04, 2.05.
Developer releases are available from the Template Toolkit web site
and have a character suffix on the version, e.g. 2.04a, 2.04b, etc.
Once you've made your changes, please remember to update the test
suite by adding extra tests to one of the existing test scripts in
the C<t> sub-directory, or by adding a new test script of your own.
And of course, run C<make test> to ensure that all the tests pass
with your new code.
Don't forget that any files you do add will need to be added to the
MANIFEST. Running C<make manifest> will do this for you, but you need
to make sure you haven't got any other temporary files lying around
that might also get added to it.
Documentation is often something that gets overlooked but it's just as
important as the code. If you're adding a new module, a plugin module, for
example, then it's OK to include the POD documentation in with the module, but
I<please> write it all in one piece at the end of the file, I<after> the code
(just look at any other C<Template::*> module for an example). It's a
religious issue, I know, but I have a strong distaste for POD documentation
interspersed throughout the code. In my not-so-humble opinion, it makes both
the code and the documentation harder to read (same kinda problem as embedding
Perl in HTML).
To share your changes with the rest of the world, you'll need to
prepare a patch file. To do this you should have 2 directories
side-by-side, one which is the original, unmodified distribution
directory for the latest developer release, and the other is a
copy of that same directory which includes your changes.
The following example shows a typical hacking session. First we
unpack the latest developer release.
$ tar zxf Template-Toolkit-2.05c.tar.gz
At this point, it's a good idea to rename the directory to give
some indicate of what it contains.
$ mv Template-Toolkit-2.05c Template-Toolkit-2.05c-abw-xyz-hack
Then go hack!
$ cd Template-Toolkit-2.05c-abw-xyz-hack
[ hacking ]
$ cd ..
When you're all done and ready to prepare a patch, unpack the
distribution archive again so that you've got the original to
C<diff> against your new code.
$ tar zxf Template-Toolkit-2.05c.tar.gz
You should now have an original distribution directory and a modified
version of that same directory, side-by-side.
$ ls
Template-Toolkit-2.05c Template-Toolkit-2.05c-abw-xyz-hack
Now run C<diff> and save the output into an appropriately named patch
file.
$ diff -Naur Template-Toolkit-2.05c Template-Toolkit-2.05c-abw-xyz-hack > patch-TT205c-abw-xyz-hack
You can then post the generated patch file to the mailing list,
describing what it does, why it does it, how it does it and any
other relevant information.
If you want to apply someone else's patch then you should start with the
same original distribution source on which the patch is based. From within
the root of the distribution, run C<patch> feeding in the patch file as
standard input. The 'C<p1>' option is required to strip the first element
of the path name (e.g. C<Template-Toolkit-2.05c/README> becomes C<README> which
is then the correct path).
$ tar zxf Template-Toolkit-2.05c.tar.gz
$ cd Template-Toolkit-2.05c
$ patch -p1 < ../patch-TT205c-abw-xyz-hack
The output generated by C<patch> should be something like the following:
patching file README
patching file lib/Template.pm
patching file lib/Template/Provider.pm
patching file t/provider.t
=cut
# Local Variables:
# mode: perl
# perl-indent-level: 4
# indent-tabs-mode: nil
# End:
#
# vim: expandtab shiftwidth=4:
|