#========================================================================
#
# Changes
#
# DESCRIPTION
# Revision history for Template Toolkit.
#
# AUTHOR
# Andy Wardley <abw@cre.canon.co.uk>
#
#------------------------------------------------------------------------
# $Id: Changes,v 1.111 2000/03/28 15:53:21 abw Exp $
#========================================================================
#------------------------------------------------------------------------
# Version 1.06 2000/03/28 15:52:48
#------------------------------------------------------------------------
* Interim release to fix a bug in Datafile plugin which became noticable
with Perl 5.6. Thanks to Nathan Torkington for spotting it.
#------------------------------------------------------------------------
# Version 1.05 2000/03/20 16:31:05
#------------------------------------------------------------------------
* Added the CALL directive, identical to GET in every way except
that it doesn't print the value returned by evaluating the variable.
This allows you to call sub-routines or methods and effectively
ignore the return value. Errors and exceptions returned are still
raised automatically.
* Added the 'html_para', 'html_break', 'truncate' and 'repeat' filters
kindly provided by Leslie Michael Orchard, or minor adaptations
thereof. Also added 'replace' and 'remove' filters as suggested by
Neil Bowers. Updated documentation and test suite accordingly.
* Added the 'URL' plugin for constructing a URL from a base part and
variable set of parameters. Based on a suggestion by Andrew Brindeew
<abr@df.ru>. Added t/url.t and updated docs.
* Added the 'Table' plugin which allows you to slice up a data set
into rows and columns. Specify either a fixed number of 'rows' or
'cols' with an optional 'overlap' and then call the col() or row()
method to request a specific row or cols() or rows() to return all
cols/rows as list references. See t/table.t for examples and
documentation in Template::Plugin::Table.
* Added get_all() method to Template::Iterator to return all remaining
data. This allows it to be passed to the Table plugin (and others)
which can then easily extract all remaining data from it. Here's a
short example showing how you might integrate the results of a DBI
query (iterator) into a table:
[% USE DBI(dsn,user,pass) -%]
[% USE table( DBI.query('SELECT * FROM alphabet ORDER BY letter'),
rows=8 overlap=1 pad=0) -%]
[% FOREACH row = table.cols -%]
[% row.first.letter %] - [% row.last.letter +%]:
[% FOREACH item = row %][% item.name %] [% END %]
[% END %]
Producing output something like this:
a - h:
alpha bravo charlie delta echo foxtrot golf hotel
h - o:
hotel india juliet kilo lima mike november oscar
o - v:
oscar papa quebec romeo sierra tango umbrella victor
v - z:
victor whisky x-ray yankee zulu
* Added the facility to specify iterator options directly in FOREACH
directives. These are simply added after the list name or list
construction. e.g.
[% FOREACH name = list order = 'sorted' %]
[% FOREACH name = [ 'tom' 'dick' 'harry' ] order = 'sorted' %]
It was previously possible to specify parenthesised iterator options
when creating anonymous lists (e.g. "[ ... ](order=>'sorted')" ).
This is still supported for backwards compatibility but is no longer
documented. The new syntax is now preferred. Added new parameter
'field' which names a key within the data items (presumably hashes)
which should be used as the sort key. See examples in t/
[% FOREACH p = people order='sorted' field='surname' %]
* Removed a rogue debug statement printed when calling a code based
CATCH handler.
* Applied a patch sent by Swen Thuemmler to fix a problem in the Template
DESTROY method reporting 'Can't call method "old" on an undefined value...'
when a $SIG{__DIE__} handler is defined.
#------------------------------------------------------------------------
# Version 1.04 2000/03/01 14:22:01
#------------------------------------------------------------------------
* Added the XML::DOM and XML::RSS plugin modules to the distribution.
* Changed the handling of file errors generated when redirecting
output and/or error, as suggested by Jonas Lilligren. Errors are
now raised as 'file' exceptions and are reported back to the caller
as per usual. That is, the process() method returns 0 and the error
can be retrieved by the usual error() method. e.g.
$template->process($infile, \%params, $path_to_output_file)
|| die $template->error(), "\n";
If a global OUTPUT or ERROR redirect is established by means of the
Template constructor parameters then any error will be stored and
also accessible via the error() method. e.g.
my $template = Template->new({ OUTPUT => $path_to_some_file });
# check for any OUTPUT errors
die $error
if $error = $template->error();
* Changed the way in which multiple values returned from user code or
object methods are handled. Previously, multiple values were
treated as being ($value, $error) and the code was required to
return a list reference in $value if it wanted to return more than
one item. This behaviour is still supported if the first value
returned (i.e. $value) is undefined. Thus, existing code can
continue to return (undef, $error) and expect the right result. If
the first item returned has any defined value then all the return
values are folded into, and returned as a list reference.
e.g. return ('foo', 'bar', 'baz') => [ 'foo', 'bar', 'baz ]. Single
values are returned by themselves as per usual. Removed the
work-around delegating AUTOLOAD code from Template::Plugin which is
no longer needed, updated documentation and added t/cgi.t to test
this behaviour with the CGI plugin. Thanks to Leslie Michael
Orchard for raising the issue and sending various patches and ideas.
* Fixed a bug concerning iterators in nested FOREACH loops, identified
by Thiery-Michel Barral <kktos@electron-libre.com>. The iterator
(i.e. the 'loop' variable) in the outer loop was getting trashed by
an inner FOREACH loop. Nested FOREACH loops now work as expected.
* Split the Template::Cache new() constructor into new() and _init()
methods to facilitate easier subclassing, thanks to another patch
from Leslie. Also fixed a minor bug which was preventing switching
of the PARSER object.
* Added '--start--' and '--stop--' markers to Template::Test to allow
sub-sections of tests to be run in isolation. Updated 'BUGS' section
of documentation to show new Template::Test module.
* Added USER_DIR and USER_BLOCK options which allow user-defined
directives and block directives to be defined. This is still
experimental and subject to change. Not yet documented for that
reason, but see t/userdef.t if you're interested.
* Added an acknowledgements section to the Template documentation and
further information on other projects and related modules. Also
added internal/external plugin information.
#------------------------------------------------------------------------
# Version 1.03 2000/02/01 12:35:13
#------------------------------------------------------------------------
* Added support for running under Perl 5.004 (previously required 5.005)
* Added a general purpose 'join' function which can be applied to list
references. A joining string can be passed, or ' ' is used by default.
Added test to t/list.t. e.g.
[% mylist.join %] [% mylist.join(', ') %]
* Improved the plugin interface by enhancing the Template::Plugin base
class to act as a general delegate to other Perl modules. The base
class constructor can be passed an object reference to which it
should delegate all methods. Alternatively, pass the name of a Perl
module as the first parameter and it will attempt to 'require' the
module and create an object instance via it's new() constructor
method. Any additional parameters are passed to new(). A plugin
object is returned which wraps the target object, providing
delegation to its methods via an AUTOLOAD function. This function
checks the values returned by the delegate method and concatenates
them if more than one is returned. Methods may have a '_as_list'
suffix added to them which will cause the autoloader to return them
as a list reference. Documented Template::Plugin, updated docs to
note changes and included some better examples for plugins in
general.
* Changed Context use_plugin() method to look for LOAD_PERL option and
use the above Template::Plugin behaviour if set. Changed CGI plugin
to also use the new delegating base class.
* Modified handling of object references in Template::Context::_evaluate.
When a template variable is bound to a blessed object reference, any
attempt to reference a member of that object (e.g. myobj.whatever)
translates to a method call (e.g. myobj->whatever). If that fails
and the object is a blessed hash reference then the method will now
attempt to resolve it as a hash member (e.g. myobj->{ whatever }).
Added test to t/object.t
* Changed Template::Plugin::Format to pass all parameters to sprintf
rather than just the first. Added test to t/format.t
* Added a tutorial document as Template::Tutorial. Many other minor
documentation updates.
* Improved the comments in the sample .ttreerc file generated
automatically by ttree when first run. Added 'eval_perl' and 'load_perl'
template options.
#------------------------------------------------------------------------
# Version 1.02 1999/12/21 14:22:04
#------------------------------------------------------------------------
* Added code to enable [% PERL %] ... [% END %] sections. This is
controlled by the EVAL_PERL option and is disabled by default. When
enabled, the Perl code contained in the block is evaluated in the
Template::Perl package and any runtime errors are thrown as 'perl'
exceptions. A 'perl' exception is thrown automatically if the EVAL_PERL
option is disabled and a PERL block is encountered. The 'context' and
'stash' variables are pre-defined in the package. e.g.
[% PERL %]
$stash->{'some_data'} = [ qw( foo bar baz ) ];
$context->output('loaded data');
[% END %]
[% "$item\n" FOREACH item = some_data %]
The PERL section is a fully-fledged block allowing it to contain other
template directives. These are processed first and the resulting output
of the entire PERL block is then evaluated as Perl code.
* Changed main Template module to watch for and report errors during
any pre-process and post-process templates. For some reason I thought
it was a Good Thing to be tolerant of errors during these phases but
I now know that it's not (i.e. when your plugins fail to load from a
pre-process file and you don't get any warning).
* Modified tokeniser regex to accept a leading '-' on literal numbers.
This is the quick fix to allow things like the following. I'll add
a proper unary minus to the parser RSN.
[% FOREACH timezone = [-12..12] %]
* Added some proper documentation to the Template::Test module. Fixed
a minor bug in the test splitter to ignore the first '-- test --' line
if provided.
#------------------------------------------------------------------------
# Version 1.01 1999/12/16 09:31:19
#------------------------------------------------------------------------
* Added the pseudo-reference operator '\' as an experimental feature
to allow things like code references to be passed around without
being pre-evaluated. The 'reference' created is actually a closure
which can be called from Perl code to evaluate the referred value
(i.e. lazy evaluation). Additional parameters may also be passed
when calling the closure. These are added to any parameters
supplied when the reference was created. A reference will be
automatically evaluated (i.e. called) each time it is used in a
template. Not yet documented - see tests in t/code.t for further
info. e.g.
[% sql_query(sql, \my_filter('foo')) %]
sub sql_query {
my ($sql, $filter) = @_;
my $data = _do_sql_query($sql);
&$filter($data); # => my_filter('foo', $data);
}
* Modified parser to accept parameter list after an evaluated term. e.g.
${foo}(bar). Thanks to Paul Sharpe for spotting the omission.
#------------------------------------------------------------------------
# Version 1.00 1999/12/02 16:14:10
#------------------------------------------------------------------------
* Removed debugging code and bumped version number for release.
#------------------------------------------------------------------------
# Version 0.29 1999/11/26 09:11:57
#------------------------------------------------------------------------
* This is the final release candidate. Barring any show-stoppers, this
will be released as version 1.00.
* Added MACRO directive. A MACRO defines some other directive which
can be repeatedly executed each time the macro is evaluated. Macros
can be passed parameters when called which may be named or mapped to
a variable name declared with the macro.
[% MACRO foo INCLUDE bar %]
[% foo %] [% foo(title='Hello World') %]
[% MACRO header(title) INCLUDE html/header %]
[% header('Hello World') %]
[% header('Hello World', bgcol='#123456') %]
* Modified grammar to allow an anonymous BLOCK to be declared. This can
be used in conjunction with MACRO to create a template block for later
evaluation without requiring you to explicitly define a block and
INCLUDE it. e.g.
[% MACRO letter BLOCK %]
Dear [% name %]...
[% END %]
[% letter(name='Fred') %]
* Rationalised the grammar slightly to allow general use of the shortcut
operator (e.g. result = this or that, file = open or die, etc). Also
added the basic binary math operators, -, +, *, div, and mod. Added tests
to t/binop.t.
* Changed the Template::Context::throw() method to be a little more
intelligent about determining which exception handler to raise. An
exception type can now be expressed in dotted form (e.g. foo.bar) and
a more general handler can be installed (e.g. foo) as a catch-all for
any sub-typed exceptions that don't define their own handlers. Failing
all that, the 'default' handler is still used. As SAM noted, (it was
his idea), this makes it much easier to handle general classes of errors
for plugin modules (like DBI) without losing the granularity of what
different errors might represent.
* Fixed problem with PLUGIN_BASE when used via ttree. The default
plugin base, 'Template::Plugin', now gets added automatically to
whatever value is supplied in the configuration. This is done in
the Template::Context constructor. Note that this changes beta
behaviour which didn't add 'Template::Plugin' if an array reference
(rather than a scalar) was passed. This is now more consistent.
* Fixed a bug in FOREACH identified by Simon Matthews where the incorrect
loop variable was being freed (loop vs iter).
* Fixed a problem in loading files with ABSOLUTE_PATHS. Thanks again to
Simon Matthews for finding and fixing.
* Moved t/texpect.pl into Template::Test module to make it easier to
load and use the test harness. Modified test scripts accordingly.
* Relaxed the behaviour of redirect (in Template::Utils, called via
Template::Context) to accept any kind of object reference that
supports a 'print' method. This includes all IO::Handle objects
(as before) and also allows Apache::Request objects to be passed.
* Added better error reporting to the plugin loading process implemented
in Template::Context::use_plugin().
* Updated documentation.
#------------------------------------------------------------------------
# Version 0.28 1999/11/05 10:29:05
#------------------------------------------------------------------------
* OK, so I lied about 0.27 being the final beta release. :-)=
The main reason is that the internal FILTER interface has been
improved at the cost of (possibly) breaking existing filter code.
This isn't as bad as it sounds because the filter code probably
wasn't working properly anyway, due to the interface not being up to
scratch. Anyway, it's a change worthy of another beta release,
IMHO, to allow the changes to be tested and any wrinkles ironed out.
Interfaces should remain stable from now on so you can consider this
version a release candidate.
* Changed the behaviour of the AND (&&) and OR (||) operators to act as
"short-circuit" operators as in Perl. If the left hand side of an OR
evaluates true, then the right hand side will not be evaluated. Likewise
for an AND which will bypass evaluation of the RHS if the LHS evaluates
false. I thought this was going to be tricky to implement but Simon
Matthews sat me down in the pub with a few pints of beer and a laptop
and it all came together quite well. Inspirational hacking, indeed!
Updated t/binop.t to test this behaviour.
* Added ABSOLUTE_PATHS option which allows template files to be specified
using absolute paths (e.g. '/foo/bar/baz.html'). Enabled by default.
Thanks to all those who badgered me about this until I got a clue. :-)=
Added t/abspath.t and updated documentation. Changed the parser grammar
to accept '/' as the first character of an unquoted INCLUDE file, e.g.
[% INCLUDE /slash/bang/wallop %]
* Added 'perl5lib' option to ttree to allow additional Perl library
directories to be specified. These are simply unshifted onto @INC.
* Changed Template::Context::_evaluate() test on ARRAY objects so that
the generic size, max, etc., and numerical indexing operations work
on blessed arrays.
* Added register_filter($name, $factory) method to context to allow
plugin modules (or whatever) to register filters for subsequent use.
Moved the filters defined in Template::Plugin::Filter into a new
module, Template::Filters, which defines all the "system" filters.
This is loaded the first time a FILTER directive is encountered and
registers all filters for subsequent use.
* Changed behaviour of Context use_filter() method so that it no longer
passes the name of the filter to the factory method.
* Added new filters 'redirect' and 'into'. The first redirects a block
into a separate file, as specified by a filename. The file will be
written relative to the OUTPUT_PATH. This can be used to generate
mucho pages from a list of records (see following example).
List of User:
<ul>
[% FOREACH user = myorg.userlist %]
[% INCLUDE user_page FILTER redirect("users/${user.id}.html") %]
<li><a href="users/${user.id}.html">[% user.name %]</a>
[%
</ul>
The 'into' filter saves the output into a named variable.
[% INCLUDE myfile FILTER into('myvar') %]
[% FILTER into('description') %]
Rhubarb, rhubard, blah, blah, cabbages.
[% END %]
* Added a minor feature to add a 'filename' variable which stores the name
of the top-level template file. This doesn't happen if a 'filename'
variables is already defined or if the template was specified via a
reference (i.e. no filename available).
* Added new Template Plugin module 'Datafile'.
* Francois Desarmenien has released a new version of Parse::Yapp (0.32)
which includes the patch to specify an alternate grammar template file
(yapp -t <template>). Removed parser/parse_yapp_patch and updated
parser/README.
#------------------------------------------------------------------------
# Version 0.27 1999/10/01 16:51:46
#------------------------------------------------------------------------
* Fifth and most certainly, final, beta release. The core toolkit is now
stable and there are only a few low-level interface issues left to
resolve (e.g. filters). The 'ttree' utility is now fully functional
and reliable.
* Added numerical list indexing of the form 'list.n', e.g 'list.0', 'list.3'.
Added t/listndx.t to test suite. Examples of use:
[% list = ['one' 'two' 'three' 'four' ] %]
[% list.0 %] [% list.1 %]
[% list.${n} FOREACH n = [0..3] %]
* Fixed a bug identified by Simon Matthews which was causing corruption
of the context runtime stack when an empty hash was created. Added a
special case to detect empty hashes rather than blindly splicing n
(possibly 0) elements off the stack to construct a hash. Added tests
to t/hash.t.
* Fixed several bugs in ttree identified by Martin Portman; files of the
same name in different directories were treated as the same file and all
received the same (cached) contents, target directories weren't always
being created, and a few other minor oddities were cleansed. Also added
-n option to do nothing.
* Modified grammar slightly to allow multiple FILTER directives to be
chained one after another, as suggested by Eugene Miretskiy e.g.
[% INCLUDE foobar FILTER this FILTER that %]
#------------------------------------------------------------------------
# Version 0.26 1999/09/15 12:22:36
#------------------------------------------------------------------------
* Fourth (and hopefully final) public beta release.
* Finished writing bin/ttree. It is now fully functional and (mostly)
documented. Added AppConfig (which ttree uses) as a Makefile.PL
pre-requisite
* Added '..' range operator for specification of simple loops:
e.g. [% FOREACH i = [ 1..10 ] %]
* Changed parser grammar to call a factory function to generate directives.
This can be specified as a package name or by reference to a prototype or
factory object.
e.g.
my $t = Template->new({ FACTORY => 'MyOrg::Template::Directive' });
or
my $t = Template->new({ FACTORY => MyOrg::TDFactory->new() });
* Re-structured the intermediate code generated by the parser and wrote
a new runtime evaluation loop in Context::_evaluate(). Re-wrote parts
of the parser grammer accordingly. This offers some new features, like
named parameters described below; is simpler to understand, maintain and
use; has smaller state and rule tables resulting in faster loading and
smaller footprint, generates less intermediate code resulting in faster
parsing and using slightly less memory. The runtime FSM now uses a
double-ended queue. Shifting/unshift opcodes and data to and from a list
is understandably slower than simply iterating through the list elements
as we previously did, but the added simplicitly seems to outweigh any
losses. Rough benchmarks show it runs about 10% faster now.
* Added facility for named parameters. These are automatically collated
into a hash array which is then passed by reference as the last item
in the parameter list. e.g. foo(10, 20, name='fred', 30, age=30) is
converted to foo(10, 20, 30, { name => 'fred', age => 30 }). This applies
to parameters passed to functions/methods like this example, USE and
FILTER parameters.
* Changed FOREACH to only localise the stash when it is expected to import
hash members, i.e. no iterator variable is specified. Thanks to Graham
Barr for spotting the irregularity.
* Iterator methods first() and next() have been renamed get_first()
and get_next(), respectively, and methods size(), max(), index(),
number(), first() and last() have been provided. The FOREACH loop
defines a 'loop' variable which contains a reference to the iterator,
allowing you to do things like the following. Updated t/foriter.t.
[% FOREACH thing = myapp.somelist %]
[% INCLUDE thing_table_header IF loop.first %]
#[% loop.number ]/[% loop.size %]: [% thing %]
[% INCLUDE thing_table_footer IF loop.last %]
[% END %]
* Added generic list methods size(), max() and sort() which can be appended
to any list (or indeed, iterator) to return the number of elements,
maximum index (size - 1), or a sorted representation of the list.
[% FOREACH name = myapp.list_of_names.sort %]
[% name %]
[% END %]
* Added generic keys() and values() methods for hash references.
* Added RECURSION option to allow recursion into template files.
Added t/recurse.t to test it.
* Changed handling of output files to automatically create any
intermediate directories required for the destination. This is
implemented in Template::Utils::output_handler() by calling on
File::Path's mkpath() function.
* Fixed bug where a PLUGIN_BASE specified as a string didn't get the
default Template::Plugin base added. Thanks to Hans von Lengerke for
the patch.
* Fixed a problem identified by Simon Matthews whereby files in local
directories would not be processed if a file of the same name existed
in an INCLUDE_PATH directory. This isn't always what you want. Added
support for a './' prefix on a file (e.g. './header' instead of 'header')
which causes the loader to look only in the current directory and not
in the INCLUDE_PATH. Caching is as per default CACHE option, with
leading './' left intact in the name.
#------------------------------------------------------------------------
# Version 0.25 1999/08/16 14:44:45
#------------------------------------------------------------------------
* Third public beta release.
* Added 'ttree' utility for process directory trees of template files,
akin to the 'metapage' script in Text::MetaText. Not yet documented
and missing a few features but very much working and useful.
* Added PRE_PROCESS and POST_PROCESS options to denote template files
for processing before and after templates. Changed organisation of
Context module a little, adding explicit localise() and delocalise()
methods. Added t/preproc.t.
* Change Template::process() method to accept optional third and fourth
parameters, $output and $error, to denote output and/or error destinations
for processing that template only. The process() method calls the
context redirect() for output and/or error, processes the template file
and then restores them to their previous values, effectively closing
any files that may have been opened. The destination may now also be
a filename relative to OUTPUT_PATH which is constructed and passed
to output_handler() (see next item). Added t/output.t.
* Modified Template::Utils:output_handler() to accept a string as a
destination, treat it as a filename, open the file and return a glob,
created by Symbol::gensym containing the file handle.
* Various minor documentation updates.
* Added t/accessor.t and made minor changes to t/texpectl.pl.
#------------------------------------------------------------------------
# Version 0.24 1999/08/12 22:04:26
#------------------------------------------------------------------------
* Second public beta release.
* Improved FILTERS configuration option which now allows filter
constructors (factories) to be defined. These take responsibility
for creating filter instances as they are required.
* Documented WHILE, PROCESS, IMPORT, TAGS, BREAK and FILTER
directives. Re-wrote the overview and summary sections, moved some
bits around, generally improved various other parts of the docs.
The Template.pod and README file are now constructed automatically
by the 'make dist' from source in doc/src, using bin/mkdoc.
* Removed operating-system dependant code which was detecting and
storing path separators. I realised that if everyone uses '/' as
the path separator, then Perl will do the conversion automagically.
Much easier. This also means that the OS, PATH_SEP and PATH_SPLIT
options are no longer required.
* Deleted old and boring 'examples' directory.
* Deleted obsolete code from Template::Debug.pm
#------------------------------------------------------------------------
# Version 0.23 1999/08/10 12:12:07
#------------------------------------------------------------------------
* Interim (non-public) release. This will become the next public
beta release once the documentation has been updated to reflect
the following changes. For now, the best source of inspiration for
usage of new features can be found in the relevant test scripts.
* Added PROCESS directive which acts like INCLUDE but doesn't localise
variables. This allows configuration files, etc., to update non-local
variables. Added t/process.t to test suite.
* Added IMPORT directive to copy all members of a hash into the main
namespace. Added t/import.t to test suite.
* Added WHILE directive to repeat a loop while an expression evaluates
true. The $Template::Directive::While::MAXITER variable defines an
upper iteration limit and kills the loop with an error if it is exceeded.
By default this value is set to 1000. Added t/while.t to test suite.
* Added BREAK directive to prematurely exit FOREACH or WHILE loop. Added
t/break.t to test suite and updated t/while.t and t/foreach.t.
* Added TAGS directive to allow per-file switching of the tokens that mark
the start and end of directives. Added t/tags.t to test suite
* Added FILTER directive to allow post-processing of output. Filters
are defined in the Template::Plugin::Filter module. The Context
use_filter() method simply calls use_plugin(), requesting the 'filter'
plugin module, providing he filter name and any additional parameters
specified. Thus "FILTER foo(bar)" is roughly equivalent to
"USE filter('foo', bar)". Added t/filter.t to test suite.
* Changed Context to allow multiple PLUGIN_BASE packages to be defined.
* Added Template::OS module to autodetect operating system and return
specific values such as path separator. The Context creates an OS
object and stores it internally.
* Added OS option to Template.pm to specify operating system to override
the autodetect.
* Changed old DIR_SEPARATOR option to PATH_SEP and old PATH_SEPARATOR to
PATH_SPLIT. These are defaulted based on OS if not specified.
* Removed some old code which allowed an absolute filename to be specified
and opened by the cache. This isn't a bad thing, per se, but needs
to be optional and disabled by default.
* Added an AUTOLOAD method to Template.pm to delegate to Context object.
Template redirect() removed, given that it is now accessible via
AUTOLOAD.
* Added inc() and dec() root functions to the Context object which get
evaluated to simple increment/decrement subs when called as root
variables and not otherwise defined. This may be extended in the
future to provide default object/package whose methods/subs should be
called when root variables are requested but not defined.
#------------------------------------------------------------------------
# Version 0.22 1999/08/04 20:37:43
#------------------------------------------------------------------------
* First public beta release.
* Updated all of the documentation. The general toolkit document,
Template-Toolkit.pod has been deleted and its content moved into
Template.pm.
* Added facility to escape '$' in a document (and then have it correctly
unescaped) to avoid unintentionally referencing a variable when
INTERPOLATE is on. Added test to t/interp.t
* Changed default tag style to be '[% blah_blah %]' whilst also supporting
the old '%% blah_blah %%' style. The TAG_STYLE parameter may be
specified as 'regular' ([% ...%]), 'percent' (%% ... %%) or 'default'
(both of the above - [\[%]% ... %[\]%]). The START_TAG and END_TAG
may still be specified and will override any values set by the TAG_STYLE.
* Added ERROR directive to allow reporting of errors via the $context->error()
method, which by default writes to STDERR. Changed 'error' variable as
passed to a CATCH block to 'e' to avoid a name clash with 'ERROR'. Added
t/error.t to test suite.
* Added CASE option, which by default is set to 0 to indicate non-case
sensitivity of *KEYWORDS* (variables are always case sensitive).
When set off, a keyword such as 'INCLUDE' can be specified in any
case. When set on, all keywords must be expressed in exact, upper
case. Lower or mixed case versions of the same words (e.g. 'include',
'for', 'Filter') are treated as variables. The only exceptions are
'and', 'or' and 'not' which can *always* be expressed in any case.
Added t/case.t to test.
* Added interpolation of "\n" into double-quoted text strings.
* Added THROW directive and t/throw.t to test it. Usage is:
%% THROW type info %%, mapping 'type' to a %% CATCH type %%.
* Improved handling of exceptions, blocking only multiple occurances
of the same exception type. Nested exception throwing now works OK.
* Added a catch($type, $handler) method to Template::Context for installing
exception handlers. Changed Template::Directive::Catch->process() to
call this method.
* Fixed memory leak caused by circular dependency rooted at Context.
Template.pm DESTROY method calls context->old() to perform clearup.
* Removed ERROR_PARSE ('parse' exception) and made it a case of ERROR_FILE
('file').
* Removed redundant EXPAND_* constants from Template::Constants.
#------------------------------------------------------------------------
# Version 0.21 1999/07/28 16:12:58
#------------------------------------------------------------------------
* Fifth (and final?) alpha release.
* Improved Template::Iterator to allow data items to be ordered by an
external function or by one of the default ordering styles: 'sorted'
or 'reverse'. The Iterator will also accept an action parameter
which is called on each iteration. These can be set by passing an
additional hash reference to the iterator constructor containing ORDER
and/or ACTION keys. e.g.
my $iterator = Template::Iterator->new(['foo', 'bar', 'baz'],
{ ORDER => 'sorted', ACTION => \&format_data });
These can also be added as named parameters in parenthesis after a
list constructor, e.g.
%% FOREACH user = [ tom dick harry ] ( order => 'sorted') %%
...
%% END %%
%% iterator = [ foo bar baz ] ( order => 'reverse' ) %%
%% INCLUDE winner FOREACH person = iterator %%
* Added the Template::Plugin::Format module which implements a very
simple plugin for creating sprintf-like formatting functions. e.g.
%% USE format; bold = format('<b>%s</b>'); bold('foo'); bold('bar') %%
%% FOREACH [ foo bar baz]( order='sorted' action=format('-- %s --') ) %%
etc., etc. See t/format.t for examples.
* Added thrown() method and internal flag to Template::Exception to
indicate if it has been handled by the $context->thrown() method.
Changed Template::Directive::Block to throw any unthrown exceptions
it recevies to the $context->throw() method. The upshot is that
user code can now simply C<return (undef, Template::Exception->new(...))>
and the calling block loop will throw the exception. Previously, the
user code was required to directly call $context->throw() to raise an
exception. User code is no longer passed a reference to the context
(although plugin objects have an internal reference they can use) so
this would not have been possible otherwise. Fixed a couple of other
minor bugs in the exception throwing/handling in the process.
* Finalised the return protocol for user code and object methods and
implemented. Code/methods may return a value and optionally, an
additional status. The status code may be a Template::Exception
(see previous item). An undefined value returned will raise an
'undef' exception unless the error is already defined. If the
error is STATUS_OK (0) then the calue will be silently converted
to an empty string ''.
* Added tests t/code.t and t/object.t to test variable bindings to
user code and objects respectively. Added t/private.t to test that
members prefixed with '_' or '.' remain unexposed.
* Added OP_TOLERANT as a temporary fix to set a flag to prevent the
context runop() method from automatically raising an undef exception
when it resolves a variable to an undefined value. This is to allow
directives such as IF to tolerate undefined values without raising
exceptions. Added tests to t/if.t to test this.
* Fixed another instance of the OP_NOT bug (previously fixed in 0.18)
which manifested itself when UNLESS was used as a side-effect, e.g.
%% RETURN UNLESS something_to_do %%. Added tests to t/unless.t to
detect.
* Fixed minor bug in the parser which wasn't allowing a trailing comma
in an argument or named parameter list. Updated t/hash.t and added
t/list.t to test this and other related issues.
* Added public context() method to Template.pm to return internal
context reference.
#------------------------------------------------------------------------
# Version 0.20 1999/07/27 12:59:08
#------------------------------------------------------------------------
* Fourth public alpha release.
* Fixed bug in Context throw() method which was causing re-entrancy
problems in CATCH handlers. Also changed to pass a variable named
'error' into the CATCH block containing the members 'type' and 'info'.
e.g. %% CATCH undef %% <!-- $error.info --> %% END %%. Added tests
to t/catch.t.
* Added '+' chomp option to compliment '-' option. The '+' disables chomping
for that directive, the '-' forces it. Improved the PRE_CHOMP to work
better when POST_CHOMP is also enabled and to pre-chomp correctly on the
first line of the file. And hopefully, all this without screwing up line
numbering.
* Fixed grammar to allow literals as lvalues.
* Changed BLOCK definition grammar to allow names that contain dots and
slashes as per INCLUDE. These are treated as literal.
* Fixed bug in FOREACH which was causing an undefined variable reference
to go un-noticed.
* Changed FOREACH to clone (localise) a stash context so that it
doesn't trample on previously defined variables. In addition, it
will also automagically import the members of HASH references that
are returned by each iteration when a target loop variable isn't
specified.
This now allows you to write things like:
%% FOREACH userlist %%
$name ($id)
%% END %%
Instead of:
%% FOREACH user = userlist %%
$user.name ($user.id)
%% END %%
* added tests to t/foreach.t to verify the above behaviour.
* added test scripts binop.t, chomp.t, prechomp.t, postchomp.t
and skel.t. Extended/improved tests in if.t, predefs.t.
* Fixed bug in tokeniser that was failing to recognise '!='.
#------------------------------------------------------------------------
# Version 0.19 1999/07/26 19:53:39
#------------------------------------------------------------------------
* Third public alpha release.
* Added Template::Plugin and engaged the USE directive to load plugin
modules, instantiate plugin objects and bind them to variables in
the stash. Modified the grammar a little to build the appropriate
reduction for the parenthesised parameters that may be passed from
the USE directive. Wrote simple stubs for Template::Plugin::CGI and
Template::Plugin::DBI.
* Fixed bug in UNLESS which was using the old '!' character instead of
OP_NOT. Added t/unless.t to test UNLESS directive and IF directive
with logical negation operator ('!', aka OP_NOT)
* Changed INCLUDE parameter to allow '/' as well as '.' within the name.
This is in addition to the regular \w characters permitted. Names
containing any other characters must be quoted. Updated t/include.t
to add test for this.
* Fixed bug that was causing the 'and' and 'or' boolean operations to
not be recognised unless specified in UPPER CASE.
* Added t/direcive.t to test general directive options (e.g. chomping,
whitespace and case insensitivity, etc.
* Fixed IMPORT option and added t/import.t test.
* Fixed EXPORT and added t/export.t test.
#------------------------------------------------------------------------
# Version 0.18 1999/07/23 11:50
#------------------------------------------------------------------------
* Second public alpha release
* Re-wrote the parser grammar and associated runtime support for the
very last time. The grammar needs some polishing and there are a
couple of ugly/elegant hacks (depending on your perspective)
to manage special cases for INCLUDE, in particular. These
could be improved, but they work for now.
* The language now fully supports multiple namespace variables of
which any sub-element might be represented by a variable, hash array
or entry, list, code reference or object. The runtime opcode loop
evaluates these with respect to one another where joined by '.'
* Parameters can be specified to any individual element. e.g. foo(a).bar(b)
* An individual element may be an evaluated variable e.g. user.${uname}
* The INTERPOLATE option now includes period as part of identifier names.
Braces need only be used to delimit a variable against another period.
e.g. $user.name ${user.id}.gif
* An assignment may now be enclosed in parentheses and used as a term, e.g.
%% IF (users = mydb.get_userlist) %%
* Changed the calling convention for variables bound to code and
object (methods). A reference is no longer passed as the first
parameter. This makes it easier to interface to existing code
and marginally quicker to write new code. The Template::Stash
module can be sub-classed to create plug-in library modules which
can have far greater intimacy with the Template Toolkit.
* Fixed broken parameter passing into code bound to variables. Added
t/call.t to test correct behaviour. Then the whole calling convention
got changed again, but its legacy remains...
* Re-wrote and/or cleaned up the entire test suite. Some are still
incomplete or missing.
* Updated Template-Toolkit.pod to remove some of the documentation that
was clearly obsoleted by these changes. Added and corrected most of the
obvious stuff, but there's still some lacking and it may include features
missing, changed or broken.
* Numerous minor bugs, typos, etc.
#------------------------------------------------------------------------
# Version 0.17 1999/06/24 23:55
#------------------------------------------------------------------------
* First public alpha release