From bcbf441e09fb502cf64924ff2530fa144bdf52c5 Mon Sep 17 00:00:00 2001
From: Andreas Brachold
Date: Mon, 13 Aug 2007 18:41:27 +0000
Subject: * Move files to trunk
---
lib/Template/Base.pm | 314 ++
lib/Template/Config.pm | 467 ++
lib/Template/Constants.pm | 287 ++
lib/Template/Context.pm | 1570 +++++++
lib/Template/Directive.pm | 1004 +++++
lib/Template/Document.pm | 492 +++
lib/Template/Exception.pm | 254 ++
lib/Template/FAQ.pod | 329 ++
lib/Template/Filters.pm | 1448 +++++++
lib/Template/Grammar.pm | 6179 +++++++++++++++++++++++++++
lib/Template/Iterator.pm | 456 ++
lib/Template/Library/HTML.pod | 316 ++
lib/Template/Library/PostScript.pod | 78 +
lib/Template/Library/Splash.pod | 1030 +++++
lib/Template/Manual.pod | 180 +
lib/Template/Manual/Config.pod | 2122 +++++++++
lib/Template/Manual/Credits.pod | 188 +
lib/Template/Manual/Directives.pod | 2179 ++++++++++
lib/Template/Manual/Filters.pod | 529 +++
lib/Template/Manual/Internals.pod | 556 +++
lib/Template/Manual/Intro.pod | 295 ++
lib/Template/Manual/Plugins.pod | 552 +++
lib/Template/Manual/Refs.pod | 171 +
lib/Template/Manual/Syntax.pod | 306 ++
lib/Template/Manual/VMethods.pod | 529 +++
lib/Template/Manual/Variables.pod | 868 ++++
lib/Template/Manual/Views.pod | 642 +++
lib/Template/Modules.pod | 448 ++
lib/Template/Namespace/Constants.pm | 205 +
lib/Template/Parser.pm | 1446 +++++++
lib/Template/Plugin.pm | 409 ++
lib/Template/Plugin/Autoformat.pm | 242 ++
lib/Template/Plugin/CGI.pm | 168 +
lib/Template/Plugin/DBI.pm | 947 ++++
lib/Template/Plugin/Datafile.pm | 198 +
lib/Template/Plugin/Date.pm | 361 ++
lib/Template/Plugin/Directory.pm | 410 ++
lib/Template/Plugin/Dumper.pm | 179 +
lib/Template/Plugin/File.pm | 416 ++
lib/Template/Plugin/Filter.pm | 436 ++
lib/Template/Plugin/Format.pm | 124 +
lib/Template/Plugin/GD/Constants.pm | 138 +
lib/Template/Plugin/GD/Graph/area.pm | 148 +
lib/Template/Plugin/GD/Graph/bars.pm | 191 +
lib/Template/Plugin/GD/Graph/bars3d.pm | 166 +
lib/Template/Plugin/GD/Graph/lines.pm | 178 +
lib/Template/Plugin/GD/Graph/lines3d.pm | 166 +
lib/Template/Plugin/GD/Graph/linespoints.pm | 158 +
lib/Template/Plugin/GD/Graph/mixed.pm | 176 +
lib/Template/Plugin/GD/Graph/pie.pm | 141 +
lib/Template/Plugin/GD/Graph/pie3d.pm | 145 +
lib/Template/Plugin/GD/Graph/points.pm | 155 +
lib/Template/Plugin/GD/Image.pm | 184 +
lib/Template/Plugin/GD/Polygon.pm | 155 +
lib/Template/Plugin/GD/Text.pm | 140 +
lib/Template/Plugin/GD/Text/Align.pm | 147 +
lib/Template/Plugin/GD/Text/Wrap.pm | 183 +
lib/Template/Plugin/HTML.pm | 197 +
lib/Template/Plugin/Image.pm | 425 ++
lib/Template/Plugin/Iterator.pm | 118 +
lib/Template/Plugin/Pod.pm | 116 +
lib/Template/Plugin/Procedural.pm | 170 +
lib/Template/Plugin/String.pm | 796 ++++
lib/Template/Plugin/Table.pm | 464 ++
lib/Template/Plugin/URL.pm | 236 +
lib/Template/Plugin/View.pm | 127 +
lib/Template/Plugin/Wrap.pm | 162 +
lib/Template/Plugin/XML/DOM.pm | 841 ++++
lib/Template/Plugin/XML/RSS.pm | 194 +
lib/Template/Plugin/XML/Simple.pm | 124 +
lib/Template/Plugin/XML/Style.pm | 357 ++
lib/Template/Plugin/XML/XPath.pm | 284 ++
lib/Template/Plugins.pm | 1041 +++++
lib/Template/Provider.pm | 1449 +++++++
lib/Template/Service.pm | 775 ++++
lib/Template/Stash.pm | 1040 +++++
lib/Template/Stash/Context.pm | 791 ++++
lib/Template/Stash/XS.pm | 176 +
lib/Template/Test.pm | 711 +++
lib/Template/Tools/tpage.pod | 76 +
lib/Template/Tools/ttree.pod | 332 ++
lib/Template/Tutorial.pod | 109 +
lib/Template/Tutorial/Datafile.pod | 461 ++
lib/Template/Tutorial/Web.pod | 801 ++++
lib/Template/View.pm | 752 ++++
85 files changed, 45026 insertions(+)
create mode 100644 lib/Template/Base.pm
create mode 100644 lib/Template/Config.pm
create mode 100644 lib/Template/Constants.pm
create mode 100644 lib/Template/Context.pm
create mode 100644 lib/Template/Directive.pm
create mode 100644 lib/Template/Document.pm
create mode 100644 lib/Template/Exception.pm
create mode 100644 lib/Template/FAQ.pod
create mode 100644 lib/Template/Filters.pm
create mode 100644 lib/Template/Grammar.pm
create mode 100644 lib/Template/Iterator.pm
create mode 100644 lib/Template/Library/HTML.pod
create mode 100644 lib/Template/Library/PostScript.pod
create mode 100644 lib/Template/Library/Splash.pod
create mode 100644 lib/Template/Manual.pod
create mode 100644 lib/Template/Manual/Config.pod
create mode 100644 lib/Template/Manual/Credits.pod
create mode 100644 lib/Template/Manual/Directives.pod
create mode 100644 lib/Template/Manual/Filters.pod
create mode 100644 lib/Template/Manual/Internals.pod
create mode 100644 lib/Template/Manual/Intro.pod
create mode 100644 lib/Template/Manual/Plugins.pod
create mode 100644 lib/Template/Manual/Refs.pod
create mode 100644 lib/Template/Manual/Syntax.pod
create mode 100644 lib/Template/Manual/VMethods.pod
create mode 100644 lib/Template/Manual/Variables.pod
create mode 100644 lib/Template/Manual/Views.pod
create mode 100644 lib/Template/Modules.pod
create mode 100644 lib/Template/Namespace/Constants.pm
create mode 100644 lib/Template/Parser.pm
create mode 100644 lib/Template/Plugin.pm
create mode 100644 lib/Template/Plugin/Autoformat.pm
create mode 100644 lib/Template/Plugin/CGI.pm
create mode 100644 lib/Template/Plugin/DBI.pm
create mode 100644 lib/Template/Plugin/Datafile.pm
create mode 100644 lib/Template/Plugin/Date.pm
create mode 100644 lib/Template/Plugin/Directory.pm
create mode 100644 lib/Template/Plugin/Dumper.pm
create mode 100644 lib/Template/Plugin/File.pm
create mode 100644 lib/Template/Plugin/Filter.pm
create mode 100644 lib/Template/Plugin/Format.pm
create mode 100644 lib/Template/Plugin/GD/Constants.pm
create mode 100644 lib/Template/Plugin/GD/Graph/area.pm
create mode 100644 lib/Template/Plugin/GD/Graph/bars.pm
create mode 100644 lib/Template/Plugin/GD/Graph/bars3d.pm
create mode 100644 lib/Template/Plugin/GD/Graph/lines.pm
create mode 100644 lib/Template/Plugin/GD/Graph/lines3d.pm
create mode 100644 lib/Template/Plugin/GD/Graph/linespoints.pm
create mode 100644 lib/Template/Plugin/GD/Graph/mixed.pm
create mode 100644 lib/Template/Plugin/GD/Graph/pie.pm
create mode 100644 lib/Template/Plugin/GD/Graph/pie3d.pm
create mode 100644 lib/Template/Plugin/GD/Graph/points.pm
create mode 100644 lib/Template/Plugin/GD/Image.pm
create mode 100644 lib/Template/Plugin/GD/Polygon.pm
create mode 100644 lib/Template/Plugin/GD/Text.pm
create mode 100644 lib/Template/Plugin/GD/Text/Align.pm
create mode 100644 lib/Template/Plugin/GD/Text/Wrap.pm
create mode 100644 lib/Template/Plugin/HTML.pm
create mode 100644 lib/Template/Plugin/Image.pm
create mode 100644 lib/Template/Plugin/Iterator.pm
create mode 100644 lib/Template/Plugin/Pod.pm
create mode 100644 lib/Template/Plugin/Procedural.pm
create mode 100644 lib/Template/Plugin/String.pm
create mode 100644 lib/Template/Plugin/Table.pm
create mode 100644 lib/Template/Plugin/URL.pm
create mode 100644 lib/Template/Plugin/View.pm
create mode 100644 lib/Template/Plugin/Wrap.pm
create mode 100644 lib/Template/Plugin/XML/DOM.pm
create mode 100644 lib/Template/Plugin/XML/RSS.pm
create mode 100644 lib/Template/Plugin/XML/Simple.pm
create mode 100644 lib/Template/Plugin/XML/Style.pm
create mode 100644 lib/Template/Plugin/XML/XPath.pm
create mode 100644 lib/Template/Plugins.pm
create mode 100644 lib/Template/Provider.pm
create mode 100644 lib/Template/Service.pm
create mode 100644 lib/Template/Stash.pm
create mode 100644 lib/Template/Stash/Context.pm
create mode 100644 lib/Template/Stash/XS.pm
create mode 100644 lib/Template/Test.pm
create mode 100644 lib/Template/Tools/tpage.pod
create mode 100644 lib/Template/Tools/ttree.pod
create mode 100644 lib/Template/Tutorial.pod
create mode 100644 lib/Template/Tutorial/Datafile.pod
create mode 100644 lib/Template/Tutorial/Web.pod
create mode 100644 lib/Template/View.pm
(limited to 'lib/Template')
diff --git a/lib/Template/Base.pm b/lib/Template/Base.pm
new file mode 100644
index 0000000..5f19d78
--- /dev/null
+++ b/lib/Template/Base.pm
@@ -0,0 +1,314 @@
+#============================================================= -*-perl-*-
+#
+# Template::Base
+#
+# DESCRIPTION
+# Base class module implementing common functionality for various other
+# Template Toolkit modules.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+#------------------------------------------------------------------------
+#
+# $Id: Base.pm,v 2.69 2004/01/13 16:19:09 abw Exp $
+#
+#========================================================================
+
+package Template::Base;
+
+require 5.004;
+
+use strict;
+use vars qw( $VERSION );
+use Template::Constants;
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.69 $ =~ /(\d+)\.(\d+)/);
+
+
+#------------------------------------------------------------------------
+# new(\%params)
+#
+# General purpose constructor method which expects a hash reference of
+# configuration parameters, or a list of name => value pairs which are
+# folded into a hash. Blesses a hash into an object and calls its
+# _init() method, passing the parameter hash reference. Returns a new
+# object derived from Template::Base, or undef on error.
+#------------------------------------------------------------------------
+
+sub new {
+ my $class = shift;
+ my ($argnames, @args, $arg, $cfg);
+# $class->error(''); # always clear package $ERROR var?
+
+ { no strict qw( refs );
+ $argnames = \@{"$class\::BASEARGS"} || [ ];
+ }
+
+ # shift off all mandatory args, returning error if undefined or null
+ foreach $arg (@$argnames) {
+ return $class->error("no $arg specified")
+ unless ($cfg = shift);
+ push(@args, $cfg);
+ }
+
+ # fold all remaining args into a hash, or use provided hash ref
+# local $" = ', ';
+# print STDERR "args: [@_]\n";
+ $cfg = defined $_[0] && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ };
+
+ my $self = bless {
+ map { ($_ => shift @args) } @$argnames,
+ _ERROR => '',
+ DEBUG => 0,
+ }, $class;
+
+ return $self->_init($cfg) ? $self : $class->error($self->error);
+}
+
+
+#------------------------------------------------------------------------
+# error()
+# error($msg, ...)
+#
+# May be called as a class or object method to set or retrieve the
+# package variable $ERROR (class method) or internal member
+# $self->{ _ERROR } (object method). The presence of parameters indicates
+# that the error value should be set. Undef is then returned. In the
+# abscence of parameters, the current error value is returned.
+#------------------------------------------------------------------------
+
+sub error {
+ my $self = shift;
+ my $errvar;
+
+ {
+ no strict qw( refs );
+ $errvar = ref $self ? \$self->{ _ERROR } : \${"$self\::ERROR"};
+ }
+ if (@_) {
+ $$errvar = ref($_[0]) ? shift : join('', @_);
+ return undef;
+ }
+ else {
+ return $$errvar;
+ }
+}
+
+
+#------------------------------------------------------------------------
+# _init()
+#
+# Initialisation method called by the new() constructor and passing a
+# reference to a hash array containing any configuration items specified
+# as constructor arguments. Should return $self on success or undef on
+# error, via a call to the error() method to set the error message.
+#------------------------------------------------------------------------
+
+sub _init {
+ my ($self, $config) = @_;
+ return $self;
+}
+
+
+sub DEBUG {
+ my $self = shift;
+ print STDERR "DEBUG: ", @_;
+}
+
+sub debug {
+ my $self = shift;
+ my $msg = join('', @_);
+ my ($pkg, $file, $line) = caller();
+
+ unless ($msg =~ /\n$/) {
+ $msg .= ($self->{ DEBUG } & Template::Constants::DEBUG_CALLER)
+ ? " at $file line $line\n"
+ : "\n";
+ }
+
+ print STDERR "[$pkg] $msg";
+}
+
+
+#------------------------------------------------------------------------
+# module_version()
+#
+# Returns the current version number.
+#------------------------------------------------------------------------
+
+sub module_version {
+ my $self = shift;
+ my $class = ref $self || $self;
+ no strict 'refs';
+ return ${"${class}::VERSION"};
+}
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Base - Base class module implementing common functionality
+
+=head1 SYNOPSIS
+
+ package My::Module;
+ use base qw( Template::Base );
+
+ sub _init {
+ my ($self, $config) = @_;
+ $self->{ doodah } = $config->{ doodah }
+ || return $self->error("No 'doodah' specified");
+ return $self;
+ }
+
+ package main;
+
+ my $object = My::Module->new({ doodah => 'foobar' })
+ || die My::Module->error();
+
+=head1 DESCRIPTION
+
+Base class module which implements a constructor and error reporting
+functionality for various Template Toolkit modules.
+
+=head1 PUBLIC METHODS
+
+=head2 new(\%config)
+
+Constructor method which accepts a reference to a hash array or a list
+of C value> parameters which are folded into a hash. The
+_init() method is then called, passing the configuration hash and should
+return true/false to indicate success or failure. A new object reference
+is returned, or undef on error. Any error message raised can be examined
+via the error() class method or directly via the package variable ERROR
+in the derived class.
+
+ my $module = My::Module->new({ ... })
+ || die My::Module->error(), "\n";
+
+ my $module = My::Module->new({ ... })
+ || die "constructor error: $My::Module::ERROR\n";
+
+=head2 error($msg, ...)
+
+May be called as an object method to get/set the internal _ERROR member
+or as a class method to get/set the $ERROR variable in the derived class's
+package.
+
+ my $module = My::Module->new({ ... })
+ || die My::Module->error(), "\n";
+
+ $module->do_something()
+ || die $module->error(), "\n";
+
+When called with parameters (multiple params are concatenated), this
+method will set the relevant variable and return undef. This is most
+often used within object methods to report errors to the caller.
+
+ package My::Module;
+
+ sub foobar {
+ my $self = shift;
+
+ # some other code...
+
+ return $self->error('some kind of error...')
+ if $some_condition;
+ }
+
+=head2 debug($msg, ...)
+
+Generates a debugging message by concatenating all arguments
+passed into a string and printing it to STDERR. A prefix is
+added to indicate the module of the caller.
+
+ package My::Module;
+
+ sub foobar {
+ my $self = shift;
+
+ $self->debug('called foobar()');
+
+ # some other code...
+ }
+
+When the foobar() method is called, the following message
+is sent to STDERR:
+
+ [My::Module] called foobar()
+
+Objects can set an internal DEBUG value which the debug()
+method will examine. If this value sets the relevant bits
+to indicate DEBUG_CALLER then the file and line number of
+the caller will be appened to the message.
+
+ use Template::Constants qw( :debug );
+
+ my $module = My::Module->new({
+ DEBUG => DEBUG_SERVICE | DEBUG_CONTEXT | DEBUG_CALLER,
+ });
+
+ $module->foobar();
+
+This generates an error message such as:
+
+ [My::Module] called foobar() at My/Module.pm line 6
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+2.69, distributed as part of the
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Config.pm b/lib/Template/Config.pm
new file mode 100644
index 0000000..9a3f378
--- /dev/null
+++ b/lib/Template/Config.pm
@@ -0,0 +1,467 @@
+#============================================================= -*-perl-*-
+#
+# Template::Config
+#
+# DESCRIPTION
+# Template Toolkit configuration module.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+#------------------------------------------------------------------------
+#
+# $Id: Config.pm,v 2.67 2004/01/13 16:19:10 abw Exp $
+#
+#========================================================================
+
+package Template::Config;
+
+require 5.004;
+
+use strict;
+use base qw( Template::Base );
+use vars qw( $VERSION $DEBUG $ERROR $INSTDIR
+ $PARSER $PROVIDER $PLUGINS $FILTERS $ITERATOR
+ $LATEX_PATH $PDFLATEX_PATH $DVIPS_PATH
+ $STASH $SERVICE $CONTEXT $CONSTANTS @PRELOAD );
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.67 $ =~ /(\d+)\.(\d+)/);
+$DEBUG = 0 unless defined $DEBUG;
+$ERROR = '';
+$CONTEXT = 'Template::Context';
+$FILTERS = 'Template::Filters';
+$ITERATOR = 'Template::Iterator';
+$PARSER = 'Template::Parser';
+$PLUGINS = 'Template::Plugins';
+$PROVIDER = 'Template::Provider';
+$SERVICE = 'Template::Service';
+$STASH = 'Template::Stash';
+$CONSTANTS = 'Template::Namespace::Constants';
+
+@PRELOAD = ( $CONTEXT, $FILTERS, $ITERATOR, $PARSER,
+ $PLUGINS, $PROVIDER, $SERVICE, $STASH );
+
+# the following is set at installation time by the Makefile.PL
+$INSTDIR = '';
+
+# LaTeX executable paths set at installation time by the Makefile.PL
+# Empty strings cause the latex(pdf|dvi|ps) filters to throw an error.
+$LATEX_PATH = '';
+$PDFLATEX_PATH = '';
+$DVIPS_PATH = '';
+
+#========================================================================
+# --- CLASS METHODS ---
+#========================================================================
+
+#------------------------------------------------------------------------
+# preload($module, $module, ...)
+#
+# Preloads all the standard TT modules that are likely to be used, along
+# with any other passed as arguments.
+#------------------------------------------------------------------------
+
+sub preload {
+ my $class = shift;
+
+ foreach my $module (@PRELOAD, @_) {
+ $class->load($module) || return;
+ };
+ return 1;
+}
+
+
+#------------------------------------------------------------------------
+# load($module)
+#
+# Load a module via require(). Any occurences of '::' in the module name
+# are be converted to '/' and '.pm' is appended. Returns 1 on success
+# or undef on error. Use $class->error() to examine the error string.
+#------------------------------------------------------------------------
+
+sub load {
+ my ($class, $module) = @_;
+ $module =~ s[::][/]g;
+ $module .= '.pm';
+# print STDERR "loading $module\n"
+# if $DEBUG;
+ eval {
+ require $module;
+ };
+ return $@ ? $class->error("failed to load $module: $@") : 1;
+}
+
+
+#------------------------------------------------------------------------
+# parser(\%params)
+#
+# Instantiate a new parser object of the class whose name is denoted by
+# the package variable $PARSER (default: Template::Parser). Returns
+# a reference to a newly instantiated parser object or undef on error.
+# The class error() method can be called without arguments to examine
+# the error message generated by this failure.
+#------------------------------------------------------------------------
+
+sub parser {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($PARSER);
+ return $PARSER->new($params)
+ || $class->error("failed to create parser: ", $PARSER->error);
+}
+
+
+#------------------------------------------------------------------------
+# provider(\%params)
+#
+# Instantiate a new template provider object (default: Template::Provider).
+# Returns an object reference or undef on error, as above.
+#------------------------------------------------------------------------
+
+sub provider {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($PROVIDER);
+ return $PROVIDER->new($params)
+ || $class->error("failed to create template provider: ",
+ $PROVIDER->error);
+}
+
+
+#------------------------------------------------------------------------
+# plugins(\%params)
+#
+# Instantiate a new plugins provider object (default: Template::Plugins).
+# Returns an object reference or undef on error, as above.
+#------------------------------------------------------------------------
+
+sub plugins {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($PLUGINS);
+ return $PLUGINS->new($params)
+ || $class->error("failed to create plugin provider: ",
+ $PLUGINS->error);
+}
+
+
+#------------------------------------------------------------------------
+# filters(\%params)
+#
+# Instantiate a new filters provider object (default: Template::Filters).
+# Returns an object reference or undef on error, as above.
+#------------------------------------------------------------------------
+
+sub filters {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($FILTERS);
+ return $FILTERS->new($params)
+ || $class->error("failed to create filter provider: ",
+ $FILTERS->error);
+}
+
+
+#------------------------------------------------------------------------
+# iterator(\@list)
+#
+# Instantiate a new Template::Iterator object (default: Template::Iterator).
+# Returns an object reference or undef on error, as above.
+#------------------------------------------------------------------------
+
+sub iterator {
+ my $class = shift;
+ my $list = shift;
+
+ return undef unless $class->load($ITERATOR);
+ return $ITERATOR->new($list, @_)
+ || $class->error("failed to create iterator: ", $ITERATOR->error);
+}
+
+
+#------------------------------------------------------------------------
+# stash(\%vars)
+#
+# Instantiate a new template variable stash object (default:
+# Template::Stash). Returns object or undef, as above.
+#------------------------------------------------------------------------
+
+sub stash {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($STASH);
+ return $STASH->new($params)
+ || $class->error("failed to create stash: ", $STASH->error);
+}
+
+
+#------------------------------------------------------------------------
+# context(\%params)
+#
+# Instantiate a new template context object (default: Template::Context).
+# Returns object or undef, as above.
+#------------------------------------------------------------------------
+
+sub context {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($CONTEXT);
+ return $CONTEXT->new($params)
+ || $class->error("failed to create context: ", $CONTEXT->error);
+}
+
+
+#------------------------------------------------------------------------
+# service(\%params)
+#
+# Instantiate a new template context object (default: Template::Service).
+# Returns object or undef, as above.
+#------------------------------------------------------------------------
+
+sub service {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($SERVICE);
+ return $SERVICE->new($params)
+ || $class->error("failed to create context: ", $SERVICE->error);
+}
+
+
+#------------------------------------------------------------------------
+# constants(\%params)
+#
+# Instantiate a new namespace handler for compile time constant folding
+# (default: Template::Namespace::Constants).
+# Returns object or undef, as above.
+#------------------------------------------------------------------------
+
+sub constants {
+ my $class = shift;
+ my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
+ ? shift : { @_ };
+
+ return undef unless $class->load($CONSTANTS);
+ return $CONSTANTS->new($params)
+ || $class->error("failed to create constants namespace: ",
+ $CONSTANTS->error);
+}
+
+
+#------------------------------------------------------------------------
+# instdir($dir)
+#
+# Returns the root installation directory appended with any local
+# component directory passed as an argument.
+#------------------------------------------------------------------------
+
+sub instdir {
+ my ($class, $dir) = @_;
+ my $inst = $INSTDIR
+ || return $class->error("no installation directory");
+ $inst =~ s[/$][]g;
+ $inst .= "/$dir" if $dir;
+ return $inst;
+}
+
+#------------------------------------------------------------------------
+# latexpaths()
+#
+# Returns a reference to a three element array:
+# [latex_path, pdf2latex_path, dvips_path]
+# These values are determined by Makefile.PL at installation time
+# and are used by the latex(pdf|dvi|ps) filters.
+#------------------------------------------------------------------------
+
+sub latexpaths {
+ return [$LATEX_PATH, $PDFLATEX_PATH, $DVIPS_PATH];
+}
+
+#========================================================================
+# This should probably be moved somewhere else in the long term, but for
+# now it ensures that Template::TieString is available even if the
+# Template::Directive module hasn't been loaded, as is the case when
+# using compiled templates and Template::Parser hasn't yet been loaded
+# on demand.
+#========================================================================
+
+#------------------------------------------------------------------------
+# simple package for tying $output variable to STDOUT, used by perl()
+#------------------------------------------------------------------------
+
+package Template::TieString;
+
+sub TIEHANDLE {
+ my ($class, $textref) = @_;
+ bless $textref, $class;
+}
+sub PRINT {
+ my $self = shift;
+ $$self .= join('', @_);
+}
+
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Config - Factory module for instantiating other TT2 modules
+
+=head1 SYNOPSIS
+
+ use Template::Config;
+
+=head1 DESCRIPTION
+
+This module implements various methods for loading and instantiating
+other modules that comprise the Template Toolkit. It provides a consistent
+way to create toolkit components and allows custom modules to be used in
+place of the regular ones.
+
+Package variables such as $STASH, $SERVICE, $CONTEXT, etc., contain
+the default module/package name for each component (Template::Stash,
+Template::Service and Template::Context, respectively) and are used by
+the various factory methods (stash(), service() and context()) to load
+the appropriate module. Changing these package variables will cause
+subsequent calls to the relevant factory method to load and instantiate
+an object from the new class.
+
+=head1 PUBLIC METHODS
+
+=head2 load($module)
+
+Load a module via require(). Any occurences of '::' in the module name
+are be converted to '/' and '.pm' is appended. Returns 1 on success
+or undef on error. Use $class-Eerror() to examine the error string.
+
+=head2 preload()
+
+This method preloads all the other Template::* modules that are likely
+to be used. It is called by the Template module when running under
+mod_perl ($ENV{MOD_PERL} is set).
+
+=head2 parser(\%config)
+
+Instantiate a new parser object of the class whose name is denoted by
+the package variable $PARSER (default: Template::Parser). Returns
+a reference to a newly instantiated parser object or undef on error.
+
+=head2 provider(\%config)
+
+Instantiate a new template provider object (default: Template::Provider).
+Returns an object reference or undef on error, as above.
+
+=head2 plugins(\%config)
+
+Instantiate a new plugins provider object (default: Template::Plugins).
+Returns an object reference or undef on error, as above.
+
+=head2 filters(\%config)
+
+Instantiate a new filter provider object (default: Template::Filters).
+Returns an object reference or undef on error, as above.
+
+=head2 stash(\%vars)
+
+Instantiate a new stash object (Template::Stash or Template::Stash::XS
+depending on the default set at installation time) using the contents
+of the optional hash array passed by parameter as initial variable
+definitions. Returns an object reference or undef on error, as above.
+
+=head2 context(\%config)
+
+Instantiate a new template context object (default: Template::Context).
+Returns an object reference or undef on error, as above.
+
+=head2 service(\%config)
+
+Instantiate a new template service object (default: Template::Service).
+Returns an object reference or undef on error, as above.
+
+=head2 instdir($dir)
+
+Returns the root directory of the Template Toolkit installation under
+which optional components are installed. Any relative directory specified
+as an argument will be appended to the returned directory.
+
+ # e.g. returns '/usr/local/tt2'
+ my $ttroot = Template::Config->instdir()
+ || die "$Template::Config::ERROR\n";
+
+ # e.g. returns '/usr/local/tt2/templates'
+ my $template = Template::Config->instdir('templates')
+ || die "$Template::Config::ERROR\n";
+
+Returns undef and sets $Template::Config::ERROR appropriately if the
+optional components of the Template Toolkit have not been installed.
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+2.67, distributed as part of the
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Constants.pm b/lib/Template/Constants.pm
new file mode 100644
index 0000000..b227467
--- /dev/null
+++ b/lib/Template/Constants.pm
@@ -0,0 +1,287 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Constants.pm
+#
+# DESCRIPTION
+# Definition of constants for the Template Toolkit.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+#----------------------------------------------------------------------------
+#
+# $Id: Constants.pm,v 2.67 2004/01/13 16:19:10 abw Exp $
+#
+#============================================================================
+
+package Template::Constants;
+
+require 5.004;
+require Exporter;
+
+use strict;
+use vars qw( $VERSION @ISA @EXPORT_OK %EXPORT_TAGS );
+use vars qw( $DEBUG_OPTIONS @STATUS @ERROR @CHOMP @DEBUG);
+
+@ISA = qw( Exporter );
+$VERSION = sprintf("%d.%02d", q$Revision: 2.67 $ =~ /(\d+)\.(\d+)/);
+
+
+#========================================================================
+# ----- EXPORTER -----
+#========================================================================
+
+# STATUS constants returned by directives
+use constant STATUS_OK => 0; # ok
+use constant STATUS_RETURN => 1; # ok, block ended by RETURN
+use constant STATUS_STOP => 2; # ok, stoppped by STOP
+use constant STATUS_DONE => 3; # ok, iterator done
+use constant STATUS_DECLINED => 4; # ok, declined to service request
+use constant STATUS_ERROR => 255; # error condition
+
+# ERROR constants for indicating exception types
+use constant ERROR_RETURN => 'return'; # return a status code
+use constant ERROR_FILE => 'file'; # file error: I/O, parse, recursion
+use constant ERROR_VIEW => 'view'; # view error
+use constant ERROR_UNDEF => 'undef'; # undefined variable value used
+use constant ERROR_PERL => 'perl'; # error in [% PERL %] block
+use constant ERROR_FILTER => 'filter'; # filter error
+use constant ERROR_PLUGIN => 'plugin'; # plugin error
+
+# CHOMP constants for PRE_CHOMP and POST_CHOMP
+use constant CHOMP_NONE => 0; # do not remove whitespace
+use constant CHOMP_ALL => 1; # remove whitespace
+use constant CHOMP_COLLAPSE => 2; # collapse whitespace to a single space
+
+# DEBUG constants to enable various debugging options
+use constant DEBUG_OFF => 0; # do nothing
+use constant DEBUG_ON => 1; # basic debugging flag
+use constant DEBUG_UNDEF => 2; # throw undef on undefined variables
+use constant DEBUG_VARS => 4; # general variable debugging
+use constant DEBUG_DIRS => 8; # directive debugging
+use constant DEBUG_STASH => 16; # general stash debugging
+use constant DEBUG_CONTEXT => 32; # context debugging
+use constant DEBUG_PARSER => 64; # parser debugging
+use constant DEBUG_PROVIDER => 128; # provider debugging
+use constant DEBUG_PLUGINS => 256; # plugins debugging
+use constant DEBUG_FILTERS => 512; # filters debugging
+use constant DEBUG_SERVICE => 1024; # context debugging
+use constant DEBUG_ALL => 2047; # everything
+
+# extra debugging flags
+use constant DEBUG_CALLER => 4096; # add caller file/line
+use constant DEBUG_FLAGS => 4096; # bitmask to extraxt flags
+
+$DEBUG_OPTIONS = {
+ &DEBUG_OFF => off => off => &DEBUG_OFF,
+ &DEBUG_ON => on => on => &DEBUG_ON,
+ &DEBUG_UNDEF => undef => undef => &DEBUG_UNDEF,
+ &DEBUG_VARS => vars => vars => &DEBUG_VARS,
+ &DEBUG_DIRS => dirs => dirs => &DEBUG_DIRS,
+ &DEBUG_STASH => stash => stash => &DEBUG_STASH,
+ &DEBUG_CONTEXT => context => context => &DEBUG_CONTEXT,
+ &DEBUG_PARSER => parser => parser => &DEBUG_PARSER,
+ &DEBUG_PROVIDER => provider => provider => &DEBUG_PROVIDER,
+ &DEBUG_PLUGINS => plugins => plugins => &DEBUG_PLUGINS,
+ &DEBUG_FILTERS => filters => filters => &DEBUG_FILTERS,
+ &DEBUG_SERVICE => service => service => &DEBUG_SERVICE,
+ &DEBUG_ALL => all => all => &DEBUG_ALL,
+ &DEBUG_CALLER => caller => caller => &DEBUG_CALLER,
+};
+
+@STATUS = qw( STATUS_OK STATUS_RETURN STATUS_STOP STATUS_DONE
+ STATUS_DECLINED STATUS_ERROR );
+@ERROR = qw( ERROR_FILE ERROR_VIEW ERROR_UNDEF ERROR_PERL
+ ERROR_RETURN ERROR_FILTER ERROR_PLUGIN );
+@CHOMP = qw( CHOMP_NONE CHOMP_ALL CHOMP_COLLAPSE );
+@DEBUG = qw( DEBUG_OFF DEBUG_ON DEBUG_UNDEF DEBUG_VARS
+ DEBUG_DIRS DEBUG_STASH DEBUG_CONTEXT DEBUG_PARSER
+ DEBUG_PROVIDER DEBUG_PLUGINS DEBUG_FILTERS DEBUG_SERVICE
+ DEBUG_ALL DEBUG_CALLER DEBUG_FLAGS );
+
+@EXPORT_OK = ( @STATUS, @ERROR, @CHOMP, @DEBUG );
+%EXPORT_TAGS = (
+ 'all' => [ @EXPORT_OK ],
+ 'status' => [ @STATUS ],
+ 'error' => [ @ERROR ],
+ 'chomp' => [ @CHOMP ],
+ 'debug' => [ @DEBUG ],
+);
+
+
+sub debug_flags {
+ my ($self, $debug) = @_;
+ my (@flags, $flag, $value);
+ $debug = $self unless defined($debug) || ref($self);
+
+ if ($debug =~ /^\d+$/) {
+ foreach $flag (@DEBUG) {
+ next if $flag =~ /^DEBUG_(OFF|ALL|FLAGS)$/;
+
+ # don't trash the original
+ my $copy = $flag;
+ $flag =~ s/^DEBUG_//;
+ $flag = lc $flag;
+ return $self->error("no value for flag: $flag")
+ unless defined($value = $DEBUG_OPTIONS->{ $flag });
+ $flag = $value;
+
+ if ($debug & $flag) {
+ $value = $DEBUG_OPTIONS->{ $flag };
+ return $self->error("no value for flag: $flag") unless defined $value;
+ push(@flags, $value);
+ }
+ }
+ return wantarray ? @flags : join(', ', @flags);
+ }
+ else {
+ @flags = split(/\W+/, $debug);
+ $debug = 0;
+ foreach $flag (@flags) {
+ $value = $DEBUG_OPTIONS->{ $flag };
+ return $self->error("unknown debug flag: $flag") unless defined $value;
+ $debug |= $value;
+ }
+ return $debug;
+ }
+}
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Constants - Defines constants for the Template Toolkit
+
+=head1 SYNOPSIS
+
+ use Template::Constants qw( :status :error :all );
+
+=head1 DESCRIPTION
+
+The Template::Constants modules defines, and optionally exports into the
+caller's namespace, a number of constants used by the Template package.
+
+Constants may be used by specifying the Template::Constants package
+explicitly:
+
+ use Template::Constants;
+
+ print Template::Constants::STATUS_DECLINED;
+
+Constants may be imported into the caller's namespace by naming them as
+options to the C
+
+Like other block directives, it can be used in side-effect notation:
+
+ [% INSERT legalese.txt WRAPPER big_bold_table %]
+
+It's also possible to specify multiple templates to a WRAPPER directive.
+The specification order indicates outermost to innermost wrapper templates.
+For example, given the following template block definitions:
+
+ [% BLOCK bold %][% content %][% END %]
+ [% BLOCK italic %][% content %][% END %]
+
+the directive
+
+ [% WRAPPER bold+italic %]Hello World[% END %]
+
+would generate the following output:
+
+ Hello World
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=item BLOCK
+
+The BLOCK ... END construct can be used to define template component
+blocks which can be processed with the INCLUDE, PROCESS and WRAPPER
+directives.
+
+ [% BLOCK tabrow %]
+
[% name %]
[% email %]
+ [% END %]
+
+
+ [% PROCESS tabrow name='Fred' email='fred@nowhere.com' %]
+ [% PROCESS tabrow name='Alan' email='alan@nowhere.com' %]
+
+
+A BLOCK definition can be used before it is defined, as long as the
+definition resides in the same file. The block definition itself does
+not generate any output.
+
+ [% PROCESS tmpblk %]
+
+ [% BLOCK tmpblk %] This is OK [% END %]
+
+You can use an anonymous BLOCK to capture the output of a template
+fragment.
+
+ [% julius = BLOCK %]
+ And Caesar's spirit, ranging for revenge,
+ With Ate by his side come hot from hell,
+ Shall in these confines with a monarch's voice
+ Cry 'Havoc', and let slip the dogs of war;
+ That this foul deed shall smell above the earth
+ With carrion men, groaning for burial.
+ [% END %]
+
+Like a named block, it can contain any other template directives which
+are processed when the block is defined. The output generated by the
+block is then assigned to the variable 'julius'.
+
+Anonymous BLOCKs can also be used to define block macros. The
+enclosing block is processed each time the macro is called.
+
+ [% MACRO locate BLOCK %]
+ The [% animal %] sat on the [% place %].
+ [% END %]
+
+ [% locate(animal='cat', place='mat') %] # The cat sat on the mat
+ [% locate(animal='dog', place='log') %] # The dog sat on the log
+
+
+
+=back
+
+=head2 Conditional Processing
+
+=over 4
+
+
+=item IF / UNLESS / ELSIF / ELSE
+
+The IF and UNLESS directives can be used to process or ignore a
+block based on some run-time condition.
+
+ [% IF frames %]
+ [% INCLUDE frameset %]
+ [% END %]
+
+ [% UNLESS text_mode %]
+ [% INCLUDE biglogo %]
+ [% END %]
+
+Multiple conditions may be joined with ELSIF and/or ELSE blocks.
+
+ [% IF age < 10 %]
+ Hello [% name %], does your mother know you're
+ using her AOL account?
+ [% ELSIF age < 18 %]
+ Sorry, you're not old enough to enter
+ (and too dumb to lie about your age)
+ [% ELSE %]
+ Welcome [% name %].
+ [% END %]
+
+The following conditional and boolean operators may be used:
+
+ == != < <= > >= && || ! and or not
+
+Note that C, C and C are also provided as aliases for
+C<&&>, C<||> and C, respectively.
+
+Conditions may be arbitrarily complex and are evaluated with the same
+precedence as in Perl. Parenthesis may be used to explicitly
+determine evaluation order.
+
+ # ridiculously contrived complex example
+ [% IF (name == 'admin' || uid <= 0) && mode == 'debug' %]
+ I'm confused.
+ [% ELSIF more > less %]
+ That's more or less correct.
+ [% END %]
+
+
+
+
+
+
+=item SWITCH / CASE
+
+The SWITCH / CASE construct can be used to perform a multi-way
+conditional test. The SWITCH directive expects an expression which is
+first evaluated and then compared against each CASE statement in turn.
+Each CASE directive should contain a single value or a list of values
+which should match. CASE may also be left blank or written as [% CASE
+DEFAULT %] to specify a default match. Only one CASE matches, there
+is no drop-through between CASE statements.
+
+ [% SWITCH myvar %]
+ [% CASE value1 %]
+ ...
+ [% CASE [ value2 value3 ] %] # multiple values
+ ...
+ [% CASE myhash.keys %] # ditto
+ ...
+ [% CASE %] # default
+ ...
+ [% END %]
+
+
+
+
+=back
+
+=head2 Loop Processing
+
+=over 4
+
+
+=item FOREACH
+
+The FOREACH directive will iterate through the items in a list, processing
+the enclosed block for each one.
+
+ my $vars = {
+ foo => 'Foo',
+ items => [ 'one', 'two', 'three' ],
+ };
+
+template:
+
+ Things:
+ [% FOREACH thing = [ foo 'Bar' "$foo Baz" ] %]
+ * [% thing %]
+ [% END %]
+
+ Items:
+ [% FOREACH i = items %]
+ * [% i %]
+ [% END %]
+
+ Stuff:
+ [% stuff = [ foo "$foo Bar" ] %]
+ [% FOREACH s = stuff %]
+ * [% s %]
+ [% END %]
+
+output:
+
+ Things:
+ * Foo
+ * Bar
+ * Foo Baz
+
+ Items:
+ * one
+ * two
+ * three
+
+ Stuff:
+ * Foo
+ * Foo Bar
+
+You can use also use 'IN' instead of '=' if you prefer.
+
+ [% FOREACH crook IN government %]
+
+When the FOREACH directive is used without specifying a target variable,
+any iterated values which are hash references will be automatically
+imported.
+
+ [% userlist = [
+ { id => 'tom', name => 'Thomas' },
+ { id => 'dick', name => 'Richard' },
+ { id => 'larry', name => 'Lawrence' },
+ ]
+ %]
+
+ [% FOREACH user IN userlist %]
+ [% user.id %] [% user.name %]
+ [% END %]
+
+short form:
+
+ [% FOREACH userlist %]
+ [% id %] [% name %]
+ [% END %]
+
+Note that this particular usage creates a localised variable context
+to prevent the imported hash keys from overwriting any existing
+variables. The imported definitions and any other variables defined
+in such a FOREACH loop will be lost at the end of the loop, when the
+previous context and variable values are restored.
+
+However, under normal operation, the loop variable remains in scope
+after the FOREACH loop has ended (caveat: overwriting any variable
+previously in scope). This is useful as the loop variable is secretly
+an iterator object (see below) and can be used to analyse the last
+entry processed by the loop.
+
+The FOREACH directive can also be used to iterate through the entries
+in a hash array. Each entry in the hash is returned in sorted order
+(based on the key) as a hash array containing 'key' and 'value' items.
+
+ [% users = {
+ tom => 'Thomas',
+ dick => 'Richard',
+ larry => 'Lawrence',
+ }
+ %]
+
+ [% FOREACH u IN users %]
+ * [% u.key %] : [% u.value %]
+ [% END %]
+
+Output:
+
+ * dick : Richard
+ * larry : Lawrence
+ * tom : Thomas
+
+The NEXT directive starts the next iteration in the FOREACH loop.
+
+ [% FOREACH user IN userlist %]
+ [% NEXT IF user.isguest %]
+ Name: [% user.name %] Email: [% user.email %]
+ [% END %]
+
+The LAST directive can be used to prematurely exit the loop. BREAK is
+also provided as an alias for LAST.
+
+ [% FOREACH match IN results.nsort('score').reverse %]
+ [% LAST IF match.score < 50 %]
+ [% match.score %] : [% match.url %]
+ [% END %]
+
+The FOREACH directive is implemented using the Template::Iterator
+module. A reference to the iterator object for a FOREACH directive is
+implicitly available in the 'loop' variable. The following methods
+can be called on the 'loop' iterator.
+
+ size() number of elements in the list
+ max() index number of last element (size - 1)
+ index() index of current iteration from 0 to max()
+ count() iteration counter from 1 to size() (i.e. index() + 1)
+ first() true if the current iteration is the first
+ last() true if the current iteration is the last
+ prev() return the previous item in the list
+ next() return the next item in the list
+
+See L for further details.
+
+Example:
+
+ [% FOREACH item IN [ 'foo', 'bar', 'baz' ] -%]
+ [%- "
+
+Note that the number() method is supported as an alias for count() for
+backwards compatibility but may be deprecated in some future version.
+
+Nested loops will work as expected, with the 'loop' variable correctly
+referencing the innermost loop and being restored to any previous
+value (i.e. an outer loop) at the end of the loop.
+
+ [% FOREACH group IN grouplist;
+ # loop => group iterator
+ "Groups:\n" IF loop.first;
+
+ FOREACH user IN group.userlist;
+ # loop => user iterator
+ "$loop.count: $user.name\n";
+ END;
+
+ # loop => group iterator
+ "End of Groups\n" IF loop.last;
+ END
+ %]
+
+The 'iterator' plugin can also be used to explicitly create an
+iterator object. This can be useful within nested loops where you
+need to keep a reference to the outer iterator within the inner loop.
+The iterator plugin effectively allows you to create an iterator by a
+name other than 'loop'. See Template::Plugin::Iterator for further
+details.
+
+ [% 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 %]
+
+
+
+
+=item WHILE
+
+The WHILE directive can be used to repeatedly process a template block
+while a conditional expression evaluates true. The expression may
+be arbitrarily complex as per IF / UNLESS.
+
+ [% WHILE total < 100 %]
+ ...
+ [% total = calculate_new_total %]
+ [% END %]
+
+An assignment can be enclosed in parenthesis to evaluate the assigned
+value.
+
+ [% WHILE (user = get_next_user_record) %]
+ [% user.name %]
+ [% END %]
+
+The NEXT directive can be used to start the next iteration of a
+WHILE loop and BREAK can be used to exit the loop, both as per FOREACH.
+
+The Template Toolkit uses a failsafe counter to prevent runaway WHILE
+loops which would otherwise never terminate. If the loop exceeds 1000
+iterations then an 'undef' exception will be thrown, reporting the
+error:
+
+ WHILE loop terminated (> 1000 iterations)
+
+The $Template::Directive::WHILE_MAX variable controls this behaviour
+and can be set to a higher value if necessary.
+
+
+=back
+
+=head2 Filters, Plugins, Macros and Perl
+
+=over 4
+
+
+=item FILTER
+
+The FILTER directive can be used to post-process the output of a
+block. A number of standard filters are provided with the Template
+Toolkit. The 'html' filter, for example, escapes the 'E', 'E'
+and '&' characters to prevent them from being interpreted as HTML tags
+or entity reference markers.
+
+ [% FILTER html %]
+ HTML text may have < and > characters embedded
+ which you want converted to the correct HTML entities.
+ [% END %]
+
+output:
+
+ HTML text may have < and > characters embedded
+ which you want converted to the correct HTML entities.
+
+The FILTER directive can also follow various other non-block directives.
+For example:
+
+ [% INCLUDE mytext FILTER html %]
+
+The '|' character can also be used as an alias for 'FILTER'.
+
+ [% INCLUDE mytext | html %]
+
+Multiple filters can be chained together and will be called in sequence.
+
+ [% INCLUDE mytext FILTER html FILTER html_para %]
+
+or
+
+ [% INCLUDE mytext | html | html_para %]
+
+Filters come in two flavours, known as 'static' or 'dynamic'. A
+static filter is a simple subroutine which accepts a text string as
+the only argument and returns the modified text. The 'html' filter is
+an example of a static filter, implemented as:
+
+ sub html_filter {
+ my $text = shift;
+ for ($text) {
+ s/&/&/g;
+ s/</g;
+ s/>/>/g;
+ }
+ return $text;
+ }
+
+Dynamic filters can accept arguments which are specified when the filter
+is called from a template. The 'repeat' filter is such an example,
+accepting a numerical argument which specifies the number of times
+that the input text should be repeated.
+
+ [% FILTER repeat(3) %]blah [% END %]
+
+output:
+
+ blah blah blah
+
+These are implemented as filter 'factories'. The factory subroutine
+is passed a reference to the current Template::Context object along
+with any additional arguments specified. It should then return a
+subroutine reference (e.g. a closure) which implements the filter.
+The 'repeat' filter factory is implemented like this:
+
+ sub repeat_filter_factory {
+ my ($context, $iter) = @_;
+ $iter = 1 unless defined $iter;
+
+ return sub {
+ my $text = shift;
+ $text = '' unless defined $text;
+ return join('\n', $text) x $iter;
+ }
+ }
+
+The FILTERS option, described in L, allows
+custom filters to be defined when a Template object is instantiated.
+The Template::Context define_filter() method allows further filters
+to be defined at any time.
+
+When using a filter, it is possible to assign an alias to it for
+further use. This is most useful for dynamic filters that you want
+to re-use with the same configuration.
+
+ [% FILTER echo = repeat(2) %]
+ Is there anybody out there?
+ [% END %]
+
+ [% FILTER echo %]
+ Mother, should I build a wall?
+ [% END %]
+
+Output:
+
+ Is there anybody out there?
+ Is there anybody out there?
+
+ Mother, should I build a wall?
+ Mother, should I build a wall?
+
+The FILTER directive automatically quotes the name of the filter. As
+with INCLUDE et al, you can use a variable to provide the name of the
+filter, prefixed by '$'.
+
+ [% myfilter = 'html' %]
+ [% FILTER $myfilter %] # same as [% FILTER html %]
+ ...
+ [% END %]
+
+A template variable can also be used to define a static filter
+subroutine. However, the Template Toolkit will automatically call any
+subroutine bound to a variable and use the value returned. Thus, the
+above example could be implemented as:
+
+ my $vars = {
+ myfilter => sub { return 'html' },
+ };
+
+template:
+
+ [% FILTER $myfilter %] # same as [% FILTER html %]
+ ...
+ [% END %]
+
+To define a template variable that evaluates to a subroutine reference
+that can be used by the FILTER directive, you should create a
+subroutine that, when called automatically by the Template Toolkit,
+returns another subroutine reference which can then be used to perform
+the filter operation. Note that only static filters can be
+implemented in this way.
+
+ my $vars = {
+ myfilter => sub { \&my_filter_sub },
+ };
+
+ sub my_filter_sub {
+ my $text = shift;
+ # do something
+ return $text;
+ }
+
+template:
+
+ [% FILTER $myfilter %]
+ ...
+ [% END %]
+
+Alternately, you can bless a subroutine reference into a class (any
+class will do) to fool the Template Toolkit into thinking it's an
+object rather than a subroutine. This will then bypass the automatic
+"call-a-subroutine-to-return-a-value" magic.
+
+ my $vars = {
+ myfilter => bless(\&my_filter_sub, 'anything_you_like'),
+ };
+
+template:
+
+ [% FILTER $myfilter %]
+ ...
+ [% END %]
+
+Filters bound to template variables remain local to the variable
+context in which they are defined. That is, if you define a filter in
+a PERL block within a template that is loaded via INCLUDE, then the
+filter definition will only exist until the end of that template when
+the stash is delocalised, restoring the previous variable state. If
+you want to define a filter which persists for the lifetime of the
+processor, or define additional dynamic filter factories, then you can
+call the define_filter() method on the current Template::Context
+object.
+
+See L for a complete list of available filters,
+their descriptions and examples of use.
+
+
+
+
+
+
+=item USE
+
+The USE directive can be used to load and initialise "plugin"
+extension modules.
+
+ [% USE myplugin %]
+
+A plugin is a regular Perl module that conforms to a particular
+object-oriented interface, allowing it to be loaded into and used
+automatically by the Template Toolkit. For details of this interface
+and information on writing plugins, consult L.
+
+The plugin name is case-sensitive and will be appended to the
+PLUGIN_BASE value (default: 'Template::Plugin') to construct a full
+module name. Any periods, '.', in the name will be converted to '::'.
+
+ [% USE MyPlugin %] # => Template::Plugin::MyPlugin
+ [% USE Foo.Bar %] # => Template::Plugin::Foo::Bar
+
+Various standard plugins are included with the Template Toolkit (see
+below and L). These can be specified in lower
+case and are mapped to the appropriate name.
+
+ [% USE cgi %] # => Template::Plugin::CGI
+ [% USE table %] # => Template::Plugin::Table
+
+Any additional parameters supplied in parenthesis after the plugin
+name will be also be passed to the new() constructor. A reference to
+the current Template::Context object is always passed as the first
+parameter.
+
+ [% USE MyPlugin('foo', 123) %]
+
+equivalent to:
+
+ Template::Plugin::MyPlugin->new($context, 'foo', 123);
+
+Named parameters may also be specified. These are collated into a
+hash which is passed by reference as the last parameter to the
+constructor, as per the general code calling interface.
+
+ [% USE url('/cgi-bin/foo', mode='submit', debug=1) %]
+
+equivalent to:
+
+ Template::Plugin::URL->new($context, '/cgi-bin/foo'
+ { mode => 'submit', debug => 1 });
+
+The plugin may represent any data type; a simple variable, hash, list or
+code reference, but in the general case it will be an object reference.
+Methods can be called on the object (or the relevant members of the
+specific data type) in the usual way:
+
+ [% USE table(mydata, rows=3) %]
+
+ [% FOREACH row = table.rows %]
+
+
+=head2 html_break / html_para_break
+
+Similar to the html_para filter described above, but uses the HTML tag
+sequence EbrEEbrE to join paragraphs.
+
+ [% FILTER html_break %]
+ The cat sat on the mat.
+
+ Mary had a little lamb.
+ [% END %]
+
+output:
+
+ The cat sat on the mat.
+
+
+ Mary had a little lamb.
+
+=head2 html_line_break
+
+This filter replaces any newlines with EbrE HTML tags,
+thus preserving the line breaks of the original text in the
+HTML output.
+
+ [% FILTER html_line_break %]
+ The cat sat on the mat.
+ Mary had a little lamb.
+ [% END %]
+
+output:
+
+ The cat sat on the mat.
+ Mary had a little lamb.
+
+=head2 uri
+
+This filter URI escapes the input text, converting any characters
+outside of the permitted URI character set (as defined by RFC 2396)
+into a C<%nn> hex escape.
+
+ [% 'my file.html' | uri %]
+
+output:
+
+ my%20file.html
+
+Note that URI escaping isn't always enough when generating hyperlinks in
+an HTML document. The C<&> character, for example, is valid in a URI and
+will not be escaped by the URI filter. In this case you should also filter
+the text through the 'html' filter.
+
+ click here
+
+=head2 indent(pad)
+
+Indents the text block by a fixed pad string or width. The 'pad' argument
+can be specified as a string, or as a numerical value to indicate a pad
+width (spaces). Defaults to 4 spaces if unspecified.
+
+ [% FILTER indent('ME> ') %]
+ blah blah blah
+ cabbages, rhubard, onions
+ [% END %]
+
+output:
+
+ ME> blah blah blah
+ ME> cabbages, rhubard, onions
+
+=head2 truncate(length)
+
+Truncates the text block to the length specified, or a default length of
+32. Truncated text will be terminated with '...' (i.e. the '...' falls
+inside the required length, rather than appending to it).
+
+ [% FILTER truncate(21) %]
+ I have much to say on this matter that has previously
+ been said on more than one occasion.
+ [% END %]
+
+output:
+
+ I have much to say...
+
+=head2 repeat(iterations)
+
+Repeats the text block for as many iterations as are specified (default: 1).
+
+ [% FILTER repeat(3) %]
+ We want more beer and we want more beer,
+ [% END %]
+ We are the more beer wanters!
+
+output:
+
+ We want more beer and we want more beer,
+ We want more beer and we want more beer,
+ We want more beer and we want more beer,
+ We are the more beer wanters!
+
+=head2 remove(string)
+
+Searches the input text for any occurrences of the specified string and
+removes them. A Perl regular expression may be specified as the search
+string.
+
+ [% "The cat sat on the mat" FILTER remove('\s+') %]
+
+output:
+
+ Thecatsatonthemat
+
+=head2 replace(search, replace)
+
+Similar to the remove filter described above, but taking a second parameter
+which is used as a replacement string for instances of the search string.
+
+ [% "The cat sat on the mat" | replace('\s+', '_') %]
+
+output:
+
+ The_cat_sat_on_the_mat
+
+=head2 redirect(file, options)
+
+The 'redirect' filter redirects the output of the block into a separate
+file, specified relative to the OUTPUT_PATH configuration item.
+
+ [% FOREACH user = myorg.userlist %]
+ [% FILTER redirect("users/${user.id}.html") %]
+ [% INCLUDE userinfo %]
+ [% END %]
+ [% END %]
+
+or more succinctly, using side-effect notation:
+
+ [% INCLUDE userinfo
+ FILTER redirect("users/${user.id}.html")
+ FOREACH user = myorg.userlist
+ %]
+
+A 'file' exception will be thrown if the OUTPUT_PATH option is undefined.
+
+An optional 'binmode' argument can follow the filename to explicitly set
+the output file to binary mode.
+
+ [% PROCESS my/png/generator
+ FILTER redirect("images/logo.png", binmode=1) %]
+
+For backwards compatibility with earlier versions, a single true/false
+value can be used to set binary mode.
+
+ [% PROCESS my/png/generator
+ FILTER redirect("images/logo.png", 1) %]
+
+For the sake of future compatibility and clarity, if nothing else, we
+would strongly recommend you explicitly use the named 'binmode' option
+as shown in the first example.
+
+=head2 eval / evaltt
+
+The 'eval' filter evaluates the block as template text, processing
+any directives embedded within it. This allows template variables to
+contain template fragments, or for some method to be provided for
+returning template fragments from an external source such as a
+database, which can then be processed in the template as required.
+
+ my $vars = {
+ fragment => "The cat sat on the [% place %]",
+ };
+ $template->process($file, $vars);
+
+The following example:
+
+ [% fragment | eval %]
+
+is therefore equivalent to
+
+ The cat sat on the [% place %]
+
+The 'evaltt' filter is provided as an alias for 'eval'.
+
+=head2 perl / evalperl
+
+The 'perl' filter evaluates the block as Perl code. The EVAL_PERL
+option must be set to a true value or a 'perl' exception will be
+thrown.
+
+ [% my_perl_code | perl %]
+
+In most cases, the [% PERL %] ... [% END %] block should suffice for
+evaluating Perl code, given that template directives are processed
+before being evaluate as Perl. Thus, the previous example could have
+been written in the more verbose form:
+
+ [% PERL %]
+ [% my_perl_code %]
+ [% END %]
+
+as well as
+
+ [% FILTER perl %]
+ [% my_perl_code %]
+ [% END %]
+
+The 'evalperl' filter is provided as an alias for 'perl' for backwards
+compatibility.
+
+=head2 stdout(options)
+
+The stdout filter prints the output generated by the enclosing block to
+STDOUT. The 'binmode' option can be passed as either a named parameter
+or a single argument to set STDOUT to binary mode (see the
+binmode perl function).
+
+ [% PROCESS something/cool
+ FILTER stdout(binmode=1) # recommended %]
+
+ [% PROCESS something/cool
+ FILTER stdout(1) # alternate %]
+
+The stdout filter can be used to force binmode on STDOUT, or also inside
+redirect, null or stderr blocks to make sure that particular output goes
+to stdout. See the null filter below for an example.
+
+=head2 stderr
+
+The stderr filter prints the output generated by the enclosing block to
+STDERR.
+
+=head2 null
+
+The null filter prints nothing. This is useful for plugins whose
+methods return values that you don't want to appear in the output.
+Rather than assigning every plugin method call to a dummy variable
+to silence it, you can wrap the block in a null filter:
+
+ [% FILTER null;
+ USE im = GD.Image(100,100);
+ black = im.colorAllocate(0, 0, 0);
+ red = im.colorAllocate(255,0, 0);
+ blue = im.colorAllocate(0, 0, 255);
+ im.arc(50,50,95,75,0,360,blue);
+ im.fill(50,50,red);
+ im.png | stdout(1);
+ END;
+ -%]
+
+Notice the use of the stdout filter to ensure that a particular expression
+generates output to stdout (in this case in binary mode).
+
+=head2 latex(outputType)
+
+Passes the text block to LaTeX and produces either PDF, DVI or
+PostScript output. The 'outputType' argument determines the output
+format and it should be set to one of the strings: "pdf" (default),
+"dvi", or "ps".
+
+The text block should be a complete LaTeX source file.
+
+ [% FILTER latex("pdf") -%]
+ \documentclass{article}
+
+ \begin{document}
+
+ \title{A Sample TT2 \LaTeX\ Source File}
+ \author{Craig Barratt}
+ \maketitle
+
+ \section{Introduction}
+ This is some text.
+
+ \end{document}
+ [% END -%]
+
+The output will be a PDF file. You should be careful not to prepend or
+append any extraneous characters or text outside the FILTER block,
+since this text will wrap the (binary) output of the latex filter.
+Notice the END directive uses '-%]' for the END_TAG to remove the
+trailing new line.
+
+One example where you might prepend text is in a CGI script where
+you might include the Content-Type before the latex output, eg:
+
+ Content-Type: application/pdf
+
+ [% FILTER latex("pdf") -%]
+ \documentclass{article}
+ \begin{document}
+ ...
+ \end{document}
+ [% END -%]
+
+In other cases you might use the redirect filter to put the output
+into a file, rather than delivering it to stdout. This might be
+suitable for batch scripts:
+
+ [% output = FILTER latex("pdf") -%]
+ \documentclass{article}
+ \begin{document}
+ ...
+ \end{document}
+ [% END; output | redirect("document.pdf", 1) -%]
+
+(Notice the second argument to redirect to force binary mode.)
+
+Note that the latex filter runs one or two external programs, so it
+isn't very fast. But for modest documents the performance is adequate,
+even for interactive applications.
+
+A error of type 'latex' will be thrown if there is an error reported
+by latex, pdflatex or dvips.
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Internals.pod b/lib/Template/Manual/Internals.pod
new file mode 100644
index 0000000..b8cf80b
--- /dev/null
+++ b/lib/Template/Manual/Internals.pod
@@ -0,0 +1,556 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::Internals
+#
+# DESCRIPTION
+# This document provides an overview of the internal architecture of
+# the Template Toolkit. It is a work in progress and is far from
+# complete, currently providing little more than an overview of how
+# the major components fit together. Nevertheless, it's a good
+# starting point for anyone wishing to delve into the source code to
+# find out how it all works.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::Internals - Template Toolkit internals
+
+=head1 DESCRIPTION
+
+This document provides an overview of the internal architecture of the
+Template Toolkit. It is a work in progress and is far from complete,
+currently providing little more than an overview of how the major
+components fit together. Nevertheless, it's a good starting point for
+anyone wishing to delve into the source code to find out how it all
+works.
+
+=head2 Outside Looking In
+
+The B module is simply a front end module which creates and
+uses a Template::Service and pipes the output wherever you want it to
+go (STDOUT by default, or maybe a file, scalar, etc). The
+Apache::Template module (available separately from CPAN) is another
+front end. That creates a Template::Service::Apache object, calls on
+it as required and sends the output back to the relevant
+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 Apache::Template
+front end, for example, handles Apache::Request specifics and
+configuration via the httpd.conf. The regular Template front-end
+deals with STDOUT, variable refs, etc. Otherwise it is
+Template::Service (or subclass) which does all the work.
+
+The B 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. Template::Service hides that all
+away and makes everything look simple to the outsider. It provides
+extra features, like PRE_PROCESS, PROCESS and POST_PROCESS, and also
+provides the error recovery mechanism via ERROR. You ask it to
+process a template and it takes care of everything for you. The
+Template::Service::Apache module goes a little bit further, adding
+some extra headers to the 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 process() method and schedules the named template
+specified as an argument, and possibly several other templates
+(PRE_PROCESS, etc) to be processed in order. It doesn't actually
+process the templates itself, but instead makes a process() call
+against a Template::Context object.
+
+B 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
+Template::Provider objects (the LOAD_TEMPLATES posse) who themselves
+might get involved with a 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 template()
+method. You call it passing a template name as an argument, and it
+returns a compiled template in the form of a Template::Document
+object, or otherwise raises an exception.
+
+A B is a thin object wrapper around a compiled
+template subroutine. The object implements a 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 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 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 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 Template::Context
+object receive calls from the I, i.e. those originating in user
+code calling the process() method on a Template object, but it also
+receives calls from the I, 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);
+ }
+
+
+=head2 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 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
+Template::Exception object. An exception object is really just a
+convenient wrapper for the 'type' and '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 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 Template::Service object calls on
+Template::Context to handle a process() request from the I.
+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.
+
+ 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 B
+object. This is a blessed hash array in which template variables are
+defined. The object wrapper provides get() and set() method which
+implement all the 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 stash() method. So to print the
+value of some template variable, or for example, to represent the
+following source template:
+
+ [% title %]
+
+we might have a subroutine definition something like this:
+
+ sub {
+ my $context = shift;
+ my $stash = $context->stash();
+ return '' . $stash->get('title') . '';
+ }
+
+The stash get() method hides the details of the underlying variable
+types, automatically calling code references, checking return values,
+and performing other such tricks. If '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 get() call:
+
+ $stash->get([ 'title', ['The Cat Sat on the Mat'] ]);
+
+Dotted compound variables can be requested by passing a single
+list reference to the 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 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 process()
+method lies the include() method. Just as with the PROCESS / INCLUDE
+directives, the key difference is in variable localisation. Before
+processing a template, the process() method simply updates the stash
+to set any new variable definitions, overwriting any existing values.
+In contrast, the include() method creates a copy of the existing
+stash, in a process known as I 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 include()
+method restores the previous variable state by I the stash.
+
+The context also provides an insert() method to implement the INSERT
+directive, but no wrapper() method. This functionality can be implemented
+by rewriting the Perl code and calling include().
+
+ [% WRAPPER foo -%]
+ blah blah [% x %]
+ [%- END %]
+
+ $context->include('foo', {
+ content => 'blah blah ' . $stash->get('x'),
+ });
+
+Other than the template processing methods process(), include() and insert(),
+the context defines methods for fetching plugin objects, plugin(), and
+filters, filter().
+
+ [% USE foo = Bar(10) %]
+
+ $stash->set('foo', $context->plugin('Bar', [10]));
+
+ [% FILTER bar(20) %]
+ blah blah blah
+ [% END %]
+
+ 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 IF, UNLESS, FOREACH and so on all have direct
+counterparts in Perl.
+
+ [% IF msg %]
+ Message: [% msg %]
+ [% END %];
+
+ 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 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 STDOUT remains as you would expect:
+
+ The dog sat on the log
+
+The output sent to 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 't' sub-directory, or by adding a new test script of your own.
+And of course, run C 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 '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 updating existing documentation
+then you should download the 'docsrc' bundle from which all the
+Template Toolkit documentation is built and make your changes in there.
+It's also available from the Template Toolkit web site. See the
+README distributed in the archive for further information.
+
+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
+write it all in one piece at the end of the file, I the code
+(just look at any other 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).
+
+Aesthetics aside, if I do want to extract the documentation into the
+docsrc bundle then it's easy for me to do it if it's all written in
+one chunk and extremely tedious if not. So for practical reasons
+alone, please keep Perl and POD sections separate. Comment blocks
+within the code are of course welcome.
+
+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
+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 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 'patch' feeding in the patch file as
+standard input. The 'p1' option is required to strip the first element
+of the path name (e.g. Template-Toolkit-2.05c/README becomes 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 '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
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Intro.pod b/lib/Template/Manual/Intro.pod
new file mode 100644
index 0000000..c50c9e8
--- /dev/null
+++ b/lib/Template/Manual/Intro.pod
@@ -0,0 +1,295 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::Intro
+#
+# DESCRIPTION
+# This section provides a general introduction to the Template
+# Toolkit, giving a quick overview of features, examples of template
+# directives and use of the Template.pm module. It also described the
+# basic concept underlying the toolkit: the separation of
+# presentation elements from application logic and data.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::Intro - Introduction to the Template Toolkit
+
+=head1 DESCRIPTION
+
+This section provides a general introduction to the Template Toolkit,
+giving a quick overview of features, examples of template directives
+and use of the Template.pm module. It also described the basic concept
+underlying the toolkit: the separation of presentation elements from
+application logic and data.
+
+The Template Toolkit is a collection of modules which implement a
+fast, flexible, powerful and extensible template processing system.
+It was originally designed and remains primarily useful for generating
+dynamic web content, but it can be used equally well for processing
+any kind of text documents. This POD documentation is all generated
+using the Template Toolkit batch mode utility F, for example.
+
+At the simplest level it provides an easy way to process template
+files, filling in embedded variable references with their equivalent
+values.
+
+ 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.
+
+By default, template directives are embedded within the character
+sequences '[%' ... '%]' but you can change these and various other
+options to configure how the Template Toolkit looks, feels and works.
+You can set the INTERPOLATE option, for example, if you prefer to
+embed your variables in Perl style:
+
+ Dear $name,
+
+ It has come to our attention that your account is in
+ arrears to the sum of $debt.
+ ...
+
+=head2 Template.pm
+
+The Template.pm module is the front end to the Template Toolkit,
+providing access to the full range of functionality through a single
+module with a simple interface. It loads the other modules as
+required and instantiates a default set of objects to handle
+subsequent template processing requests. Configuration parameters may
+be passed to the Template.pm constructor, new(), which are then used
+to configure the underlying objects.
+
+ use Template;
+
+ my $tt = Template->new({
+ INCLUDE_PATH => '/usr/local/templates',
+ INTERPOLATE => 1,
+ }) || die "$Template::ERROR\n";
+
+The Template object implements a process() method for processing template
+files or text. The name of the input template (or various other sources)
+is passed as the first argument, followed by a reference to a hash array
+of variable definitions for substitution in the template.
+
+ 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";
+
+
+The process() method returns true (1) on success and prints the
+template output to STDOUT, by default. On error, the process() method
+returns false (undef). The error() method can then be called to
+retrieve details of the error.
+
+=head2 Component Based Content Construction
+
+A number of special directives are provided, such as INSERT, INCLUDE
+and PROCESS, which allow content to be built up from smaller template
+components. This permits a modular approach to building a web site or
+other content repository, promoting reusability, cross-site
+consistency, ease of construction and subsequent maintenance. Common
+elements such as headers, footers, menu bars, tables, and so on, can
+be created as separate template files which can then be processed into
+other documents as required. All defined variables are inherited by
+these templates along with any additional "local" values specified.
+
+ [% PROCESS header
+ title = "The Cat Sat on the Mat"
+ %]
+
+ [% PROCESS menu %]
+
+ The location of the missing feline has now been established.
+ Thank you for your assistance.
+
+ [% INSERT legal/disclaimer %]
+
+ [% PROCESS footer %]
+
+You can also define a template as a BLOCK within the same file and
+PROCESS it just like any other template file. This can be invaluable
+for building up repetitive elements such as tables, menus, etc.
+
+ [% BLOCK tabrow %]
+
[% name %]
[% email %]
+ [% END %]
+
+
+ [% PROCESS tabrow name="tom" email="tom@here.org" %]
+ [% PROCESS tabrow name="dick" email="disk@there.org" %]
+ [% PROCESS tabrow name="larry" email="larry@where.org" %]
+
+
+=head2 Data and Code Binding
+
+One of the key features that sets the Template Toolkit apart from
+other template processors is the ability to bind template variables to
+any kind of Perl data: scalars, lists, hash arrays, sub-routines and
+objects.
+
+ my $vars = {
+ root => 'http://here.com/there',
+ menu => [ 'modules', 'authors', 'scripts' ],
+ client => {
+ name => 'Doctor Joseph von Satriani',
+ id => 'JVSAT',
+ },
+ checkout => sub { my $total = shift; ...; return $something },
+ shopcart => My::Cool::Shopping::Cart->new(),
+ };
+
+The Template Toolkit will automatically Do The Right Thing to access
+the data in an appropriate manner to return some value which can then
+be output. The dot operator '.' is used to access into lists and
+hashes or to call object methods. The FOREACH directive is provided for
+iterating through lists, and various logical tests are available using
+directives such as IF, UNLESS, ELSIF, ELSE, SWITCH, CASE, etc.
+
+ [% FOREACH section = menu %]
+ [% section %]
+ [% END %]
+
+ Client: [% client.name %] (id: [% client.id %])
+
+ [% IF shopcart.nitems %]
+ Your shopping cart contains the following items:
+
+
+ [% checkout(shopcart.total) %]
+
+ [% ELSE %]
+ No items currently in shopping cart.
+ [% END %]
+
+=head2 Advanced Features: Filters, Macros, Exceptions, Plugins
+
+The Template Toolkit also provides a number of additional directives
+for advanced processing and programmatical functionality. It supports
+output filters (FILTER), allows custom macros to be defined (MACRO),
+has a fully-featured exception handling system (TRY, THROW, CATCH,
+FINAL) and supports a plugin architecture (USE) which allows special
+plugin modules and even regular Perl modules to be loaded and used
+with the minimum of fuss. The Template Toolkit is "just" a template
+processor but you can trivially extend it to incorporate the
+functionality of any Perl module you can get your hands on. Thus, it
+is also a scalable and extensible template framework, ideally suited
+for managing the presentation layer for application servers, content
+management systems and other web applications.
+
+=head2 Separating Presentation and Application Logic
+
+Rather than embedding Perl code or some other scripting language
+directly into template documents, it encourages you to keep functional
+components (i.e. Perl code) separate from presentation components
+(e.g. HTML templates). The template variables provide the interface
+between the two layers, allowing data to be generated in code and then
+passed to a template component for displaying (pipeline model) or for
+sub-routine or object references to be bound to variables which can
+then be called from the template as and when required (callback
+model).
+
+The directives that the Template Toolkit provide implement their own
+mini programming language, but they're not really designed for
+serious, general purpose programming. Perl is a far more appropriate
+language for that. If you embed application logic (e.g. Perl or other
+scripting language fragments) in HTML templates then you risk losing
+the clear separation of concerns between functionality and
+presentation. It becomes harder to maintain the two elements in
+isolation and more difficult, if not impossible, to reuse code or
+presentation elements by themselves. It is far better to write your
+application code in separate Perl modules, libraries or scripts and
+then use templates to control how the resulting data is presented as
+output. Thus you should think of the Template Toolkit language as a
+set of layout directives for displaying data, not calculating it.
+
+Having said that, the Template Toolkit doesn't force you into one
+approach or the other. It attempts to be pragmatic rather than
+dogmatic in allowing you to do whatever best gets the job done.
+Thus, if you enable the EVAL_PERL option then you can happily embed
+real Perl code in your templates within PERL ... END directives.
+
+=head2 Performance
+
+The Template Toolkit uses a fast YACC-like parser which compiles
+templates into Perl code for maximum runtime efficiency. It also has
+an advanced caching mechanism which manages in-memory and on-disk
+(i.e. persistent) versions of compiled templates. The modules that
+comprise the toolkit are highly configurable and the architecture
+around which they're built is designed to be extensible. The Template
+Toolkit provides a powerful framework around which content creation
+and delivery systems can be built while also providing a simple
+interface through the Template front-end module for general use.
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Plugins.pod b/lib/Template/Manual/Plugins.pod
new file mode 100644
index 0000000..7955640
--- /dev/null
+++ b/lib/Template/Manual/Plugins.pod
@@ -0,0 +1,552 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::Plugins
+#
+# DESCRIPTION
+# This section lists the standard plugins which can be used to extend
+# the runtime functionality of the Template Toolkit. The plugins are
+# distributed with the Template Toolkit but may required additional
+# modules from CPAN.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::Plugins - Standard plugins
+
+=head1 DESCRIPTION
+
+This section lists the standard plugins which can be used to extend the
+runtime functionality of the Template Toolkit. The plugins are
+distributed with the Template Toolkit but may required additional
+modules from CPAN.
+
+
+
+=head1 TEMPLATE TOOLKIT PLUGINS
+
+The following plugin modules are distributed with the Template
+Toolkit. Some of the plugins interface to external modules (detailed
+below) which should be downloaded from any CPAN site and installed
+before using the plugin.
+
+=head2 Autoformat
+
+The Autoformat plugin is an interface to Damian Conway's Text::Autoformat
+Perl module which provides advanced text wrapping and formatting. See
+L and L for further
+details.
+
+ [% USE autoformat(left=10, right=20) %]
+ [% autoformat(mytext) %] # call autoformat sub
+ [% mytext FILTER autoformat %] # or use autoformat filter
+
+The Text::Autoformat module is available from CPAN:
+
+ http://www.cpan.org/modules/by-module/Text/
+
+=head2 CGI
+
+The CGI plugin is a wrapper around Lincoln Stein's
+Elstein@genome.wi.mit.eduE CGI.pm module. The plugin is
+distributed with the Template Toolkit (see L)
+and the CGI module itself is distributed with recent versions Perl,
+or is available from CPAN.
+
+ [% USE CGI %]
+ [% CGI.param('param_name') %]
+ [% CGI.start_form %]
+ [% CGI.popup_menu( Name => 'color',
+ Values => [ 'Green', 'Brown' ] ) %]
+ [% CGI.end_form %]
+
+=head2 Datafile
+
+Provides an interface to data stored in a plain text file in a simple
+delimited format. The first line in the file specifies field names
+which should be delimiter by any non-word character sequence.
+Subsequent lines define data using the same delimiter as int he first
+line. Blank lines and comments (lines starting '#') are ignored. See
+L for further details.
+
+/tmp/mydata:
+
+ # define names for each field
+ id : email : name : tel
+ # here's the data
+ fred : fred@here.com : Fred Smith : 555-1234
+ bill : bill@here.com : Bill White : 555-5678
+
+example:
+
+ [% USE userlist = datafile('/tmp/mydata') %]
+
+ [% FOREACH user = userlist %]
+ [% user.name %] ([% user.id %])
+ [% END %]
+
+=head2 Date
+
+The Date plugin provides an easy way to generate formatted time and date
+strings by delegating to the POSIX strftime() routine. See
+L and L for further details.
+
+ [% USE date %]
+ [% date.format %] # current time/date
+
+ File last modified: [% date.format(template.modtime) %]
+
+=head2 Directory
+
+The Directory plugin provides a simple interface to a directory and
+the files within it. See L for further
+details.
+
+ [% USE dir = Directory('/tmp') %]
+ [% FOREACH file = dir.files %]
+ # all the plain files in the directory
+ [% END %]
+ [% FOREACH file = dir.dirs %]
+ # all the sub-directories
+ [% END %]
+
+=head2 DBI
+
+The DBI plugin, developed by Simon Matthews
+Esam@knowledgepool.comE, brings the full power of Tim Bunce's
+ETim.Bunce@ig.co.ukE database interface module (DBI) to your
+templates. See L and L for further details.
+
+ [% USE DBI('dbi:driver:database', 'user', 'pass') %]
+
+ [% FOREACH user = DBI.query( 'SELECT * FROM users' ) %]
+ [% user.id %] [% user.name %]
+ [% END %]
+
+The DBI and relevant DBD modules are available from CPAN:
+
+ http://www.cpan.org/modules/by-module/DBI/
+
+=head2 Dumper
+
+The Dumper plugin provides an interface to the Data::Dumper module. See
+L and L for futher details.
+
+ [% USE dumper(indent=0, pad=" ") %]
+ [% dumper.dump(myvar, yourvar) %]
+
+=head2 File
+
+The File plugin provides a general abstraction for files and can be
+used to fetch information about specific files within a filesystem.
+See L for further details.
+
+ [% USE File('/tmp/foo.html') %]
+ [% File.name %] # foo.html
+ [% File.dir %] # /tmp
+ [% File.mtime %] # modification time
+
+=head2 Filter
+
+This module implements a base class plugin which can be subclassed
+to easily create your own modules that define and install new filters.
+
+ package MyOrg::Template::Plugin::MyFilter;
+
+ use Template::Plugin::Filter;
+ use base qw( Template::Plugin::Filter );
+
+ sub filter {
+ my ($self, $text) = @_;
+
+ # ...mungify $text...
+
+ return $text;
+ }
+
+ # now load it...
+ [% USE MyFilter %]
+
+ # ...and use the returned object as a filter
+ [% FILTER $MyFilter %]
+ ...
+ [% END %]
+
+See L for further details.
+
+=head2 Format
+
+The Format plugin provides a simple way to format text according to a
+printf()-like format. See L for further
+details.
+
+ [% USE bold = format('%s') %]
+ [% bold('Hello') %]
+
+=head2 GD::Image, GD::Polygon, GD::Constants
+
+These plugins provide access to the GD graphics library via Lincoln
+D. Stein's GD.pm interface. These plugins allow PNG, JPEG and other
+graphical formats to be generated.
+
+ [% FILTER null;
+ USE im = GD.Image(100,100);
+ # allocate some colors
+ black = im.colorAllocate(0, 0, 0);
+ red = im.colorAllocate(255,0, 0);
+ blue = im.colorAllocate(0, 0, 255);
+ # Draw a blue oval
+ im.arc(50,50,95,75,0,360,blue);
+ # And fill it with red
+ im.fill(50,50,red);
+ # Output image in PNG format
+ im.png | stdout(1);
+ END;
+ -%]
+
+See L for further details.
+
+=head2 GD::Text, GD::Text::Align, GD::Text::Wrap
+
+These plugins provide access to Martien Verbruggen's GD::Text,
+GD::Text::Align and GD::Text::Wrap modules. These plugins allow the
+layout, alignment and wrapping of text when drawing text in GD images.
+
+ [% FILTER null;
+ USE gd = GD.Image(200,400);
+ USE gdc = GD.Constants;
+ black = gd.colorAllocate(0, 0, 0);
+ green = gd.colorAllocate(0, 255, 0);
+ txt = "This is some long text. " | repeat(10);
+ USE wrapbox = GD.Text.Wrap(gd,
+ line_space => 4,
+ color => green,
+ text => txt,
+ );
+ wrapbox.set_font(gdc.gdMediumBoldFont);
+ wrapbox.set(align => 'center', width => 160);
+ wrapbox.draw(20, 20);
+ gd.png | stdout(1);
+ END;
+ -%]
+
+See L, L
+and L for further details.
+
+=head2 GD::Graph::lines, GD::Graph::bars, GD::Graph::points, GD::Graph::linespoin
+ts, GD::Graph::area, GD::Graph::mixed, GD::Graph::pie
+
+These plugins provide access to Martien Verbruggen's GD::Graph module
+that allows graphs, plots and charts to be created. These plugins allow
+graphs, plots and charts to be generated in PNG, JPEG and other
+graphical formats.
+
+ [% FILTER null;
+ data = [
+ ["1st","2nd","3rd","4th","5th","6th"],
+ [ 4, 2, 3, 4, 3, 3.5]
+ ];
+ USE my_graph = GD.Graph.pie(250, 200);
+ my_graph.set(
+ title => 'A Pie Chart',
+ label => 'Label',
+ axislabelclr => 'black',
+ pie_height => 36,
+ transparent => 0,
+ );
+ my_graph.plot(data).png | stdout(1);
+ END;
+ -%]
+
+See
+L,
+L,
+L,
+L,
+L,
+L,
+L, and
+L,
+for more details.
+
+=head2 GD::Graph::bars3d, GD::Graph::lines3d, GD::Graph::pie3d
+
+These plugins provide access to Jeremy Wadsack's GD::Graph3d
+module. This allows 3D bar charts and 3D lines plots to
+be generated.
+
+ [% FILTER null;
+ data = [
+ ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"],
+ [ 1, 2, 5, 6, 3, 1.5, 1, 3, 4],
+ ];
+ USE my_graph = GD.Graph.bars3d();
+ my_graph.set(
+ x_label => 'X Label',
+ y_label => 'Y label',
+ title => 'A 3d Bar Chart',
+ y_max_value => 8,
+ y_tick_number => 8,
+ y_label_skip => 2,
+ # shadows
+ bar_spacing => 8,
+ shadow_depth => 4,
+ shadowclr => 'dred',
+ transparent => 0,
+ my_graph.plot(data).png | stdout(1);
+ END;
+ -%]
+
+See
+L,
+L, and
+L
+for more details.
+
+=head2 HTML
+
+The HTML plugin is very new and very basic, implementing a few useful
+methods for generating HTML. It is likely to be extended in the future
+or integrated with a larger project to generate HTML elements in a generic
+way (as discussed recently on the mod_perl mailing list).
+
+ [% USE HTML %]
+ [% HTML.escape("if (a < b && c > d) ..." %]
+ [% HTML.attributes(border => 1, cellpadding => 2) %]
+ [% HTML.element(table => { border => 1, cellpadding => 2 }) %]
+
+See L for further details.
+
+=head2 Iterator
+
+The Iterator plugin provides a way to create a Template::Iterator
+object to iterate over a data set. An iterator is created
+automatically by the FOREACH directive and is aliased to the 'loop'
+variable. This plugin allows an iterator to be explicitly created
+with a given name, or the default plugin name, 'iterator'. See
+L for further details.
+
+ [% USE iterator(list, args) %]
+
+ [% FOREACH item = iterator %]
+ [% '
' IF iterator.first %]
+
[% item %]
+ [% '
' IF iterator.last %]
+ [% END %]
+
+=head2 Pod
+
+This plugin provides an interface to the L module
+which parses POD documents into an internal object model which can
+then be traversed and presented through the Template Toolkit.
+
+ [% USE Pod(podfile) %]
+
+ [% FOREACH head1 = Pod.head1;
+ FOREACH head2 = head1/head2;
+ ...
+ END;
+ END
+ %]
+
+=head2 String
+
+The String plugin implements an object-oriented interface for
+manipulating strings. See L for further
+details.
+
+ [% USE String 'Hello' %]
+ [% String.append(' World') %]
+
+ [% msg = String.new('Another string') %]
+ [% msg.replace('string', 'text') %]
+
+ The string "[% msg %]" is [% msg.length %] characters long.
+
+=head2 Table
+
+The Table plugin allows you to format a list of data items into a
+virtual table by specifying a fixed number of rows or columns, with
+an optional overlap. See L for further
+details.
+
+ [% USE table(list, rows=10, overlap=1) %]
+
+ [% FOREACH item = table.col(3) %]
+ [% item %]
+ [% END %]
+
+=head2 URL
+
+The URL plugin provides a simple way of contructing URLs from a base
+part and a variable set of parameters. See L
+for further details.
+
+ [% USE mycgi = url('/cgi-bin/bar.pl', debug=1) %]
+
+ [% mycgi %]
+ # ==> /cgi/bin/bar.pl?debug=1
+
+ [% mycgi(mode='submit') %]
+ # ==> /cgi/bin/bar.pl?mode=submit&debug=1
+
+=head2 Wrap
+
+The Wrap plugin uses the Text::Wrap module by David Muir Sharnoff
+Emuir@idiom.comE (with help from Tim Pierce and many many others)
+to provide simple paragraph formatting. See L
+and L for further details.
+
+ [% USE wrap %]
+ [% wrap(mytext, 40, '* ', ' ') %] # use wrap sub
+ [% mytext FILTER wrap(40) -%] # or wrap FILTER
+
+The Text::Wrap module is available from CPAN:
+
+ http://www.cpan.org/modules/by-module/Text/
+
+=head2 XML::DOM
+
+The XML::DOM plugin gives access to the XML Document Object Module via
+Clark Cooper Ecooper@sch.ge.comE and Enno Derksen's
+Eenno@att.comE XML::DOM module. See L
+and L for further details.
+
+ [% USE dom = XML.DOM %]
+ [% doc = dom.parse(filename) %]
+
+ [% FOREACH node = doc.getElementsByTagName('CODEBASE') %]
+ * [% node.getAttribute('href') %]
+ [% END %]
+
+The plugin requires the XML::DOM module, available from CPAN:
+
+ http://www.cpan.org/modules/by-module/XML/
+
+=head2 XML::RSS
+
+The XML::RSS plugin is a simple interface to Jonathan Eisenzopf's
+Eeisen@pobox.comE XML::RSS module. A RSS (Rich Site Summary)
+file is typically used to store short news 'headlines' describing
+different links within a site. This plugin allows you to parse RSS
+files and format the contents accordingly using templates.
+See L and L for further details.
+
+ [% USE news = XML.RSS(filename) %]
+
+ [% FOREACH item = news.items %]
+ [% item.title %]
+ [% END %]
+
+The XML::RSS module is available from CPAN:
+
+ http://www.cpan.org/modules/by-module/XML/
+
+=head2 XML::Simple
+
+This plugin implements an interface to the L
+module.
+
+ [% USE xml = XML.Simple(xml_file_or_text) %]
+
+ [% xml.head.title %]
+
+See L for further details.
+
+=head2 XML::Style
+
+This plugin defines a filter for performing simple stylesheet based
+transformations of XML text.
+
+ [% USE xmlstyle
+ table = {
+ attributes = {
+ border = 0
+ cellpadding = 4
+ cellspacing = 1
+ }
+ }
+ %]
+
+ [% FILTER xmlstyle %]
+
+
+
Foo
Bar
Baz
+
+
+ [% END %]
+
+See L for further details.
+
+=head2 XML::XPath
+
+The XML::XPath plugin provides an interface to Matt Sergeant's
+Ematt@sergeant.orgE XML::XPath module. See
+L and L for further details.
+
+ [% USE xpath = XML.XPath(xmlfile) %]
+ [% FOREACH page = xpath.findnodes('/html/body/page') %]
+ [% page.getAttribute('title') %]
+ [% END %]
+
+The plugin requires the XML::XPath module, available from CPAN:
+
+ http://www.cpan.org/modules/by-module/XML/
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Refs.pod b/lib/Template/Manual/Refs.pod
new file mode 100644
index 0000000..b0c9719
--- /dev/null
+++ b/lib/Template/Manual/Refs.pod
@@ -0,0 +1,171 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::Refs
+#
+# DESCRIPTION
+# This section provides references to external modules, projects and
+# other resources related to the Template Toolkit.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::Refs - Related modules, projects and other resources
+
+=head1 DESCRIPTION
+
+This section provides references to external modules, projects and
+other resources related to the Template Toolkit.
+
+=head2 Resources
+
+The Template Toolkit web site contains the latest information, news and
+other resources.
+
+ http://www.template-toolkit.org/
+
+A mailing list exists for up-to-date information on the Template Toolkit
+and for following and contributing to the development process. To
+subscribe, send an email to
+
+ templates-request@template-toolkit.org
+
+with the message 'subscribe' in the body. You can also use the web
+interface to subscribe or browse the archives:
+
+ http://www.template-toolkit.org/mailman/listinfo/templates
+
+The F and F scripts are distributed and installed along
+with the Template Toolkit. The F script simply processes named
+files or STDIN if unspecified, using a default Template object. The
+F script can be used to process entire directory trees of templates,
+allowing large content systems such as web sites to be rebuilt from a
+single command or configuration file.
+
+ perldoc tpage
+ perldoc ttree
+
+The F document provides an introduction to the Template
+Toolkit and shows some typical examples of usage.
+
+ perldoc Template::Tutorial
+
+You may also like to consult the paper 'Building and Managing Web Systems
+with the Template Toolkit' and accompanying slides from the presentation
+at the 4th Perl Conference. These are available from the Template
+Toolkit web site:
+
+ http://www.template-toolkit.org/docs.html
+
+
+
+=head2 Projects
+
+There are a number of other projects related to the Template Toolkit.
+
+=over 4
+
+=item OpenInteract
+
+OpenInteract is a robust web application framework built to run under
+Apache and mod_perl using the Template Toolkit as a foundation.
+
+ http://www.openinteract.org/
+
+=item Apache::Template
+
+This is an Apache/mod_perl interface to the Template Toolkit. Available
+from CPAN in the directory:
+
+ http://www.cpan.org/modules/by-module/Apache/
+
+=item AxKit::Template
+
+AxKit is Matt Sergeant's Apache XML Delivery Toolkit. AxKit::Template
+provides an interface between AxKit and the Template Toolkit. Available
+from CPAN in the directory:
+
+ http://www.cpan.org/modules/by-module/Apache/
+
+=item Slashcode
+
+Slashcode is the code which runs Slashdot. Version 2 uses the
+Template Toolkit for generating the user interface from database
+driven template.
+
+ http://slashcode.org/
+
+=item OpenFrame
+
+OpenFrame is an open source application framework for distributed
+media applications. It ships with a generator for the Template
+Toolkit.
+
+ http://openframe.fotango.com/
+
+=item PCMT
+
+PCMT is the Personal Content Management Toolkit. It uses the Template
+Toolkit as the presentation engine.
+
+ http://pcmt.sf.net/
+
+=back
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Syntax.pod b/lib/Template/Manual/Syntax.pod
new file mode 100644
index 0000000..cc1b6c8
--- /dev/null
+++ b/lib/Template/Manual/Syntax.pod
@@ -0,0 +1,306 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::Syntax
+#
+# DESCRIPTION
+# This section describes the syntax, structure and semantics of the
+# Template Toolkit directives and general presentation language.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::Syntax - Directive syntax, structure and semantics
+
+=head1 DESCRIPTION
+
+This section describes the syntax, structure and semantics of the
+Template Toolkit directives and general presentation language.
+
+=head2 Tag Styles
+
+By default, template directives are embedded within the character sequences
+'[%' and '%]'. e.g.
+
+ [% PROCESS header %]
+
+
Hello World!
+
+
+ [% PROCESS footer %]
+
+You can change the tag characters using the START_TAG, END_TAG and
+TAG_STYLE configuration options. You can also use the TAGS directive
+to define a new tag style for the current template file.
+
+You can also set the INTERPOLATE option to allow simple variable
+references to be embedded directly in templates, prefixed by a '$'.
+
+ # INTERPOLATE => 0
+
[% name %]
[% email %]
+
+ # INTERPOLATE => 1
+
$name
$email
+
+Directives may be embedded anywhere in a line of text and can be split
+across several lines. Insignificant whitespace is generally ignored
+within the directive.
+
+ [% INCLUDE header
+ title = 'Hello World'
+ bgcol = '#ffffff'
+ %]
+
+ [%INCLUDE menu align='right'%]
+
+ Name: [% name %] ([%id%])
+
+=head2 Comments
+
+The '#' character is used to indicate comments within a directive.
+When placed immediately inside the opening directive tag, it causes
+the entire directive to be ignored.
+
+ [%# this entire directive is ignored no
+ matter how many lines it wraps onto
+ %]
+
+In any other position, it causes the remainder of the current line to
+be treated as a comment.
+
+ [% # this is a comment
+ theta = 20 # so is this
+ rho = 30 # me too!
+ %]
+
+=head2 Chomping Whitespace
+
+You can add '-' or '+' to the immediate start or end of a directive
+tag to control the whitespace chomping options. See the PRE_CHOMP and
+POST_CHOMP options for further details.
+
+ [% BLOCK foo -%] # remove trailing newline
+ This is block foo
+ [%- END %] # remove leading newline
+
+=head2 Implicit Directives: GET and SET
+
+The simplest directives are GET and SET which retrieve and update
+variable values respectively. The GET and SET keywords are actually
+optional as the parser is smart enough to see them for what they
+really are (but note the caveat below on using side-effect notation).
+Thus, you'll generally see:
+
+ [% SET foo = 10 %]
+ [% GET foo %]
+
+written as:
+
+ [% foo = 10 %]
+ [% foo %]
+
+You can also express simple logical statements as implicit GET directives:
+
+ [% title or template.title or 'Default Title' %]
+
+ [% mode == 'graphics' ? "Graphics Mode Enabled" : "Text Mode" %]
+
+All other directives should start with a keyword specified in UPPER
+CASE (but see the ANYCASE option). All directives keywords are in
+UPPER CASE to make them visually distinctive and to distinguish them
+from variables of the same name but different case. It is perfectly
+valid, for example, to define a variable called 'stop' which is
+entirely separate from the STOP directive.
+
+ [% stop = 'Clackett Lane Bus Depot' %]
+
+ The bus will next stop at [% stop %] # variable
+
+ [% STOP %] # directive
+
+=head2 Block Directives
+
+Directives such as FOREACH, WHILE, BLOCK, FILTER, etc., mark the start
+of a block which may contain text or other directives up to the
+matching END directive. Blocks may be nested indefinitely. The
+IF, UNLESS, ELSIF and ELSE directives also define blocks and may be
+grouped together in the usual manner.
+
+ [% FOREACH item = [ 'foo' 'bar' 'baz' ] %]
+ * Item: [% item %]
+ [% END %]
+
+ [% BLOCK footer %]
+ Copyright 2000 [% me %]
+ [% INCLUDE company/logo %]
+ [% END %]
+
+ [% IF foo %]
+ [% FOREACH thing = foo.things %]
+ [% thing %]
+ [% END %]
+ [% ELSIF bar %]
+ [% INCLUDE barinfo %]
+ [% ELSE %]
+ do nothing...
+ [% END %]
+
+Block directives can also be used in a convenient side-effect notation.
+
+ [% INCLUDE userinfo FOREACH user = userlist %]
+
+ [% INCLUDE debugtxt msg="file: $error.info"
+ IF debugging %]
+
+ [% "Danger Will Robinson" IF atrisk %]
+
+versus:
+
+ [% FOREACH user = userlist %]
+ [% INCLUDE userinfo %]
+ [% END %]
+
+ [% IF debugging %]
+ [% INCLUDE debugtxt msg="file: $error.info" %]
+ [% END %]
+
+ [% IF atrisk %]
+ Danger Will Robinson
+ [% END %]
+
+=head2 Capturing Block Output
+
+The output of a directive can be captured by simply assigning the directive
+to a variable.
+
+ [% headtext = PROCESS header title="Hello World" %]
+
+ [% people = PROCESS userinfo FOREACH user = userlist %]
+
+This can be used in conjunction with the BLOCK directive for defining large
+blocks of text or other content.
+
+ [% poem = BLOCK %]
+ The boy stood on the burning deck,
+ His fleece was white as snow.
+ A rolling stone gathers no moss,
+ And Keith is sure to follow.
+ [% END %]
+
+Note one important caveat of using this syntax in conjunction with side-effect
+notation. The following directive does not behave as might be expected:
+
+ [% var = 'value' IF some_condition %]
+
+In this case, the directive is interpreted as (spacing added for clarity)
+
+ [% var = IF some_condition %]
+ value
+ [% END %]
+
+rather than
+
+ [% IF some_condition %]
+ [% var = 'value' %]
+ [% END %]
+
+The variable is assigned the output of the IF block which returns
+'value' if true, but nothing if false. In other words, the following
+directive will always cause 'var' to be cleared.
+
+ [% var = 'value' IF 0 %]
+
+To achieve the expected behaviour, the directive should be written as:
+
+ [% SET var = 'value' IF some_condition %]
+
+=head2 Chaining Filters
+
+Multiple FILTER directives can be chained together in sequence. They
+are called in the order defined, piping the output of one into the
+input of the next.
+
+ [% PROCESS somefile FILTER truncate(100) FILTER html %]
+
+The pipe character, '|', can also be used as an alias for FILTER.
+
+ [% PROCESS somefile | truncate(100) | html %]
+
+=head2 Multiple Directive Blocks
+
+Multiple directives can be included within a single tag when delimited
+by semi-colons, ';'. Note however that the TAGS directive must always
+be specified in a tag by itself.
+
+ [% IF title;
+ INCLUDE header;
+ ELSE;
+ INCLUDE other/header title="Some Other Title";
+ END
+ %]
+
+versus
+
+ [% IF title %]
+ [% INCLUDE header %]
+ [% ELSE %]
+ [% INCLUDE other/header title="Some Other Title" %]
+ [% END %]
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/VMethods.pod b/lib/Template/Manual/VMethods.pod
new file mode 100644
index 0000000..7e380fa
--- /dev/null
+++ b/lib/Template/Manual/VMethods.pod
@@ -0,0 +1,529 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::VMethods
+#
+# DESCRIPTION
+# The Template Toolkit provides virtual methods for manipulating
+# variable values. Most of them are analogous to regular Perl
+# functions of the same names. This section describes the different
+# virtual methods that can be applied to scalar, list and hash
+# values.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::VMethods - Virtual Methods
+
+=head1 DESCRIPTION
+
+The Template Toolkit provides virtual methods for manipulating variable
+values. Most of them are analogous to regular Perl functions of the
+same names. This section describes the different virtual methods that
+can be applied to scalar, list and hash values.
+
+=head2 Scalar Virtual Methods
+
+=over 4
+
+=item defined
+
+Returns true if the value is defined.
+
+ [% user = get_user(uid) IF uid.defined %]
+
+=item length
+
+Returns the length of the string representation of the item:
+
+ [% IF password.length < 8 %]
+ Password too short, dumbass!
+ [% END %]
+
+=item repeat(n)
+
+Repeat the string a specified number of times.
+
+ [% name = 'foo' %]
+ [% name.repeat(3) %] # foofoofoo
+
+=item replace(search, replace)
+
+Outputs the string with all instances of the first argument (specified
+as a Perl regular expression) with the second.
+
+ [% name = 'foo, bar & baz' %]
+ [% name.replace('\W+', '_') %] # foo_bar_baz
+
+=item match(pattern)
+
+Performs a regular expression match on the string using the pattern
+passed as an argument. If the pattern matches the string then the
+method returns a reference to a list of any strings captured within
+parenthesis in the pattern.
+
+ [% name = 'Larry Wall' %]
+ [% matches = name.match('(\w+) (\w+)') %]
+ [% matches.1 %], [% matches.0 %] # Wall, Larry
+
+If the pattern does not match then the method returns false, rather
+than returning an empty list which Perl and the Template Toolkit both
+consider to be a true value. This allows you to write expression like
+this.
+
+ [% "We're not worthy!" IF name.match('Larry Wall') %]
+
+ [% IF (matches = name.match('(\w+) (\w+)')) %]
+ pattern matches: [% matches.join(', ') %]
+ [% ELSE %]
+ pattern does not match
+ [% END %]
+
+Any regex modifiers, like C, should be added in the regex using
+the C<(?s)> syntax. For example, to modify the regex to disregard
+whitespace (the C switch), use:
+
+ [% re = '(?x)
+ (\w+)
+ [ ]
+ (\w+)
+ ';
+ matches = name.match(re);
+ %]
+
+=item search(pattern)
+
+Performs a similar function to 'match' but simply returns true if the
+string matches the regular expression pattern passed as an argument.
+
+ [% name = 'foo bar baz' %]
+ [% name.search('bar') ? 'bar' : 'no bar' %] # bar
+
+This virtual method is now deprecated in favour of 'match'. Move along
+now, there's nothing more to see here.
+
+=item split(pattern)
+
+Calls Perl's split() function to split a string into a list of
+strings.
+
+ [% FOREACH dir = mypath.split(':') %]
+ [% dir %]
+ [% END %]
+
+=item chunk(size)
+
+Splits the value into a list of chunks of a certain size.
+
+ [% ccard_no = "1234567824683579";
+ ccard_no.chunk(4).join
+ %]
+
+Output:
+
+ 1234 5678 2468 3579
+
+If the size is specified as a negative number then the text will
+be chunked from right-to-left. This gives the correct grouping
+for numbers, for example.
+
+ [% number = 1234567;
+ number.chunk(-3).join(',')
+ %]
+
+Output:
+
+ 1,234,567
+
+=item list
+
+Return the value as a single element list. This can be useful if you
+have a variable which may contain a single item or a list and you want
+to treat them equally. The 'list' method can be called against a list
+reference and will simply return the original reference, effectively
+a no-op.
+
+ [% thing.list.size %] # thing can be a scalar or a list
+
+=item hash
+
+Return the value as a hash reference containing a single entry with
+the key 'value' indicating the original scalar value. As with the
+'list' virtual method, this is generally used to help massage data
+into different formats.
+
+=item size
+
+Always returns 1 for scalar values. This method is provided for
+consistency with the hash and list size methods.
+
+=back
+
+
+=head2 Hash Virtual Methods
+
+=over 4
+
+=item keys, values, each
+
+The regular hash operators returning lists of keys, values or both.
+Note how we use a '$' prefix on the 'key' variable in this example to
+have it interpolated (i.e. replaced with its value) before use.
+
+ [% FOREACH key = product.keys %]
+ [% key %] => [% product.$key %]
+ [% END %]
+
+=item sort, nsort
+
+Return a list of the keys, sorted alphabetically (sort) or numerically
+(nsort) according to the corresponding values in the hash.
+
+ [% FOREACH n = phones.sort %]
+ [% phones.$n %] is [% n %],
+ [% END %]
+
+=item import
+
+The import method can be called on a hash array to import the contents
+of another hash array.
+
+ [% hash1 = {
+ foo => 'Foo',
+ bar => 'Bar',
+ }
+ hash2 = {
+ wiz => 'Wiz',
+ woz => 'Woz',
+ }
+ %]
+
+ [% hash1.import(hash2) %]
+ [% hash1.wiz %] # Wiz
+
+You can also call the import() method by itself to import a hash array
+into the current namespace hash.
+
+ [% user = { id => 'lwall', name => 'Larry Wall' } %]
+ [% import(user) %]
+ [% id %]: [% name %] # lwall: Larry Wall
+
+=item defined, exists
+
+Returns a true or false value if an item in the hash denoted by the key
+passed as an argument is defined or exists, respectively.
+
+ [% hash.defined('somekey') ? 'yes' : 'no' %]
+ [% hash.exists('somekey') ? 'yes' : 'no' %]
+
+=item size
+
+Returns the number of key =E value pairs in the hash.
+
+=item item
+
+Returns an item from the hash using a key passed as an argument.
+
+ [% hash.item('foo') %] # same as hash.foo
+
+=item list
+
+Returns the contents of the hash in list form. An argument can be
+passed to indicate the desired items required in the list: 'keys' to
+return a list of the keys (same as hash.keys), 'values' to return a
+list of the values (same as hash.values), or 'each' to return as list
+of (key, value) pairs (same as hash.each). When called without an
+argument it returns a list of hash references, each of which contains
+a 'key' and 'value' item representing a single key =E value pair
+in the hash.
+
+=back
+
+
+=head2 List Virtual Methods
+
+=over 4
+
+=item first, last
+
+Returns the first/last item in the list. The item is not removed from the
+list.
+
+ [% results.first %] to [% results.last %]
+
+If either is given a numeric argument C, they return the first or
+last C elements:
+
+ The first 5 results are [% results.first(5).join(", ") %].
+
+=item size, max
+
+Returns the size of a list (number of elements) and the maximum
+index number (size - 1), respectively.
+
+ [% results.size %] search results matched your query
+
+=item reverse
+
+Returns the items of the list in reverse order.
+
+ [% FOREACH s = scores.reverse %]
+ ...
+ [% END %]
+
+=item join
+
+Joins the items in the list into a single string, using Perl's join
+function.
+
+ [% items.join(', ') %]
+
+=item grep
+
+Returns a list of the items in the list that match a regular expression
+pattern.
+
+ [% FOREACH directory.files.grep('\.txt$') %]
+ ...
+ [% END %]
+
+=item sort, nsort
+
+Returns the items in alpha (sort) or numerical (nsort) order.
+
+ [% library = books.sort %]
+
+An argument can be provided to specify a search key. Where an item in
+the list is a hash reference, the search key will be used to retrieve a
+value from the hash which will then be used as the comparison value.
+Where an item is an object which implements a method of that name, the
+method will be called to return a comparison value.
+
+ [% library = books.sort('author') %]
+
+In the example, the 'books' list can contains hash references with
+an 'author' key or objects with an 'author' method.
+
+=item unshift(item), push(item)
+
+Adds an item to the start/end of a list.
+
+ [% mylist.unshift('prev item') %]
+ [% mylist.push('next item') %]
+
+=item shift, pop
+
+Removes the first/last item from the list and returns it.
+
+ [% first = mylist.shift %]
+ [% last = mylist.pop %]
+
+=item unique
+
+Returns a list of the unique elements in a list, in the same order
+as in the list itself.
+
+ [% mylist = [ 1, 2, 3, 2, 3, 4, 1, 4, 3, 4, 5 ] %]
+ [% numbers = mylist.unique %]
+
+While this can be explicitly sorted, it is not required that the list
+be sorted before the unique elements are pulled out (unlike the Unix
+command line utility).
+
+ [% numbers = mylist.unique.sort %]
+
+=item merge
+
+Returns a list composed of zero or more other lists:
+
+ [% list_one = [ 1 2 3 ];
+ list_two = [ 4 5 6 ];
+ list_three = [ 7 8 9 ];
+ list_four = list_one.merge(list_two, list_three);
+ %]
+
+The original lists are not modified.
+
+=item slice(from, to)
+
+Returns a slice of items in the list between the bounds passed as
+arguments. If the second argument, 'to', isn't specified, then it
+defaults to the last item in the list. The original list is not
+modified.
+
+ [% first_three = list.slice(0,2) %]
+
+ [% last_three = list.slice(-3, -1) %]
+
+=item splice(offset, length, list)
+
+Behaves just like Perl's splice() function allowing you to selectively
+remove and/or replace elements in a list. It removes 'length' items
+from the list, starting at 'offset' and replaces them with the items
+in 'list'.
+
+ [% play_game = [ 'play', 'scrabble' ];
+ ping_pong = [ 'ping', 'pong' ];
+ redundant = play_game.splice(1, 1, ping_pong);
+
+ redundant.join; # scrabble
+ play_game.join; # play ping pong
+ %]
+
+The method returns a list of the items removed by the splice.
+You can use the CALL directive to ignore the output if you're
+not planning to do anything with it.
+
+ [% CALL play_game.splice(1, 1, ping_pong) %]
+
+As well as providing a reference to a list of replacement values,
+you can pass in a list of items.
+
+ [% CALL list.splice(-1, 0, 'foo', 'bar') %]
+
+Be careful about passing just one item in as a replacement value.
+If it is a reference to a list then the contents of the list will
+be used. If it's not a list, then it will be treated as a single
+value. You can use square brackets around a single item if you
+need to be explicit:
+
+ [% # push a single item, an_item
+ CALL list.splice(-1, 0, an_item);
+
+ # push the items from another_list
+ CALL list.splice(-1, 0, another_list);
+
+ # push a reference to another_list
+ CALL list.splice(-1, 0, [ another_list ]);
+ %]
+
+=back
+
+=head2 Automagic Promotion of Scalar to List for Virtual Methods
+
+In addition to the scalar virtual methods listed in the previous
+section, you can also call any list virtual method against a scalar.
+The item will be automagically promoted to a single element list and
+the appropriate list virtual method will be called.
+
+One particular benefit of this comes when calling subroutines or
+object methods that return a list of items, rather than the
+preferred reference to a list of items. In this case, the
+Template Toolkit automatically folds the items returned into
+a list.
+
+The upshot is that you can continue to use existing Perl modules or
+code that returns lists of items, without having to refactor it
+just to keep the Template Toolkit happy (by returning references
+to list). Class::DBI module is just one example of a particularly
+useful module which returns values this way.
+
+If only a single item is returned from a subroutine then the
+Template Toolkit assumes it meant to return a single item (rather
+than a list of 1 item) and leaves it well alone, returning the
+single value as it is. If you're executing a database query,
+for example, you might get 1 item returned, or perhaps many
+items which are then folded into a list.
+
+The FOREACH directive will happily accept either a list or a single
+item which it will treat as a list. So it's safe to write directives
+like this, where we assume that 'something' is bound to a subroutine
+which might return 1 or more items:
+
+ [% FOREACH item = something %]
+ ...
+ [% END %]
+
+The automagic promotion of scalars to single item lists means
+that you can also use list virtual methods safely, even if you
+only get one item returned. For example:
+
+ [% something.first %]
+ [% something.join %]
+ [% something.reverse.join(', ') %]
+
+Note that this is very much a last-ditch behaviour. If the single
+item return is an object with a 'first' method, for example, then that
+will be called, as expected, in preference to the list virtual method.
+
+=head2 Defining Custom Virtual Methods
+
+You can define your own virtual methods for scalars, lists and hash
+arrays. The Template::Stash package variables $SCALAR_OPS, $LIST_OPS
+and $HASH_OPS are references to hash arrays that define these virtual
+methods. HASH_OPS and LIST_OPS methods are subroutines that accept a
+hash/list reference as the first item. SCALAR_OPS are subroutines
+that accept a scalar value as the first item. Any other arguments
+specified when the method is called will be passed to the subroutine.
+
+ # load Template::Stash to make method tables visible
+ use Template::Stash;
+
+ # define list method to return new list of odd numbers only
+ $Template::Stash::LIST_OPS->{ odd } = sub {
+ my $list = shift;
+ return [ grep { $_ % 2 } @$list ];
+ };
+
+template:
+
+ [% primes = [ 2, 3, 5, 7, 9 ] %]
+ [% primes.odd.join(', ') %] # 3, 5, 7, 9
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Variables.pod b/lib/Template/Manual/Variables.pod
new file mode 100644
index 0000000..e8d998c
--- /dev/null
+++ b/lib/Template/Manual/Variables.pod
@@ -0,0 +1,868 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::Variables
+#
+# DESCRIPTION
+# This section describes the different ways in which Perl data can be
+# bound to template variables and accessed via Template Toolkit
+# directives.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::Variables - Template variables and code bindings
+
+=head1 DESCRIPTION
+
+This section describes the different ways in which Perl data can be
+bound to template variables and accessed via Template Toolkit
+directives.
+
+=head2 Template Variables
+
+A reference to a hash array may be passed as the second argument to
+the process() method, containing definitions of template variables.
+The VARIABLES (a.k.a. PRE_DEFINE) option can also be used to pre-define
+variables for all templates processed by the object.
+
+ my $tt = Template->new({
+ VARIABLES => {
+ version => 3.14,
+ release => 'Sahara',
+ },
+ });
+
+ my $vars = {
+ serial_no => 271828,
+ };
+
+ $tt->process('myfile', $vars);
+
+'myfile':
+
+ This is version [% version %] ([% release %]).
+ Serial number: [% serial_no %]
+
+output:
+
+ This is version 3.14 (Sahara)
+ Serial number: 271828
+
+Variable names may contain any alphanumeric characters or underscores.
+They may be lower, upper or mixed case although the usual convention
+is to use lower case. The case I significant however, and 'foo',
+'Foo' and 'FOO' are all different variables. Upper case variable
+names are permitted, but not recommended due to a possible conflict
+with an existing or future reserved word. As of version 2.00, these
+are:
+
+ GET CALL SET DEFAULT INSERT INCLUDE PROCESS WRAPPER
+ IF UNLESS ELSE ELSIF FOR FOREACH WHILE SWITCH CASE
+ USE PLUGIN FILTER MACRO PERL RAWPERL BLOCK META
+ TRY THROW CATCH FINAL NEXT LAST BREAK RETURN STOP
+ CLEAR TO STEP AND OR NOT MOD DIV END
+
+
+The variable values may be of virtually any Perl type, including
+simple scalars, references to lists, hash arrays, subroutines or
+objects. The Template Toolkit will automatically apply the correct
+procedure to accessing these values as they are used in the template.
+
+Example:
+
+ my $vars = {
+ article => 'The Third Shoe',
+ person => {
+ id => 314,
+ name => 'Mr. Blue',
+ email => 'blue@nowhere.org',
+ },
+ primes => [ 2, 3, 5, 7, 11, 13 ],
+ wizard => sub { return join(' ', 'Abracadabra!', @_) },
+ cgi => CGI->new('mode=submit&debug=1'),
+ };
+
+template:
+
+ [% article %]
+
+ [% person.id %]: [% person.name %] <[% person.email %]>
+
+ [% primes.first %] - [% primes.last %], including [% primes.3 %]
+ [% primes.size %] prime numbers: [% primes.join(', ') %]
+
+ [% wizard %]
+ [% wizard('Hocus Pocus!') %]
+
+ [% cgi.param('mode') %]
+
+output:
+
+ The Third Shoe
+
+ 314: Mr. Blue
+
+ 2 - 13, including 7
+ 6 prime numbers: 2, 3, 5, 7, 11, 13
+
+ Abracadabra!
+ Abracadabra! Hocus Pocus!
+
+ submit
+
+=head2 Scalar Values
+
+Regular scalar variables are accessed by simply specifying their name.
+As these are just entries in the top-level variable hash they can be
+considered special cases of hash array referencing as described below,
+with the main namespace hash automatically implied.
+
+ [% article %]
+
+=head2 Hash Array References
+
+Members of hash arrays are accessed by specifying the hash reference
+and key separated by the dot '.' operator.
+
+ my $vars = {
+ 'home' => 'http://www.myserver.com/homepage.html',
+ 'page' => {
+ 'this' => 'mypage.html',
+ 'next' => 'nextpage.html',
+ 'prev' => 'prevpage.html',
+ },
+ };
+
+template:
+
+ Home
+ Previous Page
+ Next Page
+
+output:
+
+ Home
+ Previous Page
+ Next Page
+
+Any key in a hash which starts with a '_' or '.' character will be
+considered private and cannot be evaluated or updated from within a
+template. The undefined value will be returned for any such variable
+accessed which the Template Toolkit will silently ignore (unless the
+DEBUG option is enabled).
+
+ my $vars = {
+ message => 'Hello World!',
+ _secret => "On the Internet, no-one knows you're a dog",
+ thing => {
+ public => 123,
+ _private => 456,
+ '.hidden' => 789,
+ },
+ };
+
+template:
+
+ [% message %] # outputs "Hello World!"
+ [% _secret %] # no output
+ [% thing.public %] # outputs "123"
+ [% thing._private %] # no output
+ [% thing..hidden %] # ERROR: unexpected token (..)
+
+To access a hash entry using a key stored in another variable, prefix
+the key variable with '$' to have it interpolated before use (see
+L).
+
+ [% pagename = 'next' %]
+ [% page.$pagename %] # same as [% page.next %]
+
+When you assign to a variable that contains multiple namespace
+elements (i.e. it has one or more '.' characters in the name),
+any hashes required to represent intermediate namespaces will be
+created automatically. In this following example, the 'product'
+variable automatically springs into life as a hash array unless
+otherwise defined.
+
+ [% product.id = 'XYZ-2000'
+ product.desc = 'Bogon Generator'
+ product.price = 666
+ %]
+
+ The [% product.id %] [% product.desc %]
+ costs $[% product.price %].00
+
+output:
+
+ The XYZ-2000 Bogon Generator
+ costs $666.00
+
+You can use Perl's familiar '{' ... '}' construct to explicitly create
+a hash and assign it to a variable. Note that commas are optional
+between key/value pairs and '=' can be used in place of '=E'.
+
+ [% product = {
+ id => 'XYZ-2000',
+ desc => 'Bogon Generator',
+ price => 666,
+ }
+ %]
+
+=head2 List References
+
+Items in lists are also accessed by use of the dot operator.
+
+ my $vars = {
+ 'people' => [ 'Tom', 'Dick', 'Larry' ],
+ };
+
+template:
+
+ [% people.0 %] # Tom
+ [% people.1 %] # Dick
+ [% people.2 %] # Larry
+
+The FOREACH directive can be used to iterate through items in a list.
+
+ [% FOREACH person = people %]
+ Hello [% person %]
+ [% END %]
+
+output:
+
+ Hello Tom
+ Hello Dick
+ Hello Larry
+
+Lists can be constructed in-situ using the regular anonymous list
+'[' ... ']' construct. Commas between items are optional.
+
+ [% cols = [ 'red', 'green', 'blue' ] %]
+
+ [% FOREACH c = cols %]
+ ...
+
+or:
+
+ [% FOREACH c = [ 'red', 'green', 'blue' ] %]
+ ...
+
+You can also create simple numerical sequences using the familiar '..'
+operator:
+
+ [% n = [ 1 .. 4 ] %] # n is [ 1, 2, 3, 4 ]
+
+ [% x = 4
+ y = 8
+ z = [x..y] # z is [ 4, 5, 6, 7, 8 ]
+ %]
+
+=head2 Subroutines
+
+Template variables can contain references to Perl subroutines. When
+the variable is used, the Template Toolkit will automatically call the
+subroutine, passing any additional arguments specified. The return
+value from the subroutine is used as the variable value and inserted
+into the document output.
+
+ my $vars = {
+ wizard => sub { return join(' ', 'Abracadabra!', @_) },
+ };
+
+template:
+
+ [% wizard %] # Abracadabra!
+ [% wizard('Hocus Pocus!') %] # Abracadabra! Hocus Pocus!
+
+
+=head2 Objects
+
+Template variables can also contain references to Perl objects.
+Methods are called using the dot operator to specify the method
+against the object variable. Additional arguments can be specified
+as with subroutines.
+
+ use CGI;
+
+ ...
+
+ my $vars = {
+ # hard coded CGI params for purpose of example
+ cgi => CGI->new('mode=submit&debug=1'),
+ };
+
+template:
+
+ [% FOREACH p = cgi.param %] # returns list of param keys
+ [% p %] => [% cgi.param(p) %] # fetch each param value
+ [% END %]
+
+output:
+
+ mode => submit
+ debug => 1
+
+Object methods can also be called as lvalues. That is, they can appear on
+the left side of an assignment. The method will be called passing the
+assigning value as an argument.
+
+ [% myobj.method = 10 %]
+
+equivalent to:
+
+ [% myobj.method(10) %]
+
+=head2 Parameters and Return Values
+
+Subroutines and methods will be passed any arguments specified in the
+template. Any template variables in the argument list will first be
+evaluated and their resultant values passed to the code.
+
+ my $vars = {
+ mycode => sub { return 'received ' . join(', ', @_) },
+ };
+
+template:
+
+ [% foo = 10 %]
+ [% mycode(foo, 20) %] # received 10, 20
+
+Named parameters may also be specified. These are automatically collected
+into a single hash array which is passed by reference as the B
+parameter to the sub-routine. Named parameters can be specified using
+either '=E' or '=' and can appear anywhere in the argument list.
+
+ my $vars = {
+ myjoin => \&myjoin,
+ };
+
+ sub myjoin {
+ # look for hash ref as last argument
+ my $params = ref $_[-1] eq 'HASH' ? pop : { };
+ return join($params->{ joint } || ' + ', @_);
+ }
+
+template:
+
+ [% myjoin(10, 20, 30) %]
+ [% myjoin(10, 20, 30, joint = ' - ' %]
+ [% myjoin(joint => ' * ', 10, 20, 30 %]
+
+output:
+
+ 10 + 20 + 30
+ 10 - 20 - 30
+ 10 * 20 * 30
+
+Parenthesised parameters may be added to any element of a variable,
+not just those that are bound to code or object methods. At present,
+parameters will be ignored if the variable isn't "callable" but are
+supported for future extensions. Think of them as "hints" to that
+variable, rather than just arguments passed to a function.
+
+ [% r = 'Romeo' %]
+ [% r(100, 99, s, t, v) %] # outputs "Romeo"
+
+User code should return a value for the variable it represents. This
+can be any of the Perl data types described above: a scalar, or
+reference to a list, hash, subroutine or object. Where code returns a
+list of multiple values the items will automatically be folded into a
+list reference which can be accessed as per normal.
+
+ my $vars = {
+ # either is OK, first is recommended
+ items1 => sub { return [ 'foo', 'bar', 'baz' ] },
+ items2 => sub { return ( 'foo', 'bar', 'baz' ) },
+ };
+
+template:
+
+ [% FOREACH i = items1 %]
+ ...
+ [% END %]
+
+ [% FOREACH i = items2 %]
+ ...
+ [% END %]
+
+=head2 Error Handling
+
+Errors can be reported from user code by calling die(). Errors raised
+in this way are caught by the Template Toolkit and converted to
+structured exceptions which can be handled from within the template.
+A reference to the exception object is then available as the 'error'
+variable.
+
+ my $vars = {
+ barf => sub {
+ die "a sick error has occurred\n";
+ },
+ };
+
+template:
+
+ [% TRY %]
+ [% barf %] # calls sub which throws error via die()
+ [% CATCH %]
+ [% error.info %] # outputs "a sick error has occurred\n"
+ [% END %]
+
+Error messages thrown via die() are converted to exceptions of type
+'undef'. Exceptions of user-defined types can be thrown by calling
+die() with a reference to a Template::Exception object.
+
+ use Template::Exception;
+
+ ...
+
+ my $vars = {
+ login => sub {
+ ...
+ die Template::Exception->new('badpwd',
+ 'password too silly');
+ },
+ };
+
+template:
+
+ [% TRY %]
+ [% login %]
+ [% CATCH badpwd %]
+ Bad password: [% error.info %]
+ [% CATCH %]
+ Some other '[% error.type %]' error: [% error.info %]
+ [% END %]
+
+The exception types 'stop' and 'return' are used to implement the
+STOP and RETURN directives. Throwing an exception as:
+
+ die (Template::Exception->new('stop'));
+
+has the same effect as the directive:
+
+ [% STOP %]
+
+Subroutines and methods can also raise errors by returning a list or
+reference to a list containing the undefined value (undef) followed by
+an exception object or error message. This is supported for backwards
+compatibility with version 1 but may be deprecated in some future
+version.
+
+ my $vars = {
+ # currently equivalent
+ barf => sub {
+ die "I'm sorry Dave, I can't do that";
+ },
+ yack => sub {
+ return (undef, "I'm sorry Dave, I can't do that");
+ },
+ };
+
+=head2 Virtual Methods
+
+The Template Toolkit implements a number of "virtual methods" which
+can be applied to scalars, hashes or lists. For example:
+
+ [% mylist = [ 'foo', 'bar', 'baz' ] %]
+ [% newlist = mylist.sort %]
+
+Here 'mylist' is a regular reference to a list, and 'sort' is
+a virtual method that returns a new list of the items in sorted
+order. You can chain multiple virtual methods together. For
+example:
+
+ [% mylist.sort.join(', ') %]
+
+Here the 'join' virtual method is called to join the sorted list into
+a single string, generating the following output:
+
+ bar, baz, foo
+
+See L for details of all the virtual
+methods available.
+
+=head2 Variable Interpolation
+
+The Template Toolkit uses '$' consistently to indicate that a variable
+should be interpolated in position. Most frequently, you see this in
+double-quoted strings:
+
+ [% fullname = "$honorific $firstname $surname" %]
+
+Or embedded in plain text when the INTERPOLATE option is set:
+
+ Dear $honorific $firstname $surname,
+
+The same rules apply within directives. If a variable is prefixed
+with a '$' then it is replaced with its value before being used. The
+most common use is to retrieve an element from a hash where the key is
+stored in a variable.
+
+ [% uid = 'abw' %]
+ [% userlist.$uid %] # same as 'userlist.abw'
+
+Curly braces can be used to delimit interpolated variable names where
+necessary.
+
+ [% userlist.${me.id}.name %]
+
+Directives such as INCLUDE, PROCESS, etc., that accept a template name
+as the first argument, will automatically quote it for convenience.
+
+ [% INCLUDE foo/bar.txt %]
+
+equivalent to:
+
+ [% INCLUDE "foo/bar.txt" %]
+
+To INCLUDE a template whose name is stored in a variable, simply
+prefix the variable name with '$' to have it interpolated.
+
+ [% myfile = 'header' %]
+ [% INCLUDE $myfile %]
+
+equivalent to:
+
+ [% INCLUDE header %]
+
+Note also that a variable containing a reference to a Template::Document
+object can also be processed in this way.
+
+ my $vars = {
+ header => Template::Document->new({ ... }),
+ };
+
+template:
+
+ [% INCLUDE $header %]
+
+=head2 Local and Global Variables
+
+Any simple variables that you create, or any changes you make to
+existing variables, will only persist while the template is being
+processed. The top-level variable hash is copied before processing
+begins and any changes to variables are made in this copy, leaving the
+original intact. The same thing happens when you INCLUDE another
+template. The current namespace hash is cloned to prevent any
+variable changes made in the included template from interfering with
+existing variables. The PROCESS option bypasses the localisation step
+altogether making it slightly faster, but requiring greater attention
+to the possibility of side effects caused by creating or changing any
+variables within the processed template.
+
+ [% BLOCK change_name %]
+ [% name = 'bar' %]
+ [% END %]
+
+ [% name = 'foo' %]
+ [% INCLUDE change_name %]
+ [% name %] # foo
+ [% PROCESS change_name %]
+ [% name %] # bar
+
+Dotted compound variables behave slightly differently because the
+localisation process is only skin deep. The current variable
+namespace hash is copied, but no attempt is made to perform a
+deep-copy of other structures within it (hashes, arrays, objects,
+etc). A variable referencing a hash, for example, will be copied to
+create a new reference but which points to the same hash. Thus, the
+general rule is that simple variables (undotted variables) are
+localised, but existing complex structures (dotted variables) are not.
+
+ [% BLOCK all_change %]
+ [% x = 20 %] # changes copy
+ [% y.z = 'zulu' %] # changes original
+ [% END %]
+
+ [% x = 10
+ y = { z => 'zebra' }
+ %]
+ [% INCLUDE all_change %]
+ [% x %] # still '10'
+ [% y.z %] # now 'zulu'
+
+
+If you create a complex structure such as a hash or list reference
+within a local template context then it will cease to exist when
+the template is finished processing.
+
+ [% BLOCK new_stuff %]
+ [% # define a new 'y' hash array in local context
+ y = { z => 'zulu' }
+ %]
+ [% END %]
+
+ [% x = 10 %]
+ [% INCLUDE new_stuff %]
+ [% x %] # outputs '10'
+ [% y %] # nothing, y is undefined
+
+Similarly, if you update an element of a compound variable which
+I already exists then a hash will be created automatically
+and deleted again at the end of the block.
+
+ [% BLOCK new_stuff %]
+ [% y.z = 'zulu' %]
+ [% END %]
+
+However, if the hash I already exist then you will modify the
+original with permanent effect. To avoid potential confusion, it is
+recommended that you don't update elements of complex variables from
+within blocks or templates included by another.
+
+If you want to create or update truly global variables then you can
+use the 'global' namespace. This is a hash array automatically created
+in the top-level namespace which all templates, localised or otherwise
+see the same reference to. Changes made to variables within this
+hash are visible across all templates.
+
+ [% global.version = 123 %]
+
+=head2 Compile Time Constant Folding
+
+In addition to variables that get resolved each time a template is
+processed, you can also define variables that get resolved just once
+when the template is compiled. This generally results in templates
+processing faster because there is less work to be done.
+
+To define compile-time constants, specify a CONSTANTS hash as a
+constructor item as per VARIABLES. The CONSTANTS hash can contain any
+kind of complex, nested, or dynamic data structures, just like regular
+variables.
+
+ my $tt = Template->new({
+ CONSTANTS => {
+ version => 3.14,
+ release => 'skyrocket',
+ col => {
+ back => '#ffffff',
+ fore => '#000000',
+ },
+ myobj => My::Object->new(),
+ mysub => sub { ... },
+ joint => ', ',
+ },
+ });
+
+Within a template, you access these variables using the 'constants'
+namespace prefix.
+
+ Version [% constants.version %] ([% constants.release %])
+
+ Background: [% constants.col.back %]
+
+When the template is compiled, these variable references are replaced
+with the corresponding value. No further variable lookup is then
+required when the template is processed.
+
+You can call subroutines, object methods, and even virtual methods on
+constant variables.
+
+ [% constants.mysub(10, 20) %]
+ [% constants.myobj(30, 40) %]
+ [% constants.col.keys.sort.join(', ') %]
+
+One important proviso is that any arguments you pass to subroutines
+or methods must also be literal values or compile time constants.
+
+For example, these are both fine:
+
+ # literal argument
+ [% constants.col.keys.sort.join(', ') %]
+
+ # constant argument
+ [% constants.col.keys.sort.join(constants.joint) %]
+
+But this next example will raise an error at parse time because
+'joint' is a runtime variable and cannot be determined at compile
+time.
+
+ # ERROR: runtime variable argument!
+ [% constants.col.keys.sort.join(joint) %]
+
+The CONSTANTS_NAMESPACE option can be used to provide a different
+namespace prefix for constant variables. For example:
+
+ my $tt = Template->new({
+ CONSTANTS => {
+ version => 3.14,
+ # ...etc...
+ },
+ CONSTANTS_NAMESPACE => 'const',
+ });
+
+Constants would then be referenced in templates as:
+
+ [% const.version %]
+
+=head2 Special Variables
+
+A number of special variables are automatically defined by the Template
+Toolkit.
+
+=over 4
+
+=item template
+
+The 'template' variable contains a reference to the main template
+being processed, in the form of a Template::Document object. This
+variable is correctly defined within PRE_PROCESS, PROCESS and
+POST_PROCESS templates, allowing standard headers, footers, etc., to
+access metadata items from the main template. The 'name' and
+'modtime' metadata items are automatically provided, giving the
+template name and modification time in seconds since the epoch.
+
+Note that the 'template' variable always references the top-level
+template, even when processing other template components via INCLUDE,
+PROCESS, etc.
+
+=item component
+
+The 'component' variable is like 'template' but always contains a
+reference to the current, innermost template component being processed.
+In the main template, the 'template' and 'component' variable will
+reference the same Template::Document object. In any other template
+component called from the main template, the 'template' variable
+will remain unchanged, but 'component' will contain a new reference
+to the current component.
+
+This example should demonstrate the difference:
+
+ $template->process('foo')
+ || die $template->error(), "\n";
+
+'foo':
+
+ [% template.name %] # foo
+ [% component.name %] # foo
+ [% PROCESS footer %]
+
+'footer':
+
+ [% template.name %] # foo
+ [% component.name %] # footer
+
+=item loop
+
+Within a FOREACH loop, the 'loop' variable references the Template::Iterator
+object responsible for controlling the loop.
+
+ [% FOREACH item = [ 'foo', 'bar', 'baz' ] -%]
+ [% "Items:\n" IF loop.first -%]
+ [% loop.count %]/[% loop.size %]: [% item %]
+ [% END %]
+
+=item error
+
+Within a CATCH block, the 'error' variable contains a reference to the
+Template::Exception object thrown from within the TRY block. The
+'type' and 'info' methods can be called or the variable itself can
+be printed for automatic stringification into a message of the form
+"$type error - $info". See L for further details.
+
+ [% TRY %]
+ ...
+ [% CATCH %]
+ [% error %]
+ [% END %]
+
+=item content
+
+The WRAPPER method captures the output from a template block and then
+includes a named template, passing the captured output as the 'content'
+variable.
+
+ [% WRAPPER box %]
+ Be not afeard; the isle is full of noises,
+ Sounds and sweet airs, that give delight and hurt not.
+ [% END %]
+
+ [% BLOCK box %]
+
+
+
+ [% content %]
+
+
+
+ [% END %]
+
+=back
+
+=head2 Compound Variables
+
+Compound 'dotted' variables may contain any number of separate
+elements. Each element may evaluate to any of the permitted variable
+types and the processor will then correctly use this value to evaluate
+the rest of the variable. Arguments may be passed to any of the
+intermediate elements.
+
+ [% myorg.people.sort('surname').first.fullname %]
+
+Intermediate variables may be used and will behave entirely as expected.
+
+ [% sorted = myorg.people.sort('surname') %]
+ [% sorted.first.fullname %]
+
+This simplified dotted notation has the benefit of hiding the
+implementation details of your data. For example, you could implement
+a data structure as a hash array one day and then change it to an
+object the next without requiring any change to the templates.
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Views.pod b/lib/Template/Manual/Views.pod
new file mode 100644
index 0000000..7bc53b0
--- /dev/null
+++ b/lib/Template/Manual/Views.pod
@@ -0,0 +1,642 @@
+#============================================================= -*-perl-*-
+#
+# Template::Manual::Views
+#
+# DESCRIPTION
+# This section describes dynamic views: a powerful but experimental
+# new feature in version 2.01 of the Template Toolkit.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Manual::Views - Template Toolkit views (experimental)
+
+=head1 DESCRIPTION
+
+This section describes dynamic views: a powerful but experimental new
+feature in version 2.01 of the Template Toolkit.
+
+A view is effectively a collection of templates and/or variable
+definitions which can be passed around as a self-contained unit. This
+then represents a particular interface or presentation style for other
+objects or items of data.
+
+You can use views to implement custom "skins" for an application or
+content set. You can use them to help simplify the presentation of
+common objects or data types. You can even use then to automate the
+presentation of complex data structures such as that generated in an
+XML::DOM tree or similar. You let an iterator do the walking, and the
+view does the talking (or in this case, the presenting). Voila - you
+have view independant, structure shy traversal using templates.
+
+In general, views can be used in a number of different ways to achieve
+several different things. They elegantly solve some problems which
+were otherwise difficult or complicated, and make easy some things
+that were previously hard.
+
+At the moment, they're still very experimental. The directive syntax
+and underlying API are likely to change quite considerably over the
+next version or two. Please be very wary about building your
+multi-million dollar e-commerce solutions based around this feature.
+
+=head2 Views as Template Collectors/Providers
+
+The VIEW directive starts a view definition and includes a name by
+which the view can be referenced. The view definition continues up to
+the matching END directive.
+
+ [% VIEW myview %]
+ ...
+ [% END %]
+
+The first role of a view is to act as a collector and provider of templates.
+The include() method can be called on a view to effectively do the same
+thing as the INCLUDE directive. The template name is passed as the first
+argument, followed by any local variable definitions for the template.
+
+ [% myview.include('header', title='The Title') %]
+
+ # equivalent to
+ [% INCLUDE header title='The Title' %]
+
+Views accept a number of configuration options which can be used to control
+different aspects of their behaviour. The 'prefix' and 'suffix' options
+can be specified to add a fixed prefix and/or suffix to the name of each template.
+
+ [% VIEW myview
+ prefix = 'my/'
+ suffix = '.tt2' ;
+ END
+ %]
+
+Now the call
+
+ [% myview.include('header', title='The Title') %]
+
+is equivalent to
+
+ [% INCLUDE my/header.tt2 title='The Title' %]
+
+Views provide an AUTOLOAD method which maps method names to the
+include() method. Thus, the following are all equivalent:
+
+ [% myview.include('header', title='Hello World') %]
+ [% myview.include_header(title='Hello World') %]
+ [% myview.header(title='Hello World') %]
+
+=head2 Local BLOCK Definitions
+
+A VIEW definition can include BLOCK definitions which remain local to
+the view. A request for a particular template will return a BLOCK,
+if defined, in preference to any other template of the same name.
+
+ [% BLOCK foo %]
+ public foo block
+ [% END %]
+
+ [% VIEW plain %]
+ [% BLOCK foo %]
+ plain foo block
+ [% END %]
+ [% END %]
+
+ [% VIEW fancy %]
+ [% BLOCK foo %]
+ fancy foo block
+ [% END %]
+ [% END %]
+
+ [% INCLUDE foo %] # public foo block
+ [% plain.foo %] # plain foo block
+ [% fancy.foo %] # fancy foo block
+
+In addition to BLOCK definitions, a VIEW can contain any other
+template directives. The entire VIEW definition block is processed to
+initialise the view but no output is generated (this may change RSN -
+and get stored as 'output' item, subsequently accessible as [%
+view.output %]). However, directives that have side-effects, such as
+those that update a variable, will have noticable consequences.
+
+=head2 Preserving Variable State within Views
+
+Views can also be used to save the values of any existing variables,
+or to create new ones at the point at which the view is defined.
+Unlike simple template metadata (META) which can only contain static
+string values, the view initialisation block can contain any template
+directives and generate any kind of dynamic output and/or data items.
+
+ [% VIEW my_web_site %]
+ [% view.title = title or 'My Cool Web Site' %]
+ [% view.author = "$abw.name, $abw.email" %]
+ [% view.sidebar = INCLUDE my/sidebar.tt2 %]
+ [% END %]
+
+Note that additional data items can be specified as arguments to the VIEW
+directive. Anything that doesn't look like a configuration parameter is
+assumed to be a data item. This can be a little hazardous, of course, because
+you never know when a new configuration item might get added which interferes
+with your data.
+
+ [% VIEW my_web_site
+ # config options
+ prefix = 'my/'
+ # misc data
+ title = title or 'My Cool Web Site'
+ author = "$abw.name, $abw.email"
+ sidebar = INCLUDE my/sidebar.tt2
+ %]
+ ...
+ [% END %]
+
+Outside of the view definition you can access the view variables as, for
+example:
+
+ [% my_web_site.title %]
+
+One important feature is the equivalence of simple variables and templates.
+You can implement the view item 'title' as a simple variable, a template
+defined in an external file, possibly with a prefix/suffix automatically
+appended, or as a local BLOCK definition within the [% VIEW %] ... [% END %]
+definition. If you use the syntax above then the view will Do The Right
+Thing to return the appropriate output.
+
+At the END of the VIEW definition the view is "sealed" to prevent you
+from accidentally updating any variable values. If you attempt to change
+the value of a variable after the END of the VIEW definition block then
+an 'view' error will be thrown.
+
+ [% TRY;
+ my_web_site.title = 'New Title';
+ CATCH;
+ error;
+ END
+ %]
+
+The error above will be reported as:
+
+ view error - cannot update item in sealed view: title
+
+The same is true if you pass a parameter to a view variable. This is
+interpreted as an attempt to update the variable and will raise the same
+warning.
+
+ [% my_web_site.title('New Title') %] # view error!
+
+You can set the 'silent' parameter to have the view ignore these
+parameters and simply return the variable value.
+
+ [% VIEW my_web_site
+ silent = 1
+ title = title or 'My Cool Web Site'
+ # ... ;
+ END
+ %]
+
+ [% my_web_site.title('Blah Blah') %] # My Cool Web Site
+
+Alternately, you can specify that a view is unsealed allowing existing
+variables to be updated and new variables defined.
+
+ [% VIEW my_web_site
+ sealed = 0
+ title = title or 'My Cool Web Site'
+ # ... ;
+ END
+ %]
+
+ [% my_web_site.title('Blah Blah') %] # Blah Blah
+ [% my_web_site.title %] # Blah Blah
+
+=head2 Inheritance, Delegation and Reuse
+
+Views can be inherited from previously defined views by use of the 'base'
+parameter. This example shows how a base class view is defined which
+applies a 'view/default/' prefix to all template names.
+
+ [% VIEW my.view.default
+ prefix = 'view/default/';
+ END
+ %]
+
+Thus the directive:
+
+ [% my.view.default.header(title='Hello World') %]
+
+is now equivalent to:
+
+ [% INCLUDE view/default/header title='Hello World' %]
+
+A second view can be defined which specifies the default view as a
+base.
+
+ [% VIEW my.view.fancy
+ base = my.view.default
+ prefix = 'view/fancy/';
+ END
+ %]
+
+Now the directive:
+
+ [% my.view.fancy.header(title='Hello World') %]
+
+will resolve to:
+
+ [% INCLUDE view/fancy/header title='Hello World' %]
+
+or if that doesn't exist, it will be handled by the base view as:
+
+ [% INCLUDE view/default/header title='Hello World' %]
+
+When a parent view is specified via the 'base' parameter, the
+delegation of a view to its parent for fetching templates and accessing
+user defined variables is automatic. You can also implement your own
+inheritance, delegation or other reuse patterns by explicitly
+delegating to other views.
+
+ [% BLOCK foo %]
+ public foo block
+ [% END %]
+
+ [% VIEW plain %]
+ [% BLOCK foo %]
+ [% PROCESS foo %]
+ [% END %]
+ [% END %]
+
+ [% VIEW fancy %]
+ [% BLOCK foo %]
+ [% plain.foo | replace('plain', 'fancy') %]
+ [% END %]
+ [% END %]
+
+ [% plain.foo %] # public foo block
+ [% fancy.foo %] # public foo block
+
+Note that the regular INCLUDE/PROCESS/WRAPPER directives work entirely
+independantly of views and will always get the original, unaltered
+template name rather than any local per-view definition.
+
+=head2 Self-Reference
+
+A reference to the view object under definition is available with the
+VIEW ... END block by its specified name and also by the special name
+'view' (similar to the C in a Perl method or the
+'this' pointer in C++, etc). The view is initially unsealed allowing
+any data items to be defined and updated within the VIEW ... END
+block. The view is automatically sealed at the end of the definition
+block, preventing any view data from being subsequently changed.
+
+(NOTE: sealing should be optional. As well as sealing a view to prevent
+updates (SEALED), it should be possible to set an option in the view to
+allow external contexts to update existing variables (UPDATE) or even
+create totally new view variables (CREATE)).
+
+ [% VIEW fancy %]
+ [% fancy.title = 'My Fancy Title' %]
+ [% fancy.author = 'Frank Open' %]
+ [% fancy.col = { bg => '#ffffff', bar => '#a0a0ff' } %]
+ [% END %]
+
+or
+
+ [% VIEW fancy %]
+ [% view.title = 'My Fancy Title' %]
+ [% view.author = 'Frank Open' %]
+ [% view.col = { bg => '#ffffff', bar => '#a0a0ff' } %]
+ [% END %]
+
+It makes no real difference in this case if you refer to the view by
+its name, 'fancy', or by the general name, 'view'. Outside of the
+view block, however, you should always use the given name, 'fancy':
+
+ [% fancy.title %]
+ [% fancy.author %]
+ [% fancy.col.bg %]
+
+The choice of given name or 'view' is much more important when it
+comes to BLOCK definitions within a VIEW. It is generally recommended
+that you use 'view' inside a VIEW definition because this is guaranteed
+to be correctly defined at any point in the future when the block gets
+called. The original name of the view might have long since been changed
+or reused but the self-reference via 'view' should always be intact and
+valid.
+
+Take the following VIEW as an example:
+
+ [% VIEW foo %]
+ [% view.title = 'Hello World' %]
+ [% BLOCK header %]
+ Title: [% view.title %]
+ [% END %]
+ [% END %]
+
+Even if we rename the view, or create a new 'foo' variable, the header
+block still correctly accesses the 'title' attribute of the view to
+which it belongs. Whenever a view BLOCK is processed, the 'view'
+variable is always updated to contain the correct reference to the
+view object to which it belongs.
+
+ [% bar = foo %]
+ [% foo = { title => "New Foo" } %] # no problem
+ [% bar.header %] # => Title: Hello World
+
+=head2 Saving References to External Views
+
+When it comes to view inheritance, it's always a good idea to take a
+local copy of a parent or delegate view and store it as an attribute
+within the view for later use. This ensures that the correct view
+reference is always available, even if the external name of a view
+has been changed.
+
+ [% VIEW plain %]
+ ...
+ [% END %]
+
+ [% VIEW fancy %]
+ [% view.plain = plain %]
+ [% BLOCK foo %]
+ [% view.plain.foo | replace('plain', 'fancy') %]
+ [% END %]
+ [% END %]
+
+ [% plain.foo %] # => public foo block
+ [% plain = 'blah' %] # no problem
+ [% fancy.foo %] # => public foo block
+
+
+=head2 Views as Data Presenters
+
+Another key role of a view is to act as a dispatcher to automatically
+apply the correct template to present a particular object or data
+item. This is handled via the print() method.
+
+Here's an example:
+
+ [% VIEW foo %]
+
+ [% BLOCK text %]
+ Some text: [% item %]
+ [% END %]
+
+ [% BLOCK hash %]
+ a hash:
+ [% FOREACH key = item.keys.sort -%]
+ [% key %] => [% item.$key %]
+ [% END -%]
+ [% END %]
+
+ [% BLOCK list %]
+ a list: [% item.sort.join(', ') %]
+ [% END %]
+
+ [% END %]
+
+We can now use the view to print text, hashes or lists. The print()
+method includes the right template depending on the typing of the
+argument (or arguments) passed.
+
+ [% some_text = 'I read the news today, oh boy.' %]
+ [% a_hash = { house => 'Lords', hall => 'Albert' } %]
+ [% a_list = [ 'sure', 'Nobody', 'really' ] %]
+
+ [% view.print(some_text) %]
+ # Some text: I read the news today, oh boy.
+
+ [% view.print(a_hash) %]
+ # a hash:
+ hall => Albert
+ house => Lords
+ [% view.print(a_list) %]
+ # a list: Nobody, really, sure
+
+
+You can also provide templates to print objects of any other class.
+The class name is mapped to a template name with all non-word
+character sequences such as '::' converted to a single '_'.
+
+ [% VIEW foo %]
+ [% BLOCK Foo_Bar %]
+ a Foo::Bar object:
+ thingies: [% view.print(item.thingies) %]
+ doodahs: [% view.print(item.doodahs) %]
+ [% END %]
+ [% END %]
+
+ [% USE fubar = Foo::Bar(...) %]
+
+ [% foo.print(fubar) %]
+
+Note how we use the view object to display various items within the
+objects ('thingies' and 'doodahs'). We don't need to worry what
+kind of data these represent (text, list, hash, etc) because we can
+let the view worry about it, automatically mapping the data type to
+the correct template.
+
+Views may define their own type =E template map.
+
+ [% VIEW foo
+ map = { TEXT => 'plain_text',
+ ARRAY => 'show_list',
+ HASH => 'show_hash',
+ My::Module => 'template_name'
+ default => 'any_old_data'
+ }
+ %]
+ [% BLOCK plain_text %]
+ ...
+ [% END %]
+
+ ...
+
+ [% END %]
+
+They can also provide a 'default' map entry, specified as part of the 'map'
+hash or as a parameter by itself.
+
+
+ [% VIEW foo
+ map = { ... },
+ default = 'whatever'
+ %]
+ ...
+ [% END %]
+
+or
+
+ [% VIEW foo %]
+ [% view.map = { ... }
+ view.default = 'whatever'
+ %]
+ ...
+ [% END %]
+
+The print() method provides one more piece of magic. If you pass it a
+reference to an object which provides a present() method, then the
+method will be called passing the view as an argument. This then gives
+any object a chance to determine how it should be presented via the
+view.
+
+ package Foo::Bar;
+
+ ...
+
+ sub present {
+ my ($self, $view) = @_;
+ return "a Foo::Bar object:\n"
+ . "thingies: " . $view.print($self->{ _THINGIES }) . "\n"
+ . "doodahs: " . $view.print($self->{ _DOODAHS }) . "\n";
+ }
+
+The object is free to delve deeply into its innards and mess around with
+its own private data, before presenting the relevant data via the view.
+In a more complex example, a present() method might walk part of a tree
+making calls back against the view to present different nodes within the
+tree. We may not want to expose the internal structure of the tree
+(because that would break encapsulation and make our presentation code
+dependant on it) but we want to have some way of walking the tree and
+presenting items found in a particular manner.
+
+This is known as Structure Shy Traversal. Our view object doesn't require
+prior knowledge about the internal structure of any data set to be able
+to traverse it and present the data contained therein. The data items
+themselves, via the present() method, can implement the internal iterators
+to guide the view along the right path to presentation happiness.
+
+The upshot is that you can use views to greatly simplify the display
+of data structures like XML::DOM trees. The documentation for the
+Template::Plugins::XML::DOM module contains an example of this. In
+essence, it looks something like this:
+
+XML source:
+
+
+
+
+
+
+TT View:
+
+ [% VIEW fancy %]
+ [% BLOCK user %]
+ User: [% item.name %]
+ [% item.content(myview) %]
+ [% END %]
+
+ [% BLOCK project %]
+ Project: [% project.id %] - [% project.name %]
+ [% END %]
+ [% END %]
+
+Generate view:
+
+ [% USE dom = XML.DOM %]
+ [% fancy.print(dom.parse(xml_source)) %]
+
+Output:
+
+ User: Andy Wardley
+ Project: iCan - iCan, but theyCan't
+ Project: p45 - iDid, but theyDidn't
+
+The same approach can be applied to many other areas. Here's an example from
+the File/Directory plugins.
+
+ [% VIEW myview %]
+ [% BLOCK file %]
+ - [% item.name %]
+ [% END %]
+
+ [% BLOCK directory %]
+ * [% item.name %]
+ [% item.content(myview) FILTER indent %]
+ [% END %]
+ [% END %]
+
+ [% USE dir = Directory(dirpath) %]
+ [% myview.print(dir) %]
+
+And here's the same approach use to convert Pod documentation to any
+other format via template.
+
+ [% # load Pod plugin and parse source file into Pod Object Model
+ USE Pod;
+ pom = Pod.parse_file(my_pod_file);
+
+ # define view to map all Pod elements to "pod/html/xxx" templates
+ VIEW pod2html
+ prefix='pod/html';
+ END;
+
+ # now print document via view (i.e. as HTML)
+ pod2html.print(pom)
+ %]
+
+Here we simply define a template prefix for the view which causes the
+view to look for 'pod/html/head1', 'pod/html/head2', 'pod/html/over'
+as templates to present the different sections of the parsed Pod document.
+
+There are some examples in the Template Toolkit test suite: t/pod.t and
+t/view.t which may shed some more light on this. See the distribution
+sub-directory 'examples/pod/html' for examples of Pod -E HTML templates.
+
+(This documentation is incomplete but I'm not going to get it 100% pefect
+until the syntax and API stabilise).
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Modules.pod b/lib/Template/Modules.pod
new file mode 100644
index 0000000..78dadb8
--- /dev/null
+++ b/lib/Template/Modules.pod
@@ -0,0 +1,448 @@
+#============================================================= -*-perl-*-
+#
+# Template::Modules
+#
+# DESCRIPTION
+# This section contains the documentation for the modules that
+# comprise the Template Toolkit.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+#
+#
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Modules - Core modules comprising the Template Toolkit
+
+=head1 DESCRIPTION
+
+This section contains the documentation for the modules that comprise
+the Template Toolkit.
+
+=over 4
+
+=item L
+
+Front-end module to the Template Toolkit
+
+
+
+=item L
+
+Base class module implementing common functionality
+
+
+
+=item L
+
+Factory module for instantiating other TT2 modules
+
+
+
+=item L
+
+Defines constants for the Template Toolkit
+
+
+
+=item L
+
+Runtime context in which templates are processed
+
+
+
+=item L
+
+Compiled template document object
+
+
+
+=item L
+
+Exception handling class module
+
+
+
+=item L
+
+Post-processing filters for template blocks
+
+
+
+=item L
+
+Data iterator used by the FOREACH directive
+
+
+
+=item L
+
+Compile time constant folding
+
+
+
+=item L
+
+LALR(1) parser for compiling template documents
+
+
+
+=item L
+
+Base class for Template Toolkit plugins
+
+
+
+=item L
+
+Plugin provider module
+
+
+
+=item L
+
+Provider module for loading/compiling templates
+
+
+
+=item L
+
+General purpose template processing service
+
+
+
+=item L
+
+Magical storage for template variables
+
+
+
+=item L
+
+Experimetal stash allowing list/scalar context definition
+
+
+
+=item L
+
+Experimetal high-speed stash written in XS
+
+
+
+=item L
+
+Module for automating TT2 test scripts
+
+
+
+=item L
+
+Interface to Text::Autoformat module
+
+
+
+=item L
+
+Interface to the CGI module
+
+
+
+=item L
+
+Template interface to the DBI module
+
+
+
+=item L
+
+Plugin to construct records from a simple data file
+
+
+
+=item L
+
+Plugin to generate formatted date strings
+
+
+
+=item L
+
+Plugin for generating directory listings
+
+
+
+=item L
+
+Plugin interface to Data::Dumper
+
+
+
+=item L
+
+Plugin providing information about files
+
+
+
+=item L
+
+Base class for plugin filters
+
+
+
+=item L
+
+Plugin to create formatting functions
+
+
+
+=item L
+
+Interface to GD Graphics Library
+
+
+
+=item L
+
+Interface to GD module Polygon class
+
+
+
+=item L
+
+Interface to GD module constants
+
+
+
+=item L
+
+Text utilities for use with GD
+
+
+
+=item L
+
+Draw aligned strings in GD images
+
+
+
+=item L
+
+Break and wrap strings in GD images
+
+
+
+=item L
+
+Create line graphs with axes and legends
+
+
+
+=item L
+
+Create 3D line graphs with axes and legends
+
+
+
+=item L
+
+Create bar graphs with axes and legends
+
+
+
+=item L
+
+Create 3D bar graphs with axes and legends
+
+
+
+=item L
+
+Create point graphs with axes and legends
+
+
+
+=item L
+
+Create line/point graphs with axes and legends
+
+
+
+=item L
+
+Create area graphs with axes and legends
+
+
+
+=item L
+
+Create mixed graphs with axes and legends
+
+
+
+=item L
+
+Create pie charts with legends
+
+
+
+=item L
+
+Create 3D pie charts with legends
+
+
+
+=item L
+
+Plugin to create HTML elements
+
+
+
+=item L
+
+Plugin access to image sizes
+
+
+
+=item L
+
+Plugin to create iterators (Template::Iterator)
+
+
+
+=item L
+
+Plugin interface to mathematical functions
+
+
+
+=item L
+
+Plugin interface to Pod::POM (Pod Object Model)
+
+
+
+=item L
+
+Base class for procedural plugins
+
+
+
+=item L
+
+Object oriented interface for string manipulation
+
+
+
+=item L
+
+Plugin to present data in a table
+
+
+
+=item L
+
+Plugin to construct complex URLs
+
+
+
+=item L
+
+Plugin to create views (Template::View)
+
+
+
+=item L
+
+Plugin interface to Text::Wrap
+
+
+
+=item L
+
+Plugin interface to XML::DOM
+
+
+
+=item L
+
+Plugin interface to XML::RSS
+
+
+
+=item L
+
+Plugin interface to XML::Simple
+
+
+
+=item L
+
+Simple XML stylesheet transfomations
+
+
+
+=item L
+
+Plugin interface to XML::XPath
+
+
+
+
+
+=back
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Namespace/Constants.pm b/lib/Template/Namespace/Constants.pm
new file mode 100644
index 0000000..e1b5114
--- /dev/null
+++ b/lib/Template/Namespace/Constants.pm
@@ -0,0 +1,205 @@
+#================================================================= -*-Perl-*-
+#
+# Template::Namespace::Constants
+#
+# DESCRIPTION
+# Plugin compiler module for performing constant folding at compile time
+# on variables in a particular namespace.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2002 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# REVISION
+# $Id: Constants.pm,v 1.22 2004/01/13 16:20:36 abw Exp $
+#
+#============================================================================
+
+package Template::Namespace::Constants;
+
+use strict;
+use Template::Base;
+use Template::Config;
+use Template::Directive;
+use Template::Exception;
+
+use base qw( Template::Base );
+use vars qw( $VERSION $DEBUG );
+
+$VERSION = sprintf("%d.%02d", q$Revision: 1.22 $ =~ /(\d+)\.(\d+)/);
+$DEBUG = 0 unless defined $DEBUG;
+
+
+sub _init {
+ my ($self, $config) = @_;
+ $self->{ STASH } = Template::Config->stash($config)
+ || return $self->error(Template::Config->error());
+ return $self;
+}
+
+
+
+#------------------------------------------------------------------------
+# ident(\@ident) foo.bar(baz)
+#------------------------------------------------------------------------
+
+sub ident {
+ my ($self, $ident) = @_;
+ my @save = @$ident;
+
+ # discard first node indicating constants namespace
+ splice(@$ident, 0, 2);
+
+ my $nelems = @$ident / 2;
+ my ($e, $result);
+ local $" = ', ';
+
+ print STDERR "constant ident [ @$ident ] " if $DEBUG;
+
+ foreach $e (0..$nelems-1) {
+ # node name must be a constant
+ unless ($ident->[$e * 2] =~ s/^'(.+)'$/$1/s) {
+ $self->DEBUG(" * deferred (non-constant item: ", $ident->[$e * 2], ")\n")
+ if $DEBUG;
+ return Template::Directive->ident(\@save);
+ }
+
+ # if args is non-zero then it must be eval'ed
+ if ($ident->[$e * 2 + 1]) {
+ my $args = $ident->[$e * 2 + 1];
+ my $comp = eval "$args";
+ if ($@) {
+ $self->DEBUG(" * deferred (non-constant args: $args)\n") if $DEBUG;
+ return Template::Directive->ident(\@save);
+ }
+ $self->DEBUG("($args) ") if $comp && $DEBUG;
+ $ident->[$e * 2 + 1] = $comp;
+ }
+ }
+
+
+ $result = $self->{ STASH }->get($ident);
+
+ if (! length $result || ref $result) {
+ my $reason = length $result ? 'reference' : 'no result';
+ $self->DEBUG(" * deferred ($reason)\n") if $DEBUG;
+ return Template::Directive->ident(\@save);
+ }
+
+ $result =~ s/'/\\'/g;
+
+ $self->DEBUG(" * resolved => '$result'\n") if $DEBUG;
+
+ return "'$result'";
+}
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Namespace::Constants - Compile time constant folding
+
+=head1 SYNOPSIS
+
+ # easy way to define constants
+ use Template;
+
+ my $tt = Template->new({
+ CONSTANTS => {
+ pi => 3.14,
+ e => 2.718,
+ },
+ });
+
+ # nitty-gritty, hands-dirty way
+ use Template::Namespace::Constants;
+
+ my $tt = Template->new({
+ NAMESPACE => {
+ constants => Template::Namespace::Constants->new({
+ pi => 3.14,
+ e => 2.718,
+ },
+ },
+ });
+
+=head1 DESCRIPTION
+
+The Template::Namespace::Constants module implements a namespace handler
+which is plugged into the Template::Directive compiler module. This then
+performs compile time constant folding of variables in a particular namespace.
+
+=head1 PUBLIC METHODS
+
+=head2 new(\%constants)
+
+The new() constructor method creates and returns a reference to a new
+Template::Namespace::Constants object. This creates an internal stash
+to store the constant variable definitions passed as arguments.
+
+ my $handler = Template::Namespace::Constants->new({
+ pi => 3.14,
+ e => 2.718,
+ });
+
+=head2 ident(\@ident)
+
+Method called to resolve a variable identifier into a compiled form. In this
+case, the method fetches the corresponding constant value from its internal
+stash and returns it.
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+=head1 VERSION
+
+1.22, distributed as part of the
+Template Toolkit version 2.13, released on 30 January 2004.
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Parser.pm b/lib/Template/Parser.pm
new file mode 100644
index 0000000..68bf9e0
--- /dev/null
+++ b/lib/Template/Parser.pm
@@ -0,0 +1,1446 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Parser
+#
+# DESCRIPTION
+# This module implements a LALR(1) parser and assocated support
+# methods to parse template documents into the appropriate "compiled"
+# format. Much of the parser DFA code (see _parse() method) is based
+# on Francois Desarmenien's Parse::Yapp module. Kudos to him.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# The following copyright notice appears in the Parse::Yapp
+# documentation.
+#
+# The Parse::Yapp module and its related modules and shell
+# scripts are copyright (c) 1998 Francois Desarmenien,
+# France. All rights reserved.
+#
+# You may use and distribute them under the terms of either
+# the GNU General Public License or the Artistic License, as
+# specified in the Perl README file.
+#
+#----------------------------------------------------------------------------
+#
+# $Id: Parser.pm,v 2.81 2004/01/13 16:19:15 abw Exp $
+#
+#============================================================================
+
+package Template::Parser;
+
+require 5.004;
+
+use strict;
+use vars qw( $VERSION $DEBUG $ERROR );
+use base qw( Template::Base );
+use vars qw( $TAG_STYLE $DEFAULT_STYLE $QUOTED_ESCAPES );
+
+use Template::Constants qw( :status :chomp );
+use Template::Directive;
+use Template::Grammar;
+
+# parser state constants
+use constant CONTINUE => 0;
+use constant ACCEPT => 1;
+use constant ERROR => 2;
+use constant ABORT => 3;
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.81 $ =~ /(\d+)\.(\d+)/);
+$DEBUG = 0 unless defined $DEBUG;
+$ERROR = '';
+
+
+#========================================================================
+# -- COMMON TAG STYLES --
+#========================================================================
+
+$TAG_STYLE = {
+ 'default' => [ '\[%', '%\]' ],
+ 'template1' => [ '[\[%]%', '%[\]%]' ],
+ 'metatext' => [ '%%', '%%' ],
+ 'html' => [ '' ],
+ 'mason' => [ '<%', '>' ],
+ 'asp' => [ '<%', '%>' ],
+ 'php' => [ '<\?', '\?>' ],
+ 'star' => [ '\[\*', '\*\]' ],
+};
+$TAG_STYLE->{ template } = $TAG_STYLE->{ tt2 } = $TAG_STYLE->{ default };
+
+
+$DEFAULT_STYLE = {
+ START_TAG => $TAG_STYLE->{ default }->[0],
+ END_TAG => $TAG_STYLE->{ default }->[1],
+# TAG_STYLE => 'default',
+ ANYCASE => 0,
+ INTERPOLATE => 0,
+ PRE_CHOMP => 0,
+ POST_CHOMP => 0,
+ V1DOLLAR => 0,
+ EVAL_PERL => 0,
+};
+
+$QUOTED_ESCAPES = {
+ n => "\n",
+ r => "\r",
+ t => "\t",
+};
+
+
+#========================================================================
+# ----- PUBLIC METHODS -----
+#========================================================================
+
+#------------------------------------------------------------------------
+# new(\%config)
+#
+# Constructor method.
+#------------------------------------------------------------------------
+
+sub new {
+ my $class = shift;
+ my $config = $_[0] && UNIVERSAL::isa($_[0], 'HASH') ? shift(@_) : { @_ };
+ my ($tagstyle, $debug, $start, $end, $defaults, $grammar, $hash, $key, $udef);
+
+ my $self = bless {
+ START_TAG => undef,
+ END_TAG => undef,
+ TAG_STYLE => 'default',
+ ANYCASE => 0,
+ INTERPOLATE => 0,
+ PRE_CHOMP => 0,
+ POST_CHOMP => 0,
+ V1DOLLAR => 0,
+ EVAL_PERL => 0,
+ FILE_INFO => 1,
+ GRAMMAR => undef,
+ _ERROR => '',
+ FACTORY => 'Template::Directive',
+ }, $class;
+
+ # update self with any relevant keys in config
+ foreach $key (keys %$self) {
+ $self->{ $key } = $config->{ $key } if defined $config->{ $key };
+ }
+ $self->{ FILEINFO } = [ ];
+
+ # DEBUG config item can be a bitmask
+ if (defined ($debug = $config->{ DEBUG })) {
+ $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PARSER
+ | Template::Constants::DEBUG_FLAGS );
+ $self->{ DEBUG_DIRS } = $debug & Template::Constants::DEBUG_DIRS;
+ }
+ # package variable can be set to 1 to support previous behaviour
+ elsif ($DEBUG == 1) {
+ $self->{ DEBUG } = Template::Constants::DEBUG_PARSER;
+ $self->{ DEBUG_DIRS } = 0;
+ }
+ # otherwise let $DEBUG be a bitmask
+ else {
+ $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER
+ | Template::Constants::DEBUG_FLAGS );
+ $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS;
+ }
+
+ $grammar = $self->{ GRAMMAR } ||= do {
+ require Template::Grammar;
+ Template::Grammar->new();
+ };
+
+ # build a FACTORY object to include any NAMESPACE definitions,
+ # but only if FACTORY isn't already an object
+ if ($config->{ NAMESPACE } && ! ref $self->{ FACTORY }) {
+ my $fclass = $self->{ FACTORY };
+ $self->{ FACTORY } = $fclass->new( NAMESPACE => $config->{ NAMESPACE } )
+ || return $class->error($fclass->error());
+ }
+
+ # load grammar rules, states and lex table
+ @$self{ qw( LEXTABLE STATES RULES ) }
+ = @$grammar{ qw( LEXTABLE STATES RULES ) };
+
+ $self->new_style($config)
+ || return $class->error($self->error());
+
+ return $self;
+}
+
+
+#------------------------------------------------------------------------
+# new_style(\%config)
+#
+# Install a new (stacked) parser style. This feature is currently
+# experimental but should mimic the previous behaviour with regard to
+# TAG_STYLE, START_TAG, END_TAG, etc.
+#------------------------------------------------------------------------
+
+sub new_style {
+ my ($self, $config) = @_;
+ my $styles = $self->{ STYLE } ||= [ ];
+ my ($tagstyle, $tags, $start, $end, $key);
+
+ # clone new style from previous or default style
+ my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } };
+
+ # expand START_TAG and END_TAG from specified TAG_STYLE
+ if ($tagstyle = $config->{ TAG_STYLE }) {
+ return $self->error("Invalid tag style: $tagstyle")
+ unless defined ($tags = $TAG_STYLE->{ $tagstyle });
+ ($start, $end) = @$tags;
+ $config->{ START_TAG } ||= $start;
+ $config->{ END_TAG } ||= $end;
+ }
+
+ foreach $key (keys %$DEFAULT_STYLE) {
+ $style->{ $key } = $config->{ $key } if defined $config->{ $key };
+ }
+ push(@$styles, $style);
+ return $style;
+}
+
+
+#------------------------------------------------------------------------
+# old_style()
+#
+# Pop the current parser style and revert to the previous one. See
+# new_style(). ** experimental **
+#------------------------------------------------------------------------
+
+sub old_style {
+ my $self = shift;
+ my $styles = $self->{ STYLE };
+ return $self->error('only 1 parser style remaining')
+ unless (@$styles > 1);
+ pop @$styles;
+ return $styles->[-1];
+}
+
+
+#------------------------------------------------------------------------
+# parse($text, $data)
+#
+# Parses the text string, $text and returns a hash array representing
+# the compiled template block(s) as Perl code, in the format expected
+# by Template::Document.
+#------------------------------------------------------------------------
+
+sub parse {
+ my ($self, $text, $info) = @_;
+ my ($tokens, $block);
+
+ $info->{ DEBUG } = $self->{ DEBUG_DIRS }
+ unless defined $info->{ DEBUG };
+
+# print "info: { ", join(', ', map { "$_ => $info->{ $_ }" } keys %$info), " }\n";
+
+ # store for blocks defined in the template (see define_block())
+ my $defblock = $self->{ DEFBLOCK } = { };
+ my $metadata = $self->{ METADATA } = [ ];
+
+ $self->{ _ERROR } = '';
+
+ # split file into TEXT/DIRECTIVE chunks
+ $tokens = $self->split_text($text)
+ || return undef; ## RETURN ##
+
+ push(@{ $self->{ FILEINFO } }, $info);
+
+ # parse chunks
+ $block = $self->_parse($tokens, $info);
+
+ pop(@{ $self->{ FILEINFO } });
+
+ return undef unless $block; ## RETURN ##
+
+ $self->debug("compiled main template document block:\n$block")
+ if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
+
+ return {
+ BLOCK => $block,
+ DEFBLOCKS => $defblock,
+ METADATA => { @$metadata },
+ };
+}
+
+
+
+#------------------------------------------------------------------------
+# split_text($text)
+#
+# Split input template text into directives and raw text chunks.
+#------------------------------------------------------------------------
+
+sub split_text {
+ my ($self, $text) = @_;
+ my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags);
+ my $style = $self->{ STYLE }->[-1];
+ my ($start, $end, $prechomp, $postchomp, $interp ) =
+ @$style{ qw( START_TAG END_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) };
+
+ my @tokens = ();
+ my $line = 1;
+
+ return \@tokens ## RETURN ##
+ unless defined $text && length $text;
+
+ # extract all directives from the text
+ while ($text =~ s/
+ ^(.*?) # $1 - start of line up to directive
+ (?:
+ $start # start of tag
+ (.*?) # $2 - tag contents
+ $end # end of tag
+ )
+ //sx) {
+
+ ($pre, $dir) = ($1, $2);
+ $pre = '' unless defined $pre;
+ $dir = '' unless defined $dir;
+
+ $postlines = 0; # denotes lines chomped
+ $prelines = ($pre =~ tr/\n//); # NULL - count only
+ $dirlines = ($dir =~ tr/\n//); # ditto
+
+ # the directive CHOMP options may modify the preceding text
+ for ($dir) {
+ # remove leading whitespace and check for a '-' chomp flag
+ s/^([-+\#])?\s*//s;
+ if ($1 && $1 eq '#') {
+ # comment out entire directive except for any chomp flag
+ $dir = ($dir =~ /([-+])$/) ? $1 : '';
+ }
+ else {
+ $chomp = ($1 && $1 eq '+') ? 0 : ($1 || $prechomp);
+# my $space = $prechomp == &Template::Constants::CHOMP_COLLAPSE
+ my $space = $prechomp == CHOMP_COLLAPSE
+ ? ' ' : '';
+
+ # chomp off whitespace and newline preceding directive
+ $chomp and $pre =~ s/(\n|^)([ \t]*)\Z/($1||$2) ? $space : ''/me
+ and $1 eq "\n"
+ and $prelines++;
+ }
+
+ # remove trailing whitespace and check for a '-' chomp flag
+ s/\s*([-+])?\s*$//s;
+ $chomp = ($1 && $1 eq '+') ? 0 : ($1 || $postchomp);
+ my $space = $postchomp == &Template::Constants::CHOMP_COLLAPSE
+ ? ' ' : '';
+
+ $postlines++
+ if $chomp and $text =~ s/
+ ^
+ ([ \t]*)\n # whitespace to newline
+ (?:(.|\n)|$) # any char (not EOF)
+ /
+ (($1||$2) ? $space : '') . (defined $2 ? $2 : '')
+ /ex;
+ }
+
+ # any text preceding the directive can now be added
+ if (length $pre) {
+ push(@tokens, $interp
+ ? [ $pre, $line, 'ITEXT' ]
+ : ('TEXT', $pre) );
+ $line += $prelines;
+ }
+
+ # and now the directive, along with line number information
+ if (length $dir) {
+ # the TAGS directive is a compile-time switch
+ if ($dir =~ /^TAGS\s+(.*)/i) {
+ my @tags = split(/\s+/, $1);
+ if (scalar @tags > 1) {
+ ($start, $end) = map { quotemeta($_) } @tags;
+ }
+ elsif ($tags = $TAG_STYLE->{ $tags[0] }) {
+ ($start, $end) = @$tags;
+ }
+ else {
+ warn "invalid TAGS style: $tags[0]\n";
+ }
+ }
+ else {
+ # DIRECTIVE is pushed as:
+ # [ $dirtext, $line_no(s), \@tokens ]
+ push(@tokens,
+ [ $dir,
+ ($dirlines
+ ? sprintf("%d-%d", $line, $line + $dirlines)
+ : $line),
+ $self->tokenise_directive($dir) ]);
+ }
+ }
+
+ # update line counter to include directive lines and any extra
+ # newline chomped off the start of the following text
+ $line += $dirlines + $postlines;
+ }
+
+ # anything remaining in the string is plain text
+ push(@tokens, $interp
+ ? [ $text, $line, 'ITEXT' ]
+ : ( 'TEXT', $text) )
+ if length $text;
+
+ return \@tokens; ## RETURN ##
+}
+
+
+
+#------------------------------------------------------------------------
+# interpolate_text($text, $line)
+#
+# Examines $text looking for any variable references embedded like
+# $this or like ${ this }.
+#------------------------------------------------------------------------
+
+sub interpolate_text {
+ my ($self, $text, $line) = @_;
+ my @tokens = ();
+ my ($pre, $var, $dir);
+
+
+ while ($text =~
+ /
+ ( (?: \\. | [^\$] ){1,3000} ) # escaped or non-'$' character [$1]
+ |
+ ( \$ (?: # embedded variable [$2]
+ (?: \{ ([^\}]*) \} ) # ${ ... } [$3]
+ |
+ ([\w\.]+) # $word [$4]
+ )
+ )
+ /gx) {
+
+ ($pre, $var, $dir) = ($1, $3 || $4, $2);
+
+ # preceding text
+ if (defined($pre) && length($pre)) {
+ $line += $pre =~ tr/\n//;
+ $pre =~ s/\\\$/\$/g;
+ push(@tokens, 'TEXT', $pre);
+ }
+ # $variable reference
+ if ($var) {
+ $line += $dir =~ tr/\n/ /;
+ push(@tokens, [ $dir, $line, $self->tokenise_directive($var) ]);
+ }
+ # other '$' reference - treated as text
+ elsif ($dir) {
+ $line += $dir =~ tr/\n//;
+ push(@tokens, 'TEXT', $dir);
+ }
+ }
+
+ return \@tokens;
+}
+
+
+
+#------------------------------------------------------------------------
+# tokenise_directive($text)
+#
+# Called by the private _parse() method when it encounters a DIRECTIVE
+# token in the list provided by the split_text() or interpolate_text()
+# methods. The directive text is passed by parameter.
+#
+# The method splits the directive into individual tokens as recognised
+# by the parser grammar (see Template::Grammar for details). It
+# constructs a list of tokens each represented by 2 elements, as per
+# split_text() et al. The first element contains the token type, the
+# second the token itself.
+#
+# The method tokenises the string using a complex (but fast) regex.
+# For a deeper understanding of the regex magic at work here, see
+# Jeffrey Friedl's excellent book "Mastering Regular Expressions",
+# from O'Reilly, ISBN 1-56592-257-3
+#
+# Returns a reference to the list of chunks (each one being 2 elements)
+# identified in the directive text. On error, the internal _ERROR string
+# is set and undef is returned.
+#------------------------------------------------------------------------
+
+sub tokenise_directive {
+ my ($self, $text, $line) = @_;
+ my ($token, $uctoken, $type, $lookup);
+ my $lextable = $self->{ LEXTABLE };
+ my $style = $self->{ STYLE }->[-1];
+ my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) };
+ my @tokens = ( );
+
+ while ($text =~
+ /
+ # strip out any comments
+ (\#[^\n]*)
+ |
+ # a quoted phrase matches in $3
+ (["']) # $2 - opening quote, ' or "
+ ( # $3 - quoted text buffer
+ (?: # repeat group (no backreference)
+ \\\\ # an escaped backslash \\
+ | # ...or...
+ \\\2 # an escaped quote \" or \' (match $1)
+ | # ...or...
+ . # any other character
+ | \n
+ )*? # non-greedy repeat
+ ) # end of $3
+ \2 # match opening quote
+ |
+ # an unquoted number matches in $4
+ (-?\d+(?:\.\d+)?) # numbers
+ |
+ # filename matches in $5
+ ( \/?\w+(?:(?:\/|::?)\w*)+ | \/\w+)
+ |
+ # an identifier matches in $6
+ (\w+) # variable identifier
+ |
+ # an unquoted word or symbol matches in $7
+ ( [(){}\[\]:;,\/\\] # misc parenthesis and symbols
+# | \-> # arrow operator (for future?)
+ | [+\-*] # math operations
+ | \$\{? # dollar with option left brace
+ | => # like '='
+ | [=!<>]?= | [!<>] # eqality tests
+ | &&? | \|\|? # boolean ops
+ | \.\.? # n..n sequence
+ | \S+ # something unquoted
+ ) # end of $7
+ /gmxo) {
+
+ # ignore comments to EOL
+ next if $1;
+
+ # quoted string
+ if (defined ($token = $3)) {
+ # double-quoted string may include $variable references
+ if ($2 eq '"') {
+ if ($token =~ /[\$\\]/) {
+ $type = 'QUOTED';
+ # unescape " and \ but leave \$ escaped so that
+ # interpolate_text() doesn't incorrectly treat it
+ # as a variable reference
+# $token =~ s/\\([\\"])/$1/g;
+ for ($token) {
+ s/\\([^\$nrt])/$1/g;
+ s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge;
+ }
+ push(@tokens, ('"') x 2,
+ @{ $self->interpolate_text($token) },
+ ('"') x 2);
+ next;
+ }
+ else {
+ $type = 'LITERAL';
+ $token =~ s['][\\']g;
+ $token = "'$token'";
+ }
+ }
+ else {
+ $type = 'LITERAL';
+ $token = "'$token'";
+ }
+ }
+ # number
+ elsif (defined ($token = $4)) {
+ $type = 'NUMBER';
+ }
+ elsif (defined($token = $5)) {
+ $type = 'FILENAME';
+ }
+ elsif (defined($token = $6)) {
+ # reserved words may be in lower case unless case sensitive
+ $uctoken = $anycase ? uc $token : $token;
+ if (defined ($type = $lextable->{ $uctoken })) {
+ $token = $uctoken;
+ }
+ else {
+ $type = 'IDENT';
+ }
+ }
+ elsif (defined ($token = $7)) {
+ # reserved words may be in lower case unless case sensitive
+ $uctoken = $anycase ? uc $token : $token;
+ unless (defined ($type = $lextable->{ $uctoken })) {
+ $type = 'UNQUOTED';
+ }
+ }
+
+ push(@tokens, $type, $token);
+
+# print(STDERR " +[ $type, $token ]\n")
+# if $DEBUG;
+ }
+
+# print STDERR "tokenise directive() returning:\n [ @tokens ]\n"
+# if $DEBUG;
+
+ return \@tokens; ## RETURN ##
+}
+
+
+#------------------------------------------------------------------------
+# define_block($name, $block)
+#
+# Called by the parser 'defblock' rule when a BLOCK definition is
+# encountered in the template. The name of the block is passed in the
+# first parameter and a reference to the compiled block is passed in
+# the second. This method stores the block in the $self->{ DEFBLOCK }
+# hash which has been initialised by parse() and will later be used
+# by the same method to call the store() method on the calling cache
+# to define the block "externally".
+#------------------------------------------------------------------------
+
+sub define_block {
+ my ($self, $name, $block) = @_;
+ my $defblock = $self->{ DEFBLOCK }
+ || return undef;
+
+ $self->debug("compiled block '$name':\n$block")
+ if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
+
+ $defblock->{ $name } = $block;
+
+ return undef;
+}
+
+sub push_defblock {
+ my $self = shift;
+ my $stack = $self->{ DEFBLOCK_STACK } ||= [];
+ push(@$stack, $self->{ DEFBLOCK } );
+ $self->{ DEFBLOCK } = { };
+}
+
+sub pop_defblock {
+ my $self = shift;
+ my $defs = $self->{ DEFBLOCK };
+ my $stack = $self->{ DEFBLOCK_STACK } || return $defs;
+ return $defs unless @$stack;
+ $self->{ DEFBLOCK } = pop @$stack;
+ return $defs;
+}
+
+
+#------------------------------------------------------------------------
+# add_metadata(\@setlist)
+#------------------------------------------------------------------------
+
+sub add_metadata {
+ my ($self, $setlist) = @_;
+ my $metadata = $self->{ METADATA }
+ || return undef;
+
+ push(@$metadata, @$setlist);
+
+ return undef;
+}
+
+
+#------------------------------------------------------------------------
+# location()
+#
+# Return Perl comment indicating current parser file and line
+#------------------------------------------------------------------------
+
+sub location {
+ my $self = shift;
+ return "\n" unless $self->{ FILE_INFO };
+ my $line = ${ $self->{ LINE } };
+ my $info = $self->{ FILEINFO }->[-1];
+ my $file = $info->{ path } || $info->{ name }
+ || '(unknown template)';
+ $line =~ s/\-.*$//; # might be 'n-n'
+ return "#line $line \"$file\"\n";
+}
+
+
+#========================================================================
+# ----- PRIVATE METHODS -----
+#========================================================================
+
+#------------------------------------------------------------------------
+# _parse(\@tokens, \@info)
+#
+# Parses the list of input tokens passed by reference and returns a
+# Template::Directive::Block object which contains the compiled
+# representation of the template.
+#
+# This is the main parser DFA loop. See embedded comments for
+# further details.
+#
+# On error, undef is returned and the internal _ERROR field is set to
+# indicate the error. This can be retrieved by calling the error()
+# method.
+#------------------------------------------------------------------------
+
+sub _parse {
+ my ($self, $tokens, $info) = @_;
+ my ($token, $value, $text, $line, $inperl);
+ my ($state, $stateno, $status, $action, $lookup, $coderet, @codevars);
+ my ($lhs, $len, $code); # rule contents
+ my $stack = [ [ 0, undef ] ]; # DFA stack
+
+# DEBUG
+# local $" = ', ';
+
+ # retrieve internal rule and state tables
+ my ($states, $rules) = @$self{ qw( STATES RULES ) };
+
+ # call the grammar set_factory method to install emitter factory
+ $self->{ GRAMMAR }->install_factory($self->{ FACTORY });
+
+ $line = $inperl = 0;
+ $self->{ LINE } = \$line;
+ $self->{ FILE } = $info->{ name };
+ $self->{ INPERL } = \$inperl;
+
+ $status = CONTINUE;
+ my $in_string = 0;
+
+ while(1) {
+ # get state number and state
+ $stateno = $stack->[-1]->[0];
+ $state = $states->[$stateno];
+
+ # see if any lookaheads exist for the current state
+ if (exists $state->{'ACTIONS'}) {
+
+ # get next token and expand any directives (i.e. token is an
+ # array ref) onto the front of the token list
+ while (! defined $token && @$tokens) {
+ $token = shift(@$tokens);
+ if (ref $token) {
+ ($text, $line, $token) = @$token;
+ if (ref $token) {
+ if ($info->{ DEBUG } && ! $in_string) {
+ # - - - - - - - - - - - - - - - - - - - - - - - - -
+ # This is gnarly. Look away now if you're easily
+ # frightened. We're pushing parse tokens onto the
+ # pending list to simulate a DEBUG directive like so:
+ # [% DEBUG msg line='20' text='INCLUDE foo' %]
+ # - - - - - - - - - - - - - - - - - - - - - - - - -
+ my $dtext = $text;
+ $dtext =~ s[(['\\])][\\$1]g;
+ unshift(@$tokens,
+ DEBUG => 'DEBUG',
+ IDENT => 'msg',
+ IDENT => 'line',
+ ASSIGN => '=',
+ LITERAL => "'$line'",
+ IDENT => 'text',
+ ASSIGN => '=',
+ LITERAL => "'$dtext'",
+ IDENT => 'file',
+ ASSIGN => '=',
+ LITERAL => "'$info->{ name }'",
+ (';') x 2,
+ @$token,
+ (';') x 2);
+ }
+ else {
+ unshift(@$tokens, @$token, (';') x 2);
+ }
+ $token = undef; # force redo
+ }
+ elsif ($token eq 'ITEXT') {
+ if ($inperl) {
+ # don't perform interpolation in PERL blocks
+ $token = 'TEXT';
+ $value = $text;
+ }
+ else {
+ unshift(@$tokens,
+ @{ $self->interpolate_text($text, $line) });
+ $token = undef; # force redo
+ }
+ }
+ }
+ else {
+ # toggle string flag to indicate if we're crossing
+ # a string boundary
+ $in_string = ! $in_string if $token eq '"';
+ $value = shift(@$tokens);
+ }
+ };
+ # clear undefined token to avoid 'undefined variable blah blah'
+ # warnings and let the parser logic pick it up in a minute
+ $token = '' unless defined $token;
+
+ # get the next state for the current lookahead token
+ $action = defined ($lookup = $state->{'ACTIONS'}->{ $token })
+ ? $lookup
+ : defined ($lookup = $state->{'DEFAULT'})
+ ? $lookup
+ : undef;
+ }
+ else {
+ # no lookahead actions
+ $action = $state->{'DEFAULT'};
+ }
+
+ # ERROR: no ACTION
+ last unless defined $action;
+
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ # shift (+ive ACTION)
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ if ($action > 0) {
+ push(@$stack, [ $action, $value ]);
+ $token = $value = undef;
+ redo;
+ };
+
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ # reduce (-ive ACTION)
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ ($lhs, $len, $code) = @{ $rules->[ -$action ] };
+
+ # no action imples ACCEPTance
+ $action
+ or $status = ACCEPT;
+
+ # use dummy sub if code ref doesn't exist
+ $code = sub { $_[1] }
+ unless $code;
+
+ @codevars = $len
+ ? map { $_->[1] } @$stack[ -$len .. -1 ]
+ : ();
+
+ eval {
+ $coderet = &$code( $self, @codevars );
+ };
+ if ($@) {
+ my $err = $@;
+ chomp $err;
+ return $self->_parse_error($err);
+ }
+
+ # reduce stack by $len
+ splice(@$stack, -$len, $len);
+
+ # ACCEPT
+ return $coderet ## RETURN ##
+ if $status == ACCEPT;
+
+ # ABORT
+ return undef ## RETURN ##
+ if $status == ABORT;
+
+ # ERROR
+ last
+ if $status == ERROR;
+ }
+ continue {
+ push(@$stack, [ $states->[ $stack->[-1][0] ]->{'GOTOS'}->{ $lhs },
+ $coderet ]),
+ }
+
+ # ERROR ## RETURN ##
+ return $self->_parse_error('unexpected end of input')
+ unless defined $value;
+
+ # munge text of last directive to make it readable
+# $text =~ s/\n/\\n/g;
+
+ return $self->_parse_error("unexpected end of directive", $text)
+ if $value eq ';'; # end of directive SEPARATOR
+
+ return $self->_parse_error("unexpected token ($value)", $text);
+}
+
+
+
+#------------------------------------------------------------------------
+# _parse_error($msg, $dirtext)
+#
+# Method used to handle errors encountered during the parse process
+# in the _parse() method.
+#------------------------------------------------------------------------
+
+sub _parse_error {
+ my ($self, $msg, $text) = @_;
+ my $line = $self->{ LINE };
+ $line = ref($line) ? $$line : $line;
+ $line = 'unknown' unless $line;
+
+ $msg .= "\n [% $text %]"
+ if defined $text;
+
+ return $self->error("line $line: $msg");
+}
+
+
+#------------------------------------------------------------------------
+# _dump()
+#
+# Debug method returns a string representing the internal state of the
+# object.
+#------------------------------------------------------------------------
+
+sub _dump {
+ my $self = shift;
+ my $output = "[Template::Parser] {\n";
+ my $format = " %-16s => %s\n";
+ my $key;
+
+ foreach $key (qw( START_TAG END_TAG TAG_STYLE ANYCASE INTERPOLATE
+ PRE_CHOMP POST_CHOMP V1DOLLAR )) {
+ my $val = $self->{ $key };
+ $val = '' unless defined $val;
+ $output .= sprintf($format, $key, $val);
+ }
+
+ $output .= '}';
+ return $output;
+}
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Parser - LALR(1) parser for compiling template documents
+
+=head1 SYNOPSIS
+
+ use Template::Parser;
+
+ $parser = Template::Parser->new(\%config);
+ $template = $parser->parse($text)
+ || die $parser->error(), "\n";
+
+=head1 DESCRIPTION
+
+The Template::Parser module implements a LALR(1) parser and associated methods
+for parsing template documents into Perl code.
+
+=head1 PUBLIC METHODS
+
+=head2 new(\%params)
+
+The new() constructor creates and returns a reference to a new
+Template::Parser object. A reference to a hash may be supplied as a
+parameter to provide configuration values. These may include:
+
+=over
+
+
+
+
+=item START_TAG, END_TAG
+
+The START_TAG and END_TAG options are used to specify character
+sequences or regular expressions that mark the start and end of a
+template directive. The default values for START_TAG and END_TAG are
+'[%' and '%]' respectively, giving us the familiar directive style:
+
+ [% example %]
+
+Any Perl regex characters can be used and therefore should be escaped
+(or use the Perl C function) if they are intended to
+represent literal characters.
+
+ my $parser = Template::Parser->new({
+ START_TAG => quotemeta('<+'),
+ END_TAG => quotemeta('+>'),
+ });
+
+example:
+
+ <+ INCLUDE foobar +>
+
+The TAGS directive can also be used to set the START_TAG and END_TAG values
+on a per-template file basis.
+
+ [% TAGS <+ +> %]
+
+
+
+
+
+
+=item TAG_STYLE
+
+The TAG_STYLE option can be used to set both START_TAG and END_TAG
+according to pre-defined tag styles.
+
+ my $parser = Template::Parser->new({
+ TAG_STYLE => 'star',
+ });
+
+Available styles are:
+
+ template [% ... %] (default)
+ template1 [% ... %] or %% ... %% (TT version 1)
+ metatext %% ... %% (Text::MetaText)
+ star [* ... *] (TT alternate)
+ php ... ?> (PHP)
+ asp <% ... %> (ASP)
+ mason <% ... > (HTML::Mason)
+ html (HTML comments)
+
+Any values specified for START_TAG and/or END_TAG will over-ride
+those defined by a TAG_STYLE.
+
+The TAGS directive may also be used to set a TAG_STYLE
+
+ [% TAGS html %]
+
+
+
+
+
+
+
+=item PRE_CHOMP, POST_CHOMP
+
+Anything outside a directive tag is considered plain text and is
+generally passed through unaltered (but see the INTERPOLATE option).
+This includes all whitespace and newlines characters surrounding
+directive tags. Directives that don't generate any output will leave
+gaps in the output document.
+
+Example:
+
+ Foo
+ [% a = 10 %]
+ Bar
+
+Output:
+
+ Foo
+
+ Bar
+
+The PRE_CHOMP and POST_CHOMP options can help to clean up some of this
+extraneous whitespace. Both are disabled by default.
+
+ my $parser = Template::Parser->new({
+ PRE_CHOMP => 1,
+ POST_CHOMP => 1,
+ });
+
+With PRE_CHOMP set to 1, the newline and whitespace preceding a directive
+at the start of a line will be deleted. This has the effect of
+concatenating a line that starts with a directive onto the end of the
+previous line.
+
+ Foo <----------.
+ |
+ ,---(PRE_CHOMP)----'
+ |
+ `-- [% a = 10 %] --.
+ |
+ ,---(POST_CHOMP)---'
+ |
+ `-> Bar
+
+With POST_CHOMP set to 1, any whitespace after a directive up to and
+including the newline will be deleted. This has the effect of joining
+a line that ends with a directive onto the start of the next line.
+
+If PRE_CHOMP or POST_CHOMP is set to 2, then instead of removing all
+the whitespace, the whitespace will be collapsed to a single space.
+This is useful for HTML, where (usually) a contiguous block of
+whitespace is rendered the same as a single space.
+
+You may use the CHOMP_NONE, CHOMP_ALL, and CHOMP_COLLAPSE constants
+from the Template::Constants module to deactivate chomping, remove
+all whitespace, or collapse whitespace to a single space.
+
+PRE_CHOMP and POST_CHOMP can be activated for individual directives by
+placing a '-' immediately at the start and/or end of the directive.
+
+ [% FOREACH user = userlist %]
+ [%- user -%]
+ [% END %]
+
+The '-' characters activate both PRE_CHOMP and POST_CHOMP for the one
+directive '[%- name -%]'. Thus, the template will be processed as if
+written:
+
+ [% FOREACH user = userlist %][% user %][% END %]
+
+Note that this is the same as if PRE_CHOMP and POST_CHOMP were set
+to CHOMP_ALL; the only way to get the CHOMP_COLLAPSE behavior is
+to set PRE_CHOMP or POST_CHOMP accordingly. If PRE_CHOMP or POST_CHOMP
+is already set to CHOMP_COLLAPSE, using '-' will give you CHOMP_COLLAPSE
+behavior, not CHOMP_ALL behavior.
+
+Similarly, '+' characters can be used to disable PRE_CHOMP or
+POST_CHOMP (i.e. leave the whitespace/newline intact) options on a
+per-directive basis.
+
+ [% FOREACH user = userlist %]
+ User: [% user +%]
+ [% END %]
+
+With POST_CHOMP enabled, the above example would be parsed as if written:
+
+ [% FOREACH user = userlist %]User: [% user %]
+ [% END %]
+
+
+
+
+
+=item INTERPOLATE
+
+The INTERPOLATE flag, when set to any true value will cause variable
+references in plain text (i.e. not surrounded by START_TAG and END_TAG)
+to be recognised and interpolated accordingly.
+
+ my $parser = Template::Parser->new({
+ INTERPOLATE => 1,
+ });
+
+Variables should be prefixed by a '$' to identify them. Curly braces
+can be used in the familiar Perl/shell style to explicitly scope the
+variable name where required.
+
+ # INTERPOLATE => 0
+
+
+ [% myorg.name %]
+
+ # INTERPOLATE => 1
+
+
+ $myorg.name
+
+ # explicit scoping with { }
+
+
+Note that a limitation in Perl's regex engine restricts the maximum length
+of an interpolated template to around 32 kilobytes or possibly less. Files
+that exceed this limit in size will typically cause Perl to dump core with
+a segmentation fault. If you routinely process templates of this size
+then you should disable INTERPOLATE or split the templates in several
+smaller files or blocks which can then be joined backed together via
+PROCESS or INCLUDE.
+
+
+
+
+
+
+
+=item ANYCASE
+
+By default, directive keywords should be expressed in UPPER CASE. The
+ANYCASE option can be set to allow directive keywords to be specified
+in any case.
+
+ # ANYCASE => 0 (default)
+ [% INCLUDE foobar %] # OK
+ [% include foobar %] # ERROR
+ [% include = 10 %] # OK, 'include' is a variable
+
+ # ANYCASE => 1
+ [% INCLUDE foobar %] # OK
+ [% include foobar %] # OK
+ [% include = 10 %] # ERROR, 'include' is reserved word
+
+One side-effect of enabling ANYCASE is that you cannot use a variable
+of the same name as a reserved word, regardless of case. The reserved
+words are currently:
+
+ GET CALL SET DEFAULT INSERT INCLUDE PROCESS WRAPPER
+ IF UNLESS ELSE ELSIF FOR FOREACH WHILE SWITCH CASE
+ USE PLUGIN FILTER MACRO PERL RAWPERL BLOCK META
+ TRY THROW CATCH FINAL NEXT LAST BREAK RETURN STOP
+ CLEAR TO STEP AND OR NOT MOD DIV END
+
+
+The only lower case reserved words that cannot be used for variables,
+regardless of the ANYCASE option, are the operators:
+
+ and or not mod div
+
+
+
+
+
+
+
+
+=item V1DOLLAR
+
+In version 1 of the Template Toolkit, an optional leading '$' could be placed
+on any template variable and would be silently ignored.
+
+ # VERSION 1
+ [% $foo %] === [% foo %]
+ [% $hash.$key %] === [% hash.key %]
+
+To interpolate a variable value the '${' ... '}' construct was used.
+Typically, one would do this to index into a hash array when the key
+value was stored in a variable.
+
+example:
+
+ my $vars = {
+ users => {
+ aba => { name => 'Alan Aardvark', ... },
+ abw => { name => 'Andy Wardley', ... },
+ ...
+ },
+ uid => 'aba',
+ ...
+ };
+
+ $template->process('user/home.html', $vars)
+ || die $template->error(), "\n";
+
+'user/home.html':
+
+ [% user = users.${uid} %] # users.aba
+ Name: [% user.name %] # Alan Aardvark
+
+This was inconsistent with double quoted strings and also the
+INTERPOLATE mode, where a leading '$' in text was enough to indicate a
+variable for interpolation, and the additional curly braces were used
+to delimit variable names where necessary. Note that this use is
+consistent with UNIX and Perl conventions, among others.
+
+ # double quoted string interpolation
+ [% name = "$title ${user.name}" %]
+
+ # INTERPOLATE = 1
+
+
+
+For version 2, these inconsistencies have been removed and the syntax
+clarified. A leading '$' on a variable is now used exclusively to
+indicate that the variable name should be interpolated
+(e.g. subsituted for its value) before being used. The earlier example
+from version 1:
+
+ # VERSION 1
+ [% user = users.${uid} %]
+ Name: [% user.name %]
+
+can now be simplified in version 2 as:
+
+ # VERSION 2
+ [% user = users.$uid %]
+ Name: [% user.name %]
+
+The leading dollar is no longer ignored and has the same effect of
+interpolation as '${' ... '}' in version 1. The curly braces may
+still be used to explicitly scope the interpolated variable name
+where necessary.
+
+e.g.
+
+ [% user = users.${me.id} %]
+ Name: [% user.name %]
+
+The rule applies for all variables, both within directives and in
+plain text if processed with the INTERPOLATE option. This means that
+you should no longer (if you ever did) add a leading '$' to a variable
+inside a directive, unless you explicitly want it to be interpolated.
+
+One obvious side-effect is that any version 1 templates with variables
+using a leading '$' will no longer be processed as expected. Given
+the following variable definitions,
+
+ [% foo = 'bar'
+ bar = 'baz'
+ %]
+
+version 1 would interpret the following as:
+
+ # VERSION 1
+ [% $foo %] => [% GET foo %] => bar
+
+whereas version 2 interprets it as:
+
+ # VERSION 2
+ [% $foo %] => [% GET $foo %] => [% GET bar %] => baz
+
+In version 1, the '$' is ignored and the value for the variable 'foo' is
+retrieved and printed. In version 2, the variable '$foo' is first interpolated
+to give the variable name 'bar' whose value is then retrieved and printed.
+
+The use of the optional '$' has never been strongly recommended, but
+to assist in backwards compatibility with any version 1 templates that
+may rely on this "feature", the V1DOLLAR option can be set to 1
+(default: 0) to revert the behaviour and have leading '$' characters
+ignored.
+
+ my $parser = Template::Parser->new({
+ V1DOLLAR => 1,
+ });
+
+
+
+
+
+
+=item GRAMMAR
+
+The GRAMMAR configuration item can be used to specify an alternate
+grammar for the parser. This allows a modified or entirely new
+template language to be constructed and used by the Template Toolkit.
+
+Source templates are compiled to Perl code by the Template::Parser
+using the Template::Grammar (by default) to define the language
+structure and semantics. Compiled templates are thus inherently
+"compatible" with each other and there is nothing to prevent any
+number of different template languages being compiled and used within
+the same Template Toolkit processing environment (other than the usual
+time and memory constraints).
+
+The Template::Grammar file is constructed from a YACC like grammar
+(using Parse::YAPP) and a skeleton module template. These files are
+provided, along with a small script to rebuild the grammar, in the
+'parser' sub-directory of the distribution. You don't have to know or
+worry about these unless you want to hack on the template language or
+define your own variant. There is a README file in the same directory
+which provides some small guidance but it is assumed that you know
+what you're doing if you venture herein. If you grok LALR parsers,
+then you should find it comfortably familiar.
+
+By default, an instance of the default Template::Grammar will be
+created and used automatically if a GRAMMAR item isn't specified.
+
+ use MyOrg::Template::Grammar;
+
+ my $parser = Template::Parser->new({
+ GRAMMAR = MyOrg::Template::Grammar->new();
+ });
+
+
+
+=item DEBUG
+
+The DEBUG option can be used to enable various debugging features
+of the Template::Parser module.
+
+ use Template::Constants qw( :debug );
+
+ my $template = Template->new({
+ DEBUG => DEBUG_PARSER | DEBUG_DIRS,
+ });
+
+The DEBUG value can include any of the following. Multiple values
+should be combined using the logical OR operator, '|'.
+
+=over 4
+
+=item DEBUG_PARSER
+
+This flag causes the L to generate
+debugging messages that show the Perl code generated by parsing and
+compiling each template.
+
+=item DEBUG_DIRS
+
+This option causes the Template Toolkit to generate comments
+indicating the source file, line and original text of each directive
+in the template. These comments are embedded in the template output
+using the format defined in the DEBUG_FORMAT configuration item, or a
+simple default format if unspecified.
+
+For example, the following template fragment:
+
+
+ Hello World
+
+would generate this output:
+
+ ## input text line 1 : ##
+ Hello
+ ## input text line 2 : World ##
+ World
+
+
+=back
+
+
+
+
+=back
+
+=head2 parse($text)
+
+The parse() method parses the text passed in the first parameter and
+returns a reference to a Template::Document object which contains the
+compiled representation of the template text. On error, undef is
+returned.
+
+Example:
+
+ $doc = $parser->parse($text)
+ || die $parser->error();
+
+=head1 AUTHOR
+
+Andy Wardley Eabw@andywardley.comE
+
+L
+
+
+
+
+
+
+=head1 VERSION
+
+2.81, distributed as part of the
+Template Toolkit version 2.13, released on 30 January 2004.
+
+
+
+=head1 COPYRIGHT
+
+ Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
+ Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+
+The original Template::Parser module was derived from a standalone
+parser generated by version 0.16 of the Parse::Yapp module. The
+following copyright notice appears in the Parse::Yapp documentation.
+
+ The Parse::Yapp module and its related modules and shell
+ scripts are copyright (c) 1998 Francois Desarmenien,
+ France. All rights reserved.
+
+ You may use and distribute them under the terms of either
+ the GNU General Public License or the Artistic License, as
+ specified in the Perl README file.
+
+=head1 SEE ALSO
+
+L, L, L
+
diff --git a/lib/Template/Plugin.pm b/lib/Template/Plugin.pm
new file mode 100644
index 0000000..a6c9df2
--- /dev/null
+++ b/lib/Template/Plugin.pm
@@ -0,0 +1,409 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Plugin
+#
+# DESCRIPTION
+#
+# Module defining a base class for a plugin object which can be loaded
+# and instantiated via the USE directive.
+#
+# AUTHOR
+# Andy Wardley
+#
+# COPYRIGHT
+# Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved.
+# Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+#----------------------------------------------------------------------------
+#
+# $Id: Plugin.pm,v 2.65 2004/01/13 16:19:15 abw Exp $
+#
+#============================================================================
+
+package Template::Plugin;
+
+require 5.004;
+
+use strict;
+use Template::Base;
+
+use vars qw( $VERSION $DEBUG $ERROR $AUTOLOAD );
+use base qw( Template::Base );
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.65 $ =~ /(\d+)\.(\d+)/);
+$DEBUG = 0;
+
+
+#========================================================================
+# ----- CLASS METHODS -----
+#========================================================================
+
+#------------------------------------------------------------------------
+# load()
+#
+# Class method called when the plugin module is first loaded. It
+# returns the name of a class (by default, its own class) or a prototype
+# object which will be used to instantiate new objects. The new()
+# method is then called against the class name (class method) or
+# prototype object (object method) to create a new instances of the
+# object.
+#------------------------------------------------------------------------
+
+sub load {
+ return $_[0];
+}
+
+
+#------------------------------------------------------------------------
+# new($context, $delegate, @params)
+#
+# Object constructor which is called by the Template::Context to
+# instantiate a new Plugin object. This base class constructor is
+# used as a general mechanism to load and delegate to other Perl
+# modules. The context is passed as the first parameter, followed by
+# a reference to a delegate object or the name of the module which
+# should be loaded and instantiated. Any additional parameters passed
+# to the USE directive are forwarded to the new() constructor.
+#
+# A plugin object is returned which has an AUTOLOAD method to delegate
+# requests to the underlying object.
+#------------------------------------------------------------------------
+
+sub new {
+ my $class = shift;
+ bless {
+ }, $class;
+}
+
+sub old_new {
+ my ($class, $context, $delclass, @params) = @_;
+ my ($delegate, $delmod);
+
+ return $class->error("no context passed to $class constructor\n")
+ unless defined $context;
+
+ if (ref $delclass) {
+ # $delclass contains a reference to a delegate object
+ $delegate = $delclass;
+ }
+ else {
+ # delclass is the name of a module to load and instantiate
+ ($delmod = $delclass) =~ s|::|/|g;
+
+ eval {
+ require "$delmod.pm";
+ $delegate = $delclass->new(@params)
+ || die "failed to instantiate $delclass object\n";
+ };
+ return $class->error($@) if $@;
+ }
+
+ bless {
+ _CONTEXT => $context,
+ _DELEGATE => $delegate,
+ _PARAMS => \@params,
+ }, $class;
+}
+
+
+#------------------------------------------------------------------------
+# fail($error)
+#
+# Version 1 error reporting function, now replaced by error() inherited
+# from Template::Base. Raises a "deprecated function" warning and then
+# calls error().
+#------------------------------------------------------------------------
+
+sub fail {
+ my $class = shift;
+ my ($pkg, $file, $line) = caller();
+ warn "Template::Plugin::fail() is deprecated at $file line $line. Please use error()\n";
+ $class->error(@_);
+}
+
+
+#========================================================================
+# ----- OBJECT METHODS -----
+#========================================================================
+
+#------------------------------------------------------------------------
+# AUTOLOAD
+#
+# General catch-all method which delegates all calls to the _DELEGATE
+# object.
+#------------------------------------------------------------------------
+
+sub OLD_AUTOLOAD {
+ my $self = shift;
+ my $method = $AUTOLOAD;
+
+ $method =~ s/.*:://;
+ return if $method eq 'DESTROY';
+
+ if (ref $self eq 'HASH') {
+ my $delegate = $self->{ _DELEGATE } || return;
+ return $delegate->$method(@_);
+ }
+ my ($pkg, $file, $line) = caller();
+# warn "no such '$method' method called on $self at $file line $line\n";
+ return undef;
+}
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+# This documentation is generated automatically from source
+# templates. Any changes you make here may be lost.
+#
+# The 'docsrc' documentation source bundle is available for download
+# from http://www.template-toolkit.org/docs.html and contains all
+# the source templates, XML files, scripts, etc., from which the
+# documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Plugin - Base class for Template Toolkit plugins
+
+=head1 SYNOPSIS
+
+ package MyOrg::Template::Plugin::MyPlugin;
+ use base qw( Template::Plugin );
+ use Template::Plugin;
+ use MyModule;
+
+ sub new {
+ my $class = shift;
+ my $context = shift;
+ bless {
+ ...
+ }, $class;
+ }
+
+=head1 DESCRIPTION
+
+A "plugin" for the Template Toolkit is simply a Perl module which
+exists in a known package location (e.g. Template::Plugin::*) and
+conforms to a regular standard, allowing it to be loaded and used
+automatically.
+
+The Template::Plugin module defines a base class from which other
+plugin modules can be derived. A plugin does not have to be derived
+from Template::Plugin but should at least conform to its object-oriented
+interface.
+
+It is recommended that you create plugins in your own package namespace
+to avoid conflict with toolkit plugins. e.g.
+
+ package MyOrg::Template::Plugin::FooBar;
+
+Use the PLUGIN_BASE option to specify the namespace that you use. e.g.
+
+ use Template;
+ my $template = Template->new({
+ PLUGIN_BASE => 'MyOrg::Template::Plugin',
+ });
+
+=head1 PLUGIN API
+
+The following methods form the basic interface between the Template
+Toolkit and plugin modules.
+
+=over 4
+
+=item load($context)
+
+This method is called by the Template Toolkit when the plugin module
+is first loaded. It is called as a package method and thus implicitly
+receives the package name as the first parameter. A reference to the
+Template::Context object loading the plugin is also passed. The
+default behaviour for the load() method is to simply return the class
+name. The calling context then uses this class name to call the new()
+package method.
+
+ package MyPlugin;
+
+ sub load { # called as MyPlugin->load($context)
+ my ($class, $context) = @_;
+ return $class; # returns 'MyPlugin'
+ }
+
+=item new($context, @params)
+
+This method is called to instantiate a new plugin object for the USE
+directive. It is called as a package method against the class name
+returned by load(). A reference to the Template::Context object creating
+the plugin is passed, along with any additional parameters specified in
+the USE directive.
+
+ sub new { # called as MyPlugin->new($context)
+ my ($class, $context, @params) = @_;
+ bless {
+ _CONTEXT => $context,
+ }, $class; # returns blessed MyPlugin object
+ }
+
+=item error($error)
+
+This method, inherited from the Template::Base module, is used for
+reporting and returning errors. It can be called as a package method
+to set/return the $ERROR package variable, or as an object method to
+set/return the object _ERROR member. When called with an argument, it
+sets the relevant variable and returns undef. When called without an
+argument, it returns the value of the variable.
+
+ sub new {
+ my ($class, $context, $dsn) = @_;
+
+ return $class->error('No data source specified')
+ unless $dsn;
+
+ bless {
+ _DSN => $dsn,
+ }, $class;
+ }
+
+ ...
+
+ my $something = MyModule->new()
+ || die MyModule->error(), "\n";
+
+ $something->do_something()
+ || die $something->error(), "\n";
+
+=back
+
+=head1 DEEPER MAGIC
+
+The Template::Context object that handles the loading and use of
+plugins calls the new() and error() methods against the package name
+returned by the load() method. In pseudo-code terms, it might look
+something like this:
+
+ $class = MyPlugin->load($context); # returns 'MyPlugin'
+
+ $object = $class->new($context, @params) # MyPlugin->new(...)
+ || die $class->error(); # MyPlugin->error()
+
+The load() method may alterately return a blessed reference to an
+object instance. In this case, new() and error() are then called as
+I