diff options
| author | Andreas Brachold <vdr07@deltab.de> | 2007-08-13 18:41:27 +0000 |
|---|---|---|
| committer | Andreas Brachold <vdr07@deltab.de> | 2007-08-13 18:41:27 +0000 |
| commit | bcbf441e09fb502cf64924ff2530fa144bdf52c5 (patch) | |
| tree | f377707a2dac078db8cd0c7d7abfe69ac1006d71 /lib/Template/Plugin | |
| download | xxv-bcbf441e09fb502cf64924ff2530fa144bdf52c5.tar.gz xxv-bcbf441e09fb502cf64924ff2530fa144bdf52c5.tar.bz2 | |
* Move files to trunk
Diffstat (limited to 'lib/Template/Plugin')
41 files changed, 10663 insertions, 0 deletions
diff --git a/lib/Template/Plugin/Autoformat.pm b/lib/Template/Plugin/Autoformat.pm new file mode 100644 index 0000000..b7153e4 --- /dev/null +++ b/lib/Template/Plugin/Autoformat.pm @@ -0,0 +1,242 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Autoformat +# +# DESCRIPTION +# Plugin interface to Damian Conway's Text::Autoformat module. +# +# AUTHORS +# Robert McArthur <mcarthur@dstc.edu.au> +# - original plugin code +# +# Andy Wardley <abw@kfs.org> +# - added FILTER registration, support for forms and some additional +# documentation +# +# COPYRIGHT +# Copyright (C) 2000 Robert McArthur & Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Autoformat.pm,v 2.64 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Autoformat; + +require 5.004; + +use strict; +use vars qw( $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; +use Text::Autoformat; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + +sub new { + my ($class, $context, $options) = @_; + my $filter_factory; + my $plugin; + + if ($options) { + # create a closure to generate filters with additional options + $filter_factory = sub { + my $context = shift; + my $filtopt = ref $_[-1] eq 'HASH' ? pop : { }; + @$filtopt{ keys %$options } = values %$options; + return sub { + tt_autoformat(@_, $filtopt); + }; + }; + + # and a closure to represent the plugin + $plugin = sub { + my $plugopt = ref $_[-1] eq 'HASH' ? pop : { }; + @$plugopt{ keys %$options } = values %$options; + tt_autoformat(@_, $plugopt); + }; + } + else { + # simple filter factory closure (no legacy options from constructor) + $filter_factory = sub { + my $context = shift; + my $filtopt = ref $_[-1] eq 'HASH' ? pop : { }; + return sub { + tt_autoformat(@_, $filtopt); + }; + }; + + # plugin without options can be static + $plugin = \&tt_autoformat; + } + + # now define the filter and return the plugin + $context->define_filter('autoformat', [ $filter_factory => 1 ]); + return $plugin; +} + +sub tt_autoformat { + my $options = ref $_[-1] eq 'HASH' ? pop : { }; + my $form = $options->{ form }; + my $out = $form ? Text::Autoformat::form($options, $form, @_) + : Text::Autoformat::autoformat(join('', @_), $options); + return $out; +} + +__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::Autoformat - Interface to Text::Autoformat module + +=head1 SYNOPSIS + + [% USE autoformat(options) %] + + [% autoformat(text, more_text, ..., options) %] + + [% FILTER autoformat(options) %] + a block of text + [% END %] + +=head1 EXAMPLES + + # define some text for the examples + [% text = BLOCK %] + Be not afeard. The isle is full of noises, sounds and sweet + airs that give delight but hurt not. + [% END %] + + # pass options to constructor... + [% USE autoformat(case => 'upper') %] + [% autoformat(text) %] + + # and/or pass options to the autoformat subroutine itself + [% USE autoformat %] + [% autoformat(text, case => 'upper') %] + + # using the autoformat filter + [% USE autoformat(left => 10, right => 30) %] + [% FILTER autoformat %] + Be not afeard. The isle is full of noises, sounds and sweet + airs that give delight but hurt not. + [% END %] + + # another filter example with configuration options + [% USE autoformat %] + [% FILTER autoformat(left => 20) %] + Be not afeard. The isle is full of noises, sounds and sweet + airs that give delight but hurt not. + [% END %] + + # another FILTER example, defining a 'poetry' filter alias + [% USE autoformat %] + [% text FILTER poetry = autoformat(left => 20, right => 40) %] + + # reuse the 'poetry' filter alias + [% text FILTER poetry %] + + # shorthand form ('|' is an alias for 'FILTER') + [% text | autoformat %] + + # using forms + [% USE autoformat(form => '>>>>.<<<', numeric => 'AllPlaces') %] + [% autoformat(10, 20.32, 11.35) %] + +=head1 DESCRIPTION + +The autoformat plugin is an interface to Damian Conway's Text::Autoformat +Perl module which provides advanced text wrapping and formatting. + +Configuration options may be passed to the plugin constructor via the +USE directive. + + [% USE autoformat(right => 30) %] + +The autoformat subroutine can then be called, passing in text items which +will be wrapped and formatted according to the current configuration. + + [% autoformat('The cat sat on the mat') %] + +Additional configuration items can be passed to the autoformat subroutine +and will be merged with any existing configuration specified via the +constructor. + + [% autoformat(text, left => 20) %] + +Configuration options are passed directly to the Text::Autoformat plugin. +At the time of writing, the basic configuration items are: + + left left margin (default: 1) + right right margin (default 72) + justify justification as one of 'left', 'right', 'full' + or 'centre' (default: left) + case case conversion as one of 'lower', 'upper', + 'sentence', 'title', or 'highlight' (default: none) + squeeze squeeze whitespace (default: enabled) + +The plugin also accepts a 'form' item which can be used to define a +format string. When a form is defined, the plugin will call the +underlying form() subroutine in preference to autoformat(). + + [% USE autoformat(form => '>>>>.<<') %] + [% autoformat(123.45, 666, 3.14) %] + +Additional configuration items relevant to forms can also be specified. + + [% USE autoformat(form => '>>>>.<<', numeric => 'AllPlaces') %] + [% autoformat(123.45, 666, 3.14) %] + +These can also be passed directly to the autoformat subroutine. + + [% USE autoformat %] + [% autoformat( 123.45, 666, 3.14, + form => '>>>>.<<', + numeric => 'AllPlaces' ) + %] + +See L<Text::Autoformat> for further details. + +=head1 AUTHORS + +Robert McArthur E<lt>mcarthur@dstc.edu.auE<gt> wrote the original plugin +code, with some modifications and additions from Andy Wardley +E<lt>abw@wardley.orgE<gt>. + +Damian Conway E<lt>damian@conway.orgE<gt> wrote the Text::Autoformat +module (in his copious spare time :-) which does all the clever stuff. + +=head1 VERSION + +2.64, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + + + +=head1 COPYRIGHT + +Copyright (C) 2000 Robert McArthur & Andy Wardley. All Rights Reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Text::Autoformat|Text::Autoformat> + diff --git a/lib/Template/Plugin/CGI.pm b/lib/Template/Plugin/CGI.pm new file mode 100644 index 0000000..53b19d8 --- /dev/null +++ b/lib/Template/Plugin/CGI.pm @@ -0,0 +1,168 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::CGI +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the CGI.pm module. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# 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: CGI.pm,v 2.64 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::CGI; + +require 5.004; + +use strict; +use vars qw( $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; +use CGI; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + +sub new { + my $class = shift; + my $context = shift; + CGI->new(@_); +} + +package CGI; + +sub params { + my $self = shift; + local $" = ', '; + + return $self->{ _TT_PARAMS } ||= do { + # must call Vars() in a list context to receive + # plain list of key/vals rather than a tied hash + my $params = { $self->Vars() }; + + # convert any null separated values into lists + @$params{ keys %$params } = map { + /\0/ ? [ split /\0/ ] : $_ + } values %$params; + + $params; + }; +} + +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::CGI - Interface to the CGI module + +=head1 SYNOPSIS + + [% USE CGI %] + [% CGI.param('parameter') %] + + [% USE things = CGI %] + [% things.param('name') %] + + # see CGI docs for other methods provided by the CGI object + +=head1 DESCRIPTION + +This is a very simple Template Toolkit Plugin interface to the CGI module. +A CGI object will be instantiated via the following directive: + + [% USE CGI %] + +CGI methods may then be called as follows: + + [% CGI.header %] + [% CGI.param('parameter') %] + +An alias can be used to provide an alternate name by which the object should +be identified. + + [% USE mycgi = CGI %] + [% mycgi.start_form %] + [% mycgi.popup_menu({ Name => 'Color' + Values => [ 'Green' 'Black' 'Brown' ] }) %] + +Parenthesised parameters to the USE directive will be passed to the plugin +constructor: + + [% USE cgiprm = CGI('uid=abw&name=Andy+Wardley') %] + [% cgiprm.param('uid') %] + +=head1 METHODS + +In addition to all the methods supported by the CGI module, this +plugin defines the following. + +=head2 params() + +This method returns a reference to a hash of all the CGI parameters. +Any parameters that have multiple values will be returned as lists. + + [% USE CGI('user=abw&item=foo&item=bar') %] + + [% CGI.params.user %] # abw + [% CGI.params.item.join(', ') %] # foo, bar + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.64, 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<Template::Plugin|Template::Plugin>, L<CGI|CGI> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/DBI.pm b/lib/Template/Plugin/DBI.pm new file mode 100644 index 0000000..b916bfc --- /dev/null +++ b/lib/Template/Plugin/DBI.pm @@ -0,0 +1,947 @@ +#============================================================================== +# +# Template::Plugin::DBI +# +# DESCRIPTION +# A Template Toolkit plugin to provide access to a DBI data source. +# +# AUTHORS +# Original version by Simon Matthews <sam@knowledgepool.com> +# with some reworking by Andy Wardley <abw@kfs.org> and other +# contributions from Craig Barratt <craig@arraycomm.com>, +# Dave Hodgkinson <daveh@davehodgkinson.com> and Rafael Kitover +# <caelum@debian.org> +# +# COPYRIGHT +# Copyright (C) 1999-2000 Simon Matthews. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: DBI.pm,v 2.62 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================== + +package Template::Plugin::DBI; + +require 5.004; + +use strict; +use Template::Plugin; +use Template::Exception; +use DBI; + +use vars qw( $VERSION $DEBUG $QUERY $ITERATOR ); +use base qw( Template::Plugin ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.62 $ =~ /(\d+)\.(\d+)/); +$DEBUG = 0 unless defined $DEBUG; +$QUERY = 'Template::Plugin::DBI::Query'; +$ITERATOR = 'Template::Plugin::DBI::Iterator'; + +# alias _connect() to connect() for backwards compatability +*_connect = \*connect; + + +#------------------------------------------------------------------------ +# new($context, @params) +# +# Constructor which returns a reference to a new DBI plugin object. +# A connection string (dsn), user name and password may be passed as +# positional arguments or a hash array of connection parameters can be +# passed to initialise a connection. Otherwise, an unconnected DBI +# plugin object is returned. +#------------------------------------------------------------------------ + +sub new { + my $class = shift; + my $context = shift; + my $self = ref $class ? $class : bless { + _CONTEXT => $context, + _STH => [ ], + }, $class; + + $self->connect(@_) if @_; + + return $self; +} + + +#------------------------------------------------------------------------ +# connect( $data_source, $username, $password, $attributes ) +# connect( { data_source => 'dbi:driver:database' +# username => 'foo' +# password => 'bar' } ) +# +# Opens a DBI connection for the plugin. +#------------------------------------------------------------------------ + +sub connect { + my $self = shift; + my $params = ref $_[-1] eq 'HASH' ? pop(@_) : { }; + my ($dbh, $dsn, $user, $pass, $klobs); + + # set debug flag + $DEBUG = $params->{ debug } if exists $params->{ debug }; + $self->{ _DEBUG } = $params->{ debug } || 0; + + # fetch 'dbh' named paramater or use positional arguments or named + # parameters to specify 'dsn', 'user' and 'pass' + + if ($dbh = $params->{ dbh }) { + # disconnect any existing database handle that we previously opened + $self->{ _DBH }->disconnect() + if $self->{ _DBH } && $self->{ _DBH_CONNECT }; + + # store new dbh but leave _DBH_CONNECT false to prevent us + # from automatically closing it in the future + $self->{ _DBH } = $dbh; + $self->{ _DBH_CONNECT } = 0; + } + else { + + # certain Perl programmers are known to have problems with short + # term memory loss (see Tie::Hash::Cannabinol) so we let the poor + # blighters fumble any kind of argument that looks like it might + # identify the database + + $dsn = shift + || $params->{ data_source } + || $params->{ database } + || $params->{ connect } + || $params->{ dsn } + || $params->{ db } + || $ENV{DBI_DSN} + || return $self->_throw('data source not defined'); + + # add 'dbi:' prefix if it's not there + $dsn = "dbi:$dsn" unless $dsn =~ /^dbi:/i; + + $user = shift + || $params->{ username } + || $params->{ user }; + + $pass = shift + || $params->{ password } + || $params->{ pass }; + + # save connection data because we might need it later to do a tie() + @$self{ qw( _DSN _USER _PASS ) } = ($dsn, $user, $pass); + + # reuse existing database handle if connection params match + my $connect = join(':', $dsn || '', $user || '', $pass || ''); + return '' + if $self->{ _DBH } && $self->{ _DBH_CONNECT } eq $connect; + + # otherwise disconnect any existing database handle that we opened + $self->{ _DBH }->disconnect() + if $self->{ _DBH } && $self->{ _DBH_CONNECT }; + + # don't need DBI to automatically print errors because all calls go + # via this plugin interface and we always check return values + $params->{ PrintError } = 0 + unless defined $params->{ PrintError }; + + $self->{ _DBH } = DBI->connect_cached( $dsn, $user, $pass, $params ) + || return $self->_throw("DBI connect failed: $DBI::errstr"); + + # store the connection parameters + $self->{ _DBH_CONNECT } = $connect; + } + + return ''; +} + + +#------------------------------------------------------------------------ +# disconnect() +# +# Disconnects the current active database connection. +#------------------------------------------------------------------------ + +sub disconnect { + my $self = shift; + $self->{ _DBH }->disconnect() + if $self->{ _DBH }; + delete $self->{ _DBH }; + return ''; +} + + +#------------------------------------------------------------------------ +# tie( $table, $key ) +# +# Return a hash tied to a table in the database, indexed by the specified +# key. +#------------------------------------------------------------------------ + +sub tie { + my $self = shift; + my $params = ref $_[-1] eq 'HASH' ? pop(@_) : { }; + my ($table, $key, $klobs, $debug, %hash); + + eval { require Tie::DBI }; + $self->_throw("failed to load Tie::DBI module: $@") if $@; + + $table = shift + || $params->{ table } + || $self->_throw('table not defined'); + + $key = shift + || $params->{ key } + || $self->_throw('key not defined'); + + # Achtung der Klobberman! + $klobs = $params->{ clobber }; + $klobs = $params->{ CLOBBER } unless defined $klobs; + + # going the extra mile to allow user to use UPPER or lower case or + # inherit internel debug flag set by connect() + $debug = $params->{ debug }; + $debug = $params->{ DEBUG } unless defined $debug; + $debug = $self->{ _DEBUG } unless defined $debug; + + tie %hash, 'Tie::DBI', { + %$params, # any other Tie::DBI options like DEBUG, WARN, etc + db => $self->{ _DBH } || $self->{ _DSN }, + user => $self->{ _USER }, + password => $self->{ _PASS }, + table => $table, + key => $key, + CLOBBER => $klobs || 0, + DEBUG => $debug || 0, + }; + + return \%hash; +} + + +#------------------------------------------------------------------------ +# prepare($sql) +# +# Prepare a query and store the live statement handle internally for +# subsequent execute() calls. +#------------------------------------------------------------------------ + +sub prepare { + my $self = shift; + my $sql = shift || return undef; + + my $sth = $self->dbh->prepare($sql) + || return $self->_throw("DBI prepare failed: $DBI::errstr"); + + # create wrapper object around handle to return to template client + $sth = $QUERY->new($sth); + push(@{ $self->{ _STH } }, $sth); + + return $sth; +} + + +#------------------------------------------------------------------------ +# execute() +# +# Calls execute() on the most recent statement created via prepare(). +#------------------------------------------------------------------------ + +sub execute { + my $self = shift; + + my $sth = $self->{ _STH }->[-1] + || return $self->_throw('no query prepared'); + + $sth->execute(@_); +} + + +#------------------------------------------------------------------------ +# query($sql, @params) +# +# Prepares and executes a SQL query. +#------------------------------------------------------------------------ + +sub query { + my $self = shift; + my $sql = shift; + + $self->prepare($sql)->execute(@_); +} + + +#------------------------------------------------------------------------ +# do($sql, \%attr, @bind) +# +# Prepares and executes a SQL statement. +#------------------------------------------------------------------------ + +sub do { + my $self = shift; + + return $self->dbh->do(@_) + || $self->_throw("DBI do failed: $DBI::errstr"); +} + + +#------------------------------------------------------------------------ +# quote($value [, $data_type ]) +# +# Returns a quoted string (correct for the connected database) from the +# value passed in. +#------------------------------------------------------------------------ + +sub quote { + my $self = shift; + $self->dbh->quote(@_); +} + + +#------------------------------------------------------------------------ +# dbh() +# +# Internal method to retrieve the database handle belonging to the +# instance or attempt to create a new one using connect. +#------------------------------------------------------------------------ + +sub dbh { + my $self = shift; + + return $self->{ _DBH } || do { + $self->connect; + $self->{ _DBH }; + }; +} + + +#------------------------------------------------------------------------ +# DESTROY +# +# Called automatically when the plugin object goes out of scope to +# disconnect the database handle cleanly +#------------------------------------------------------------------------ + +sub DESTROY { + my $self = shift; + delete($self->{ _STH }); # first DESTROY any queries + $self->{ _DBH }->disconnect() + if $self->{ _DBH } && $self->{ _DBH_CONNECT }; +} + + +#------------------------------------------------------------------------ +# _throw($error) +# +# Raise an error by throwing it via die() as a Template::Exception +# object of type 'DBI'. +#------------------------------------------------------------------------ + +sub _throw { + my $self = shift; + my $error = shift || die "DBI throw() called without an error string\n"; + + # throw error as DBI exception + die (Template::Exception->new('DBI', $error)); +} + + +#======================================================================== +# Template::Plugin::DBI::Query +#======================================================================== + +package Template::Plugin::DBI::Query; +use vars qw( $DEBUG $ITERATOR ); + +*DEBUG = \$Template::Plugin::DBI::DEBUG; +*ITERATOR = \$Template::Plugin::DBI::ITERATOR; + + +sub new { + my ($class, $sth) = @_; + bless \$sth, $class; +} + +sub execute { + my $self = shift; + + $$self->execute(@_) + || return Template::Plugin::DBI->_throw("execute failed: $DBI::errstr"); + + $ITERATOR->new($$self); +} + +sub DESTROY { + my $self = shift; + $$self->finish(); +} + + +#======================================================================== +# Template::Plugin::DBI::Iterator; +#======================================================================== + +package Template::Plugin::DBI::Iterator; + +use Template::Iterator; +use base qw( Template::Iterator ); +use vars qw( $DEBUG ); + +*DEBUG = \$Template::Plugin::DBI::DEBUG; + + +sub new { + my ($class, $sth, $params) = @_; + + my $rows = $sth->rows(); + + my $self = bless { + _STH => $sth, + SIZE => $rows, + MAX => $rows - 1, + }, $class; + + + return $self; +} + + +#------------------------------------------------------------------------ +# get_first() +# +# Initialises iterator to read from statement handle. We maintain a +# one-record lookahead buffer to allow us to detect if the current +# record is the last in the series. +#------------------------------------------------------------------------ + +sub get_first { + my $self = shift; + $self->{ _STARTED } = 1; + + # set some status variables into $self + @$self{ qw( PREV ITEM FIRST LAST COUNT INDEX ) } + = ( undef, undef, 2, 0, 0, -1 ); + + # support 'number' as an alias for 'count' for backwards compatability + $self->{ NUMBER } = 0; + + print STDERR "get_first() called\n" if $DEBUG; + + # get the first row + $self->_fetchrow(); + + print STDERR "get_first() calling get_next()\n" if $DEBUG; + + return $self->get_next(); +} + + +#------------------------------------------------------------------------ +# get_next() +# +# Called to read remaining result records from statement handle. +#------------------------------------------------------------------------ + +sub get_next { + my $self = shift; + my ($data, $fixup); + + # increment the 'index' and 'count' counts + $self->{ INDEX }++; + $self->{ COUNT }++; + $self->{ NUMBER }++; # 'number' is old name for 'count' + + # decrement the 'first-record' flag + $self->{ FIRST }-- if $self->{ FIRST }; + + # we should have a row already cache in NEXT + return (undef, Template::Constants::STATUS_DONE) + unless $data = $self->{ NEXT }; + + # set PREV to be current ITEM from last iteration + $self->{ PREV } = $self->{ ITEM }; + + # look ahead to the next row so that the rowcache is refilled + $self->_fetchrow(); + + $self->{ ITEM } = $data; + return ($data, Template::Constants::STATUS_OK); +} + + +sub get { + my $self = shift; + my ($data, $error); + + ($data, $error) = $self->{ _STARTED } + ? $self->get_next() : $self->get_first(); + + return $data; +} + + +sub get_all { + my $self = shift; + my $sth = $self->{ _STH }; + my $error; + + my $data = $sth->fetchall_arrayref({}); + $self->throw($error) if ($error = $sth->err()); + unshift(@$data, $self->{ NEXT }) if $self->{ NEXT }; + $self->{ LAST } = 1; + $self->{ NEXT } = undef; + $sth->finish(); + + return $data; +} + + +#------------------------------------------------------------------------ +# _fetchrow() +# +# Retrieve a record from the statement handle and store in row cache. +#------------------------------------------------------------------------ + +sub _fetchrow { + my $self = shift; + my $sth = $self->{ _STH }; + + my $data = $sth->fetchrow_hashref() || do { + $self->{ LAST } = 1; + $self->{ NEXT } = undef; + $sth->finish(); + return; + }; + $self->{ NEXT } = $data; + return; +} + +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::DBI - Template interface to the DBI module + +=head1 SYNOPSIS + +Making an implicit database connection: + + # ...using positional arguments + [% USE DBI('dbi:driver:dbname', 'user', 'pass') %] + + # ...using named parameters + [% USE DBI( database = 'dbi:driver:dbname', + username = 'user', + password = 'pass' ) + %] + + # ...using short named parameters (4 lzy ppl and bad typsits) + [% USE DBI( db = 'driver:dbname', + user = 'user', + pass = 'pass' ) + %] + + # ...or an existing DBI database handle + [% USE DBI( dbh = my_dbh_ref ) %] + +Making explicit database connections: + + [% USE DBI %] + + [% DBI.connect(db, user, pass) %] + ... + + [% DBI.connect(new_db, new_user, new_pass) %] + ... + + [% DBI.disconnect %] # final disconnect is optional + +Making an automagical database connection using DBI_DSN environment variable: + + [% USE DBI %] + +Making database queries: + + # single step query + [% FOREACH user = DBI.query('SELECT * FROM users') %] + [% user.uid %] blah blah [% user.name %] etc. etc. + [% END %] + + # two stage prepare/execute + [% query = DBI.prepare('SELECT * FROM users WHERE uid = ?') %] + + [% FOREACH user = query.execute('sam') %] + ... + [% END %] + + [% FOREACH user = query.execute('abw') %] + ... + [% END %] + +Making non-SELECT statements: + + [% IF DBI.do("DELETE FROM users WHERE uid = '$uid'") %] + The user '[% uid %]' was successfully deleted. + [% END %] + +Using named DBI connections: + + [% USE one = DBI(...) %] + [% USE two = DBI(...) %] + + [% FOREACH item = one.query("SELECT ...etc...") %] + ... + [% END %] + + [% FOREACH item = two.query("SELECT ...etc...") %] + ... + [% END %] + +Tieing to a database table (via Tie::DBI): + + [% people = DBI.tie('users', 'uid') %] + + [% me = people.abw %] # => SELECT * FROM users WHERE uid='abw' + + I am [% me.name %] + + # clobber option allows table updates (see Tie::DBI) + [% people = DBI.tie('users', 'uid', clobber=1) %] + + [% people.abw.name = 'not a number' %] + + I am [% people.abw.name %] # I am a free man! + +=head1 DESCRIPTION + +This Template Toolkit plugin module provides an interface to the Perl +DBI/DBD modules, allowing you to integrate SQL queries into your +template documents. It also provides an interface via the Tie::DBI +module (if installed on your system) so that you can access database +records without having to embed any SQL in your templates. + +A DBI plugin object can be created as follows: + + [% USE DBI %] + +This creates an uninitialised DBI object. You can then open a connection +to a database using the connect() method. + + [% DBI.connect('dbi:driver:dbname', 'user', 'pass') %] + +The DBI connection can be opened when the plugin is created by passing +arguments to the constructor, called from the USE directive. + + [% USE DBI('dbi:driver:dbname', 'user', 'pass') %] + +You can also use named parameters to provide the data source connection +string, user name and password. + + [% USE DBI(database => 'dbi:driver:dbname', + username => 'user', + password => 'pass') %] + +For backwards compatability with previous versions of this plugin, you can +also spell 'database' as 'data_source'. + + [% USE DBI(data_source => 'dbi:driver:dbname', + username => 'user', + password => 'pass') %] + +Lazy Template hackers may prefer to use 'db', 'dsn' or 'connect' as a +shorthand form of the 'database' parameter, and 'user' and 'pass' as +shorthand forms of 'username' and 'password', respectively. You can +also drop the 'dbi:' prefix from the database connect string because +the plugin will add it on for you automagically. + + [% USE DBI(db => 'driver:dbname', + user => 'user', + pass => 'pass') %] + +Any additional DBI attributes can be specified as named parameters. +The 'PrintError' attribute defaults to 0 unless explicitly set true. + + [% USE DBI(db, user, pass, ChopBlanks=1) %] + +An alternate variable name can be provided for the plugin as per regular +Template Toolkit syntax: + + [% USE mydb = DBI('dbi:driver:dbname', 'user', 'pass') %] + + [% FOREACH item = mydb.query('SELECT * FROM users') %] + ... + [% END %] + +You can also specify the DBI plugin name in lower case if you prefer: + + [% USE dbi(dsn, user, pass) %] + + [% FOREACH item = dbi.query('SELECT * FROM users') %] + ... + [% END %] + +The disconnect() method can be called to explicitly disconnect the +current database, but this generally shouldn't be necessary as it is +called automatically when the plugin goes out of scope. You can call +connect() at any time to open a connection to another database. The +previous connection will be closed automatically. + +Internally, the DBI connect_cached() method is used instead of the +connect() method. This allows for connection caching in a server +environment, such as when the Template Toolkit is used from an Apache +mod_perl handler. In such a case, simply enable the mod_env module +and put in a line such as: + + SetEnv DBI_DSN "dbi:mysql:dbname;host=dbhost; + user=uname;password=pword" + +(NOTE: the string shown here is split across 2 lines for the sake of +reasonable page formatting, but you should specify it all as one long +string with no spaces or newlines). + +You can then use the DBI plugin without any parameters or the need +to explicitly call connect(). + +Once you've loaded a DBI plugin and opened a database connection using +one of the techniques shown above, you can then make queries on the database +using the familiar dotted notation: + + [% FOREACH user = DBI.query('SELECT * FROM users') %] + [% user.uid %] blah blah [% user.name %] etc. etc. + [% END %] + +The query() method prepares a query and executes it all in one go. +If you want to repeat a query with different parameters then you +can use a separate prepare/execute cycle. + + [% query = DBI.prepare('SELECT * FROM users WHERE uid = ?') %] + + [% FOREACH user = query.execute('sam') %] + ... + [% END %] + + [% FOREACH user = query.execute('abw') %] + ... + [% END %] + +The query() and execute() methods return an iterator object which +manages the result set returned. You can save a reference to the +iterator and access methods like size() to determine the number of +rows returned by a query. + + [% users = DBI.query('SELECT * FROM users') %] + [% users.size %] records returned + +or even + + [% DBI.query('SELECT * FROM users').size %] + +When used within a FOREACH loop, the iterator is always aliased to the +special C<loop> variable. This makes it possible to do things like this: + + [% FOREACH user = DBI.query('SELECT * FROM users') %] + [% loop.count %]/[% loop.size %]: [% user.name %] + [% END %] + +to generate a result set of the form: + + 1/3: Jerry Garcia + 2/3: Kurt Cobain + 3/3: Freddie Mercury + +See L<Template::Iterator> for further details on iterators and the +methods that they implement. + +The DBI plugin also provides the do() method to execute non-SELECT +statements like this: + + [% IF DBI.do("DELETE FROM users WHERE uid = '$uid'") %] + The user '[% uid %]' was successfully deleted. + [% END %] + +The plugin also allows you to create a tie to a table in the database +using the Tie::DBI module. Simply call the tie() method, passing the +name of the table and the primary key as arguments. + + [% people = DBI.tie('person', 'uid') %] + +You can then access records in the database table as if they were +entries in the 'people' hash. + + My name is [% people.abw.name %] + +IMPORTANT NOTE: the XS Stash (Template::Stash::XS) does not currently +support access to tied hashes. If you are using the XS stash and having +problems then you should try enabling the regular stash instead. You +can do this by setting $Template::Config::STASH to 'Template::Stash' +before instantiating the Template object. + +=head1 OBJECT METHODS + +=head2 connect($database, $username, $password) + +Establishes a database connection. This method accepts both positional +and named parameter syntax. e.g. + + [% DBI.connect( 'dbi:driver:dbname', 'timmy', 'sk8D00Dz' ) %] + + [% DBI.connect( database = 'dbi:driver:dbname' + username = 'timmy' + password = 'sk8D00Dz' ) %] + +The connect method allows you to connect to a data source explicitly. +It can also be used to reconnect an exisiting object to a different +data source. + +If you already have a database handle then you can instruct the plugin +to reuse it by passing it as the 'dbh' parameter. + + [% DBI.connect( dbh = my_dbh_ref ) %] + +=head2 query($sql) + +This method submits an SQL query to the database and creates an iterator +object to return the results. This may be used directly in a FOREACH +directive as shown below. Data is automatically fetched a row at a time +from the query result set as required for memory efficiency. + + [% FOREACH user = DBI.query('SELECT * FROM users') %] + Each [% user.field %] can be printed here + [% END %] + +=head2 prepare($sql) + +Prepare a query for later execution. This returns a compiled query +object (of the Template::Plugin::DBI::Query class) on which the +execute() method can subsequently be called. + + [% query = DBI.prepare('SELECT * FROM users WHERE id = ?') %] + +=head2 execute(@args) + +Execute a previously prepared query. This method should be called on +the query object returned by the prepare() method. Returns an +iterator object which can be used directly in a FOREACH directive. + + [% query = DBI.prepare('SELECT * FROM users WHERE manager = ?') %] + + [% FOREACH minion = query.execute('abw') %] + [% minion.name %] + [% END %] + + [% FOREACH minion = query.execute('sam') %] + [% minion.name %] + [% END %] + +=head2 do($sql) + +The do() method executes a sql statement from which no records are +returned. It will return true if the statement was successful + + [% IF DBI.do("DELETE FROM users WHERE uid = 'sam'") %] + The user was successfully deleted. + [% END %] + +=head2 tie($table, $key, \%args) + +Returns a reference to a hash array tied to a table in the database, +implemented using the Tie::DBI module. You should pass the name of +the table and the key field as arguments. + + [% people = DBI.tie('users', 'uid') %] + +Or if you prefer, you can use the 'table' and 'key' named parameters. + + [% people = DBI.tie(table='users', key='uid') %] + +In this example, the Tie::DBI module will convert the accesses into +the 'people' hash into SQL queries of the form: + + SELECT * FROM users WHERE uid=? + +For example: + + [% me = people.abw %] + +The record returned can then be accessed just like a normal hash. + + I am [% me.name %] + +You can also do things like this to iterate through all the records +in a table. + + [% FOREACH uid = people.keys.sort; + person = people.$uid + %] + * [% person.id %] : [% person.name %] + [% END %] + +With the 'clobber' (or 'CLOBBER') option set you can update the record +and have those changes automatically permeated back into the database. + + [% people = DBI.tie('users', 'uid', clobber=1) %] + + [% people.abw.name = 'not a number' %] + + I am [% people.abw.name %] # I am a free man! + +And you can also add new records. + + [% people.newguy = { + name = 'Nobby Newguy' + ...other fields... + } + %] + +See L<Tie::DBI> for further information on the 'CLOBBER' option. + +=head2 quote($value, $type) + +Calls the quote() method on the underlying DBI handle to quote the value +specified in the appropriate manner for its type. + +=head2 dbh() + +Return the database handle currently in use by the plugin. + +=head2 disconnect() + +Disconnects the current database. + +=head1 AUTHORS + +The DBI plugin was originally written by Simon A Matthews, and +distributed as a separate module. It was integrated into the Template +Toolkit distribution for version 2.00 and includes contributions from +Andy Wardley, Craig Barratt, Dave Hodgkinson and Rafael Kitover. + +=head1 VERSION + +2.62, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + + + +=head1 COPYRIGHT + +Copyright (C) 1999-2001 Simon Matthews. All Rights Reserved + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<DBI|DBI>, L<Tie::DBI|Tie::DBI> + diff --git a/lib/Template/Plugin/Datafile.pm b/lib/Template/Plugin/Datafile.pm new file mode 100644 index 0000000..5cf53af --- /dev/null +++ b/lib/Template/Plugin/Datafile.pm @@ -0,0 +1,198 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Datafile +# +# DESCRIPTION +# +# Template Toolkit Plugin which reads a datafile and constructs a +# list object containing hashes representing records in the file. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# 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: Datafile.pm,v 2.66 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Datafile; + +require 5.004; + +use strict; +use vars qw( @ISA $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.66 $ =~ /(\d+)\.(\d+)/); + +sub new { + my ($class, $context, $filename, $params) = @_; + my ($delim, $line, @fields, @data, @results); + my $self = [ ]; + local *FD; + local $/ = "\n"; + + $params ||= { }; + $delim = $params->{'delim'} || ':'; + $delim = quotemeta($delim); + + return $class->fail("No filename specified") + unless $filename; + + open(FD, $filename) + || return $class->fail("$filename: $!"); + + # first line of file should contain field definitions + while (! $line || $line =~ /^#/) { + $line = <FD>; + chomp $line; + $line =~ s/\r$//; + } + + (@fields = split(/\s*$delim\s*/, $line)) + || return $class->fail("first line of file must contain field names"); + + # read each line of the file + while (<FD>) { + chomp; + s/\r$//; + + # ignore comments and blank lines + next if /^#/ || /^\s*$/; + + # split line into fields + @data = split(/\s*$delim\s*/); + + # create hash record to represent data + my %record; + @record{ @fields } = @data; + + push(@$self, \%record); + } + +# return $self; + bless $self, $class; +} + + +sub as_list { + return $_[0]; +} + + +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::Datafile - Plugin to construct records from a simple data file + +=head1 SYNOPSIS + + [% USE mydata = datafile('/path/to/datafile') %] + [% USE mydata = datafile('/path/to/datafile', delim = '|') %] + + [% FOREACH record = mydata %] + [% record.this %] [% record.that %] + [% END %] + +=head1 DESCRIPTION + +This plugin provides a simple facility to construct a list of hash +references, each of which represents a data record of known structure, +from a data file. + + [% USE datafile(filename) %] + +A absolute filename must be specified (for this initial implementation at +least - in a future version it might also use the INCLUDE_PATH). An +optional 'delim' parameter may also be provided to specify an alternate +delimiter character. + + [% USE userlist = datafile('/path/to/file/users') %] + [% USE things = datafile('items', delim = '|') %] + +The format of the file is intentionally simple. The first line +defines the field names, delimited by colons with optional surrounding +whitespace. Subsequent lines then defines records containing data +items, also delimited by colons. e.g. + + id : name : email : tel + abw : Andy Wardley : abw@cre.canon.co.uk : 555-1234 + neilb : Neil Bowers : neilb@cre.canon.co.uk : 555-9876 + +Each line is read, split into composite fields, and then used to +initialise a hash array containing the field names as relevant keys. +The plugin returns a blessed list reference containing the hash +references in the order as defined in the file. + + [% FOREACH user = userlist %] + [% user.id %]: [% user.name %] + [% END %] + +The first line of the file B<must> contain the field definitions. +After the first line, blank lines will be ignored, along with comment +line which start with a '#'. + +=head1 BUGS + +Should handle file names relative to INCLUDE_PATH. +Doesn't permit use of ':' in a field. Some escaping mechanism is required. + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.66, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Date.pm b/lib/Template/Plugin/Date.pm new file mode 100644 index 0000000..7351686 --- /dev/null +++ b/lib/Template/Plugin/Date.pm @@ -0,0 +1,361 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Date +# +# DESCRIPTION +# +# Plugin to generate formatted date strings. +# +# AUTHORS +# Thierry-Michel Barral <kktos@electron-libre.com> +# Andy Wardley <abw@cre.canon.co.uk> +# +# COPYRIGHT +# Copyright (C) 2000 Thierry-Michel Barral, Andy Wardley. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Date.pm,v 2.71 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Date; + +use strict; +use vars qw( $VERSION $FORMAT @LOCALE_SUFFIX ); +use base qw( Template::Plugin ); +use Template::Plugin; + +use POSIX (); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.71 $ =~ /(\d+)\.(\d+)/); +$FORMAT = '%H:%M:%S %d-%b-%Y'; # default strftime() format +@LOCALE_SUFFIX = qw( .ISO8859-1 .ISO_8859-15 .US-ASCII .UTF-8 ); + +#------------------------------------------------------------------------ +# new(\%options) +#------------------------------------------------------------------------ + +sub new { + my ($class, $context, $params) = @_; + bless { + $params ? %$params : () + }, $class; +} + + +#------------------------------------------------------------------------ +# now() +# +# Call time() to return the current system time in seconds since the epoch. +#------------------------------------------------------------------------ + +sub now { + return time(); +} + + +#------------------------------------------------------------------------ +# format() +# format($time) +# format($time, $format) +# format($time, $format, $locale) +# format($time, $format, $locale, $gmt_flag) +# format(\%named_params); +# +# Returns a formatted time/date string for the specified time, $time, +# (or the current system time if unspecified) using the $format, $locale, +# and $gmt values specified as arguments or internal values set defined +# at construction time). Specifying a Perl-true value for $gmt will +# override the local time zone and force the output to be for GMT. +# Any or all of the arguments may be specified as named parameters which +# get passed as a hash array reference as the final argument. +# ------------------------------------------------------------------------ + +sub format { + my $self = shift; + my $params = ref($_[$#_]) eq 'HASH' ? pop(@_) : { }; + my $time = shift(@_) || $params->{ time } || $self->{ time } + || $self->now(); + my $format = @_ ? shift(@_) + : ($params->{ format } || $self->{ format } || $FORMAT); + my $locale = @_ ? shift(@_) + : ($params->{ locale } || $self->{ locale }); + my $gmt = @_ ? shift(@_) + : ($params->{ gmt } || $self->{ gmt }); + my (@date, $datestr); + + if ($time =~ /^\d+$/) { + # $time is now in seconds since epoch + if ($gmt) { + @date = (gmtime($time))[0..6]; + } + else { + @date = (localtime($time))[0..6]; + } + } + else { + # if $time is numeric, then we assume it's seconds since the epoch + # otherwise, we try to parse it as a 'H:M:S D:M:Y' string + @date = (split(/(?:\/| |:|-)/, $time))[2,1,0,3..5]; + return (undef, Template::Exception->new('date', + "bad time/date string: expects 'h:m:s d:m:y' got: '$time'")) + unless @date >= 6 && defined $date[5]; + $date[4] -= 1; # correct month number 1-12 to range 0-11 + $date[5] -= 1900; # convert absolute year to years since 1900 + $time = &POSIX::mktime(@date); + } + + if ($locale) { + # format the date in a specific locale, saving and subsequently + # restoring the current locale. + my $old_locale = &POSIX::setlocale(&POSIX::LC_ALL); + + # some systems expect locales to have a particular suffix + for my $suffix ('', @LOCALE_SUFFIX) { + my $try_locale = $locale.$suffix; + my $setlocale = &POSIX::setlocale(&POSIX::LC_ALL, $try_locale); + if (defined $setlocale && $try_locale eq $setlocale) { + $locale = $try_locale; + last; + } + } + $datestr = &POSIX::strftime($format, @date); + &POSIX::setlocale(&POSIX::LC_ALL, $old_locale); + } + else { + $datestr = &POSIX::strftime($format, @date); + } + + return $datestr; +} + +sub calc { + my $self = shift; + eval { require "Date/Calc.pm" }; + $self->throw("failed to load Date::Calc: $@") if $@; + return Template::Plugin::Date::Calc->new('no context'); +} + +sub manip { + my $self = shift; + eval { require "Date/Manip.pm" }; + $self->throw("failed to load Date::Manip: $@") if $@; + return Template::Plugin::Date::Manip->new('no context'); +} + + +sub throw { + my $self = shift; + die (Template::Exception->new('date', join(', ', @_))); +} + + +package Template::Plugin::Date::Calc; +use base qw( Template::Plugin ); +use vars qw( $AUTOLOAD ); +*throw = \&Template::Plugin::Date::throw; + +sub AUTOLOAD { + my $self = shift; + my $method = $AUTOLOAD; + + $method =~ s/.*:://; + return if $method eq 'DESTROY'; + + my $sub = \&{"Date::Calc::$method"}; + $self->throw("no such Date::Calc method: $method") + unless $sub; + + &$sub(@_); +} + +package Template::Plugin::Date::Manip; +use base qw( Template::Plugin ); +use vars qw( $AUTOLOAD ); +*throw = \&Template::Plugin::Date::throw; + +sub AUTOLOAD { + my $self = shift; + my $method = $AUTOLOAD; + + $method =~ s/.*:://; + return if $method eq 'DESTROY'; + + my $sub = \&{"Date::Manip::$method"}; + $self->throw("no such Date::Manip method: $method") + unless $sub; + + &$sub(@_); +} + + +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::Date - Plugin to generate formatted date strings + +=head1 SYNOPSIS + + [% USE date %] + + # use current time and default format + [% date.format %] + + # specify time as seconds since epoch or 'h:m:s d-m-y' string + [% date.format(960973980) %] + [% date.format('4:20:36 21/12/2000') %] + + # specify format + [% date.format(mytime, '%H:%M:%S') %] + + # specify locale + [% date.format(date.now, '%a %d %b %y', 'en_GB') %] + + # named parameters + [% date.format(mytime, format = '%H:%M:%S') %] + [% date.format(locale = 'en_GB') %] + [% date.format(time = date.now, + format = '%H:%M:%S', + locale = 'en_GB) %] + + # specify default format to plugin + [% USE date(format = '%H:%M:%S', locale = 'de_DE') %] + + [% date.format %] + ... + +=head1 DESCRIPTION + +The Date plugin provides an easy way to generate formatted time and date +strings by delegating to the POSIX strftime() routine. + +The plugin can be loaded via the familiar USE directive. + + [% USE date %] + +This creates a plugin object with the default name of 'date'. An alternate +name can be specified as such: + + [% USE myname = date %] + +The plugin provides the format() method which accepts a time value, a +format string and a locale name. All of these parameters are optional +with the current system time, default format ('%H:%M:%S %d-%b-%Y') and +current locale being used respectively, if undefined. Default values +for the time, format and/or locale may be specified as named parameters +in the USE directive. + + [% USE date(format = '%a %d-%b-%Y', locale = 'fr_FR') %] + +When called without any parameters, the format() method returns a string +representing the current system time, formatted by strftime() according +to the default format and for the default locale (which may not be the +current one, if locale is set in the USE directive). + + [% date.format %] + +The plugin allows a time/date to be specified as seconds since the epoch, +as is returned by time(). + + File last modified: [% date.format(filemod_time) %] + +The time/date can also be specified as a string of the form 'h:m:s d/m/y'. +Any of the characters : / - or space may be used to delimit fields. + + [% USE day = date(format => '%A', locale => 'en_GB') %] + [% day.format('4:20:00 9-13-2000') %] + +Output: + + Tuesday + +A format string can also be passed to the format() method, and a locale +specification may follow that. + + [% date.format(filemod, '%d-%b-%Y') %] + [% date.format(filemod, '%d-%b-%Y', 'en_GB') %] + +A fourth parameter allows you to force output in GMT, in the case of +seconds-since-the-epoch input: + + [% date.format(filemod, '%d-%b-%Y', 'en_GB', 1) %] + +Note that in this case, if the local time is not GMT, then also specifying +'%Z' (time zone) in the format parameter will lead to an extremely +misleading result. + +Any or all of these parameters may be named. Positional parameters +should always be in the order ($time, $format, $locale). + + [% date.format(format => '%H:%M:%S') %] + [% date.format(time => filemod, format => '%H:%M:%S') %] + [% date.format(mytime, format => '%H:%M:%S') %] + [% date.format(mytime, format => '%H:%M:%S', locale => 'fr_FR') %] + [% date.format(mytime, format => '%H:%M:%S', gmt => 1) %] + ...etc... + +The now() method returns the current system time in seconds since the +epoch. + + [% date.format(date.now, '%A') %] + +The calc() method can be used to create an interface to the Date::Calc +module (if installed on your system). + + [% calc = date.calc %] + [% calc.Monday_of_Week(22, 2001).join('/') %] + +The manip() method can be used to create an interface to the Date::Manip +module (if installed on your system). + + [% manip = date.manip %] + [% manip.UnixDate("Noon Yesterday","%Y %b %d %H:%M") %] + +=head1 AUTHORS + +Thierry-Michel Barral E<lt>kktos@electron-libre.comE<gt> wrote the original +plugin. + +Andy Wardley E<lt>abw@cre.canon.co.ukE<gt> provided some minor +fixups/enhancements, a test script and documentation. + +Mark D. Mills E<lt>mark@hostile.orgE<gt> cloned Date::Manip from the +cute Date::Calc sub-plugin. + +=head1 VERSION + +2.71, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + + + +=head1 COPYRIGHT + +Copyright (C) 2000 Thierry-Michel Barral, Andy Wardley. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<POSIX|POSIX> + diff --git a/lib/Template/Plugin/Directory.pm b/lib/Template/Plugin/Directory.pm new file mode 100644 index 0000000..ec6247e --- /dev/null +++ b/lib/Template/Plugin/Directory.pm @@ -0,0 +1,410 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Directory +# +# DESCRIPTION +# Plugin for encapsulating information about a file system directory. +# +# AUTHORS +# Michael Stevens <michael@etla.org>, with some mutilations from +# Andy Wardley <abw@kfs.org>. +# +# COPYRIGHT +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: Directory.pm,v 2.64 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Directory; + +require 5.004; + +use strict; +use Cwd; +use File::Spec; +use Template::Plugin::File; +use vars qw( $VERSION ); +use base qw( Template::Plugin::File ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + + +#------------------------------------------------------------------------ +# new(\%config) +# +# Constructor method. +#------------------------------------------------------------------------ + +sub new { + my $config = ref($_[-1]) eq 'HASH' ? pop(@_) : { }; + my ($class, $context, $path) = @_; + + return $class->throw('no directory specified') + unless defined $path and length $path; + + my $self = $class->SUPER::new($context, $path, $config); + my ($dir, @files, $name, $item, $abs, $rel, $check); + $self->{ files } = [ ]; + $self->{ dirs } = [ ]; + $self->{ list } = [ ]; + $self->{ _dir } = { }; + + # don't read directory if 'nostat' or 'noscan' set + return $self if $config->{ nostat } || $config->{ noscan }; + + $self->throw("$path: not a directory") + unless $self->{ isdir }; + + $self->scan($config); + + return $self; +} + + +#------------------------------------------------------------------------ +# scan(\%config) +# +# Scan directory for files and sub-directories. +#------------------------------------------------------------------------ + +sub scan { + my ($self, $config) = @_; + $config ||= { }; + local *DH; + my ($dir, @files, $name, $abs, $rel, $item); + + # set 'noscan' in config if recurse isn't set, to ensure Directories + # created don't try to scan deeper + $config->{ noscan } = 1 unless $config->{ recurse }; + + $dir = $self->{ abs }; + opendir(DH, $dir) or return $self->throw("$dir: $!"); + + @files = readdir DH; + closedir(DH) + or return $self->throw("$dir close: $!"); + + my ($path, $files, $dirs, $list) = @$self{ qw( path files dirs list ) }; + @$files = @$dirs = @$list = (); + + foreach $name (sort @files) { + next if $name =~ /^\./; + $abs = File::Spec->catfile($dir, $name); + $rel = File::Spec->catfile($path, $name); + + if (-d $abs) { + $item = Template::Plugin::Directory->new(undef, $rel, $config); + push(@$dirs, $item); + } + else { + $item = Template::Plugin::File->new(undef, $rel, $config); + push(@$files, $item); + } + push(@$list, $item); + $self->{ _dir }->{ $name } = $item; + } + + return ''; +} + + +#------------------------------------------------------------------------ +# file($filename) +# +# Fetch a named file from this directory. +#------------------------------------------------------------------------ + +sub file { + my ($self, $name) = @_; + return $self->{ _dir }->{ $name }; +} + + +#------------------------------------------------------------------------ +# present($view) +# +# Present self to a Template::View +#------------------------------------------------------------------------ + +sub present { + my ($self, $view) = @_; + $view->view_directory($self); +} + + +#------------------------------------------------------------------------ +# content($view) +# +# Present directory content to a Template::View. +#------------------------------------------------------------------------ + +sub content { + my ($self, $view) = @_; + return $self->{ list } unless $view; + my $output = ''; + foreach my $file (@{ $self->{ list } }) { + $output .= $file->present($view); + } + return $output; +} + + +#------------------------------------------------------------------------ +# throw($msg) +# +# Throw a 'Directory' exception. +#------------------------------------------------------------------------ + +sub throw { + my ($self, $error) = @_; + die (Template::Exception->new('Directory', $error)); +} + +__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::Directory - Plugin for generating directory listings + +=head1 SYNOPSIS + + [% USE dir = Directory(dirpath) %] + + # files returns list of regular files + [% FOREACH file = dir.files %] + [% file.name %] [% file.path %] ... + [% END %] + + # dirs returns list of sub-directories + [% FOREACH subdir = dir.dirs %] + [% subdir.name %] [% subdir.path %] ... + [% END %] + + # list returns both interleaved in order + [% FOREACH item = dir.list %] + [% IF item.isdir %] + Directory: [% item.name %] + [% ELSE + File: [% item.name %] + [% END %] + [% END %] + + # define a VIEW to display dirs/files + [% VIEW myview %] + [% BLOCK file %] + File: [% item.name %] + [% END %] + + [% BLOCK directory %] + Directory: [% item.name %] + [% item.content(myview) | indent -%] + [% END %] + [% END %] + + # display directory content using view + [% myview.print(dir) %] + +=head1 DESCRIPTION + +This Template Toolkit plugin provides a simple interface to directory +listings. It is derived from the Template::Plugin::File module and +uses Template::Plugin::File object instances to represent files within +a directory. Sub-directories within a directory are represented by +further Template::Plugin::Directory instances. + +The constructor expects a directory name as an argument. + + [% USE dir = Directory('/tmp') %] + +It then provides access to the files and sub-directories contained within +the directory. + + # regular files (not directories) + [% FOREACH file = dir.files %] + [% file.name %] + [% END %] + + # directories only + [% FOREACH file = dir.dirs %] + [% file.name %] + [% END %] + + # files and/or directories + [% FOREACH file = dir.list %] + [% file.name %] ([% file.isdir ? 'directory' : 'file' %]) + [% END %] + + [% USE Directory('foo/baz') %] + +The plugin constructor will throw a 'Directory' error if the specified +path does not exist, is not a directory or fails to stat() (see +L<Template::Plugin::File>). Otherwise, it will scan the directory and +create lists named 'files' containing files, 'dirs' containing +directories and 'list' containing both files and directories combined. +The 'nostat' option can be set to disable all file/directory checks +and directory scanning. + +Each file in the directory will be represented by a +Template::Plugin::File object instance, and each directory by another +Template::Plugin::Directory. If the 'recurse' flag is set, then those +directories will contain further nested entries, and so on. With the +'recurse' flag unset, as it is by default, then each is just a place +marker for the directory and does not contain any further content +unless its scan() method is explicitly called. The 'isdir' flag can +be tested against files and/or directories, returning true if the item +is a directory or false if it is a regular file. + + [% FOREACH file = dir.list %] + [% IF file.isdir %] + * Directory: [% file.name %] + [% ELSE %] + * File: [% file.name %] + [% END %] + [% END %] + +This example shows how you might walk down a directory tree, displaying +content as you go. With the recurse flag disabled, as is the default, +we need to explicitly call the scan() method on each directory, to force +it to lookup files and further sub-directories contained within. + + [% USE dir = Directory(dirpath) %] + * [% dir.path %] + [% INCLUDE showdir %] + + [% BLOCK showdir -%] + [% FOREACH file = dir.list -%] + [% IF file.isdir -%] + * [% file.name %] + [% file.scan -%] + [% INCLUDE showdir dir=file FILTER indent(4) -%] + [% ELSE -%] + - [% f.name %] + [% END -%] + [% END -%] + [% END %] + +This example is adapted (with some re-formatting for clarity) from +a test in F<t/directry.t> which produces the following output: + + * test/dir + - file1 + - file2 + * sub_one + - bar + - foo + * sub_two + - waz.html + - wiz.html + - xyzfile + +The 'recurse' flag can be set (disabled by default) to cause the +constructor to automatically recurse down into all sub-directories, +creating a new Template::Plugin::Directory object for each one and +filling it with any further content. In this case there is no need +to explicitly call the scan() method. + + [% USE dir = Directory(dirpath, recurse=1) %] + ... + + [% IF file.isdir -%] + * [% file.name %] + [% INCLUDE showdir dir=file FILTER indent(4) -%] + [% ELSE -%] + ... + +From version 2.01, the Template Toolkit provides support for views. +A view can be defined as a VIEW ... END block and should contain +BLOCK definitions for files ('file') and directories ('directory'). + + [% VIEW myview %] + [% BLOCK file %] + - [% item.name %] + [% END %] + + [% BLOCK directory %] + * [% item.name %] + [% item.content(myview) FILTER indent %] + [% END %] + [% END %] + +Then the view print() method can be called, passing the +Directory object as an argument. + + [% USE dir = Directory(dirpath, recurse=1) %] + [% myview.print(dir) %] + +When a directory is presented to a view, either as [% myview.print(dir) %] +or [% dir.present(view) %], then the 'directory' BLOCK within the 'myview' +VIEW is processed, with the 'item' variable set to alias the Directory object. + + [% BLOCK directory %] + * [% item.name %] + [% item.content(myview) FILTER indent %] + [% END %] + +The directory name is first printed and the content(view) method is +then called to present each item within the directory to the view. +Further directories will be mapped to the 'directory' block, and files +will be mapped to the 'file' block. + +With the recurse option disabled, as it is by default, the 'directory' +block should explicitly call a scan() on each directory. + + [% VIEW myview %] + [% BLOCK file %] + - [% item.name %] + [% END %] + + [% BLOCK directory %] + * [% item.name %] + [% item.scan %] + [% item.content(myview) FILTER indent %] + [% END %] + [% END %] + + [% USE dir = Directory(dirpath) %] + [% myview.print(dir) %] + +=head1 TODO + +Might be nice to be able to specify accept/ignore options to catch +a subset of files. + +=head1 AUTHORS + +Michael Stevens E<lt>michael@etla.orgE<gt> wrote the original Directory plugin +on which this is based. Andy Wardley E<lt>abw@wardley.orgE<gt> split it into +separate File and Directory plugins, added some extra code and documentation +for VIEW support, and made a few other minor tweaks. + +=head1 VERSION + +2.64, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + + + +=head1 COPYRIGHT + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::File|Template::Plugin::File>, L<Template::View|Template::View> + diff --git a/lib/Template/Plugin/Dumper.pm b/lib/Template/Plugin/Dumper.pm new file mode 100644 index 0000000..5dbf1f6 --- /dev/null +++ b/lib/Template/Plugin/Dumper.pm @@ -0,0 +1,179 @@ +#============================================================================== +# +# Template::Plugin::Dumper +# +# DESCRIPTION +# +# A Template Plugin to provide a Template Interface to Data::Dumper +# +# AUTHOR +# Simon Matthews <sam@knowledgepool.com> +# +# COPYRIGHT +# +# Copyright (C) 2000 Simon Matthews. All Rights Reserved +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#------------------------------------------------------------------------------ +# +# $Id: Dumper.pm,v 2.64 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================== + +package Template::Plugin::Dumper; + +require 5.004; + +use strict; +use Template::Plugin; +use Data::Dumper; + +use vars qw( $VERSION $DEBUG @DUMPER_ARGS $AUTOLOAD ); +use base qw( Template::Plugin ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); +$DEBUG = 0 unless defined $DEBUG; +@DUMPER_ARGS = qw( Indent Pad Varname Purity Useqq Terse Freezer + Toaster Deepcopy Quotekeys Bless Maxdepth ); + +#============================================================================== +# ----- CLASS METHODS ----- +#============================================================================== + +#------------------------------------------------------------------------ +# new($context, \@params) +#------------------------------------------------------------------------ + +sub new { + my ($class, $context, $params) = @_; + my ($key, $val); + $params ||= { }; + + + foreach my $arg (@DUMPER_ARGS) { + no strict 'refs'; + if (defined ($val = $params->{ lc $arg }) + or defined ($val = $params->{ $arg })) { + ${"Data\::Dumper\::$arg"} = $val; + } + } + + bless { + _CONTEXT => $context, + }, $class; +} + +sub dump { + my $self = shift; + my $content = Dumper @_; + return $content; +} + + +sub dump_html { + my $self = shift; + my $content = Dumper @_; + for ($content) { + s/&/&/g; + s/</</g; + s/>/>/g; + s/\n/<br>\n/g; + } + return $content; +} + +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::Dumper - Plugin interface to Data::Dumper + +=head1 SYNOPSIS + + [% USE Dumper %] + + [% Dumper.dump(variable) %] + [% Dumper.dump_html(variable) %] + +=head1 DESCRIPTION + +This is a very simple Template Toolkit Plugin Interface to the Data::Dumper +module. A Dumper object will be instantiated via the following directive: + + [% USE Dumper %] + +As a standard plugin, you can also specify its name in lower case: + + [% USE dumper %] + +The Data::Dumper 'Pad', 'Indent' and 'Varname' options are supported +as constructor arguments to affect the output generated. See L<Data::Dumper> +for further details. + + [% USE dumper(Indent=0, Pad="<br>") %] + +These options can also be specified in lower case. + + [% USE dumper(indent=0, pad="<br>") %] + +=head1 METHODS + +There are two methods supported by the Dumper object. Each will +output into the template the contents of the variables passed to the +object method. + +=head2 dump() + +Generates a raw text dump of the data structure(s) passed + + [% USE Dumper %] + [% Dumper.dump(myvar) %] + [% Dumper.dump(myvar, yourvar) %] + +=head2 dump_html() + +Generates a dump of the data structures, as per dump(), but with the +characters E<lt>, E<gt> and E<amp> converted to their equivalent HTML +entities and newlines converted to E<lt>brE<gt>. + + [% USE Dumper %] + [% Dumper.dump_html(myvar) %] + +=head1 AUTHOR + +Simon Matthews E<lt>sam@knowledgepool.comE<gt> + +=head1 VERSION + +2.64, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + + + +=head1 COPYRIGHT + +Copyright (C) 2000 Simon Matthews All Rights Reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Data::Dumper|Data::Dumper> + diff --git a/lib/Template/Plugin/File.pm b/lib/Template/Plugin/File.pm new file mode 100644 index 0000000..d1d542e --- /dev/null +++ b/lib/Template/Plugin/File.pm @@ -0,0 +1,416 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::File +# +# DESCRIPTION +# Plugin for encapsulating information about a system file. +# +# AUTHOR +# Originally written by Michael Stevens <michael@etla.org> as the +# Directory plugin, then mutilated by Andy Wardley <abw@kfs.org> +# into separate File and Directory plugins, with some additional +# code for working with views, etc. +# +# COPYRIGHT +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: File.pm,v 2.64 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::File; + +require 5.004; + +use strict; +use Cwd; +use File::Spec; +use File::Basename; +use Template::Plugin; + +use vars qw( $VERSION ); +use base qw( Template::Plugin ); +use vars qw( @STAT_KEYS ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + +@STAT_KEYS = qw( dev ino mode nlink uid gid rdev size + atime mtime ctime blksize blocks ); + + +#------------------------------------------------------------------------ +# new($context, $file, \%config) +# +# Create a new File object. Takes the pathname of the file as +# the argument following the context and an optional +# hash reference of configuration parameters. +#------------------------------------------------------------------------ + +sub new { + my $config = ref($_[-1]) eq 'HASH' ? pop(@_) : { }; + my ($class, $context, $path) = @_; + my ($root, $home, @stat, $abs); + + return $class->throw('no file specified') + unless defined $path and length $path; + + # path, dir, name, root, home + + if (File::Spec->file_name_is_absolute($path)) { + $root = ''; + } + elsif (($root = $config->{ root })) { + # strip any trailing '/' from root + $root =~ s[/$][]; + } + else { + $root = ''; + } + + my ($name, $dir, $ext) = fileparse($path, '\.\w+'); + # fixup various items + $dir =~ s[/$][]; + $dir = '' if $dir eq '.'; + $name = $name . $ext; + $ext =~ s/^\.//g; + my @fields = File::Spec->splitdir($dir); + shift @fields if @fields && ! length $fields[0]; + $home = join('/', ('..') x @fields); + $abs = File::Spec->catfile($root ? $root : (), $path); + + my $self = { + path => $path, + name => $name, + root => $root, + home => $home, + dir => $dir, + ext => $ext, + abs => $abs, + user => '', + group => '', + isdir => '', + stat => defined $config->{ stat } ? $config->{ stat } + : ! $config->{ nostat }, + map { ($_ => '') } @STAT_KEYS, + }; + + if ($self->{ stat }) { + (@stat = stat( $abs )) + || return $class->throw("$abs: $!"); + @$self{ @STAT_KEYS } = @stat; + unless ($config->{ noid }) { + $self->{ user } = eval { getpwuid( $self->{ uid }) || $self->{ uid } }; + $self->{ group } = eval { getgrgid( $self->{ gid }) || $self->{ gid } }; + } + $self->{ isdir } = -d $abs; + } + + bless $self, $class; +} + + +#------------------------------------------------------------------------- +# rel($file) +# +# Generate a relative filename for some other file relative to this one. +#------------------------------------------------------------------------ + +sub rel { + my ($self, $path) = @_; + $path = $path->{ path } if ref $path eq ref $self; # assumes same root + return $path if $path =~ m[^/]; + return $path unless $self->{ home }; + return $self->{ home } . '/' . $path; +} + + +#------------------------------------------------------------------------ +# present($view) +# +# Present self to a Template::View. +#------------------------------------------------------------------------ + +sub present { + my ($self, $view) = @_; + $view->view_file($self); +} + + +sub throw { + my ($self, $error) = @_; + die (Template::Exception->new('File', $error)); +} + +__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::File - Plugin providing information about files + +=head1 SYNOPSIS + + [% USE File(filepath) %] + [% File.path %] # full path + [% File.name %] # filename + [% File.dir %] # directory + +=head1 DESCRIPTION + +This plugin provides an abstraction of a file. It can be used to +fetch details about files from the file system, or to represent abstract +files (e.g. when creating an index page) that may or may not exist on +a file system. + +A file name or path should be specified as a constructor argument. e.g. + + [% USE File('foo.html') %] + [% USE File('foo/bar/baz.html') %] + [% USE File('/foo/bar/baz.html') %] + +The file should exist on the current file system (unless 'nostat' +option set, see below) as an absolute file when specified with as +leading '/' as per '/foo/bar/baz.html', or otherwise as one relative +to the current working directory. The constructor performs a stat() +on the file and makes the 13 elements returned available as the plugin +items: + + dev ino mode nlink uid gid rdev size + atime mtime ctime blksize blocks + +e.g. + + [% USE File('/foo/bar/baz.html') %] + + [% File.mtime %] + [% File.mode %] + ... + +In addition, the 'user' and 'group' items are set to contain the user +and group names as returned by calls to getpwuid() and getgrgid() for +the file 'uid' and 'gid' elements, respectively. On Win32 platforms +on which getpwuid() and getgrid() are not available, these values are +undefined. + + [% USE File('/tmp/foo.html') %] + [% File.uid %] # e.g. 500 + [% File.user %] # e.g. abw + +This user/group lookup can be disabled by setting the 'noid' option. + + [% USE File('/tmp/foo.html', noid=1) %] + [% File.uid %] # e.g. 500 + [% File.user %] # nothing + +The 'isdir' flag will be set if the file is a directory. + + [% USE File('/tmp') %] + [% File.isdir %] # 1 + +If the stat() on the file fails (e.g. file doesn't exists, bad +permission, etc) then the constructor will throw a 'File' exception. +This can be caught within a TRY...CATCH block. + + [% TRY %] + [% USE File('/tmp/myfile') %] + File exists! + [% CATCH File %] + File error: [% error.info %] + [% END %] + +Note the capitalisation of the exception type, 'File' to indicate an +error thrown by the 'File' plugin, to distinguish it from a regular +'file' exception thrown by the Template Toolkit. + +Note that the 'File' plugin can also be referenced by the lower case +name 'file'. However, exceptions are always thrown of the 'File' +type, regardless of the capitalisation of the plugin named used. + + [% USE file('foo.html') %] + [% file.mtime %] + +As with any other Template Toolkit plugin, an alternate name can be +specified for the object created. + + [% USE foo = file('foo.html') %] + [% foo.mtime %] + +The 'nostat' option can be specified to prevent the plugin constructor +from performing a stat() on the file specified. In this case, the +file does not have to exist in the file system, no attempt will be made +to verify that it does, and no error will be thrown if it doesn't. +The entries for the items usually returned by stat() will be set +empty. + + [% USE file('/some/where/over/the/rainbow.html', nostat=1) + [% file.mtime %] # nothing + +All File plugins, regardless of the nostat option, have set a number +of items relating to the original path specified. + +=over 4 + +=item path + +The full, original file path specified to the constructor. + + [% USE file('/foo/bar.html') %] + [% file.path %] # /foo/bar.html + +=item name + +The name of the file without any leading directories. + + [% USE file('/foo/bar.html') %] + [% file.name %] # bar.html + +=item dir + +The directory element of the path with the filename removed. + + [% USE file('/foo/bar.html') %] + [% file.name %] # /foo + +=item ext + +The file extension, if any, appearing at the end of the path following +a '.' (not included in the extension). + + [% USE file('/foo/bar.html') %] + [% file.ext %] # html + +=item home + +This contains a string of the form '../..' to represent the upward path +from a file to its root directory. + + [% USE file('bar.html') %] + [% file.home %] # nothing + + [% USE file('foo/bar.html') %] + [% file.home %] # .. + + [% USE file('foo/bar/baz.html') %] + [% file.home %] # ../.. + +=item root + +The 'root' item can be specified as a constructor argument, indicating +a root directory in which the named file resides. This is otherwise +set empty. + + [% USE file('foo/bar.html', root='/tmp') %] + [% file.root %] # /tmp + +=item abs + +This returns the absolute file path by constructing a path from the +'root' and 'path' options. + + [% USE file('foo/bar.html', root='/tmp') %] + [% file.path %] # foo/bar.html + [% file.root %] # /tmp + [% file.abs %] # /tmp/foo/bar.html + +=back + +In addition, the following method is provided: + +=over 4 + +=item rel(path) + +This returns a relative path from the current file to another path specified +as an argument. It is constructed by appending the path to the 'home' +item. + + [% USE file('foo/bar/baz.html') %] + [% file.rel('wiz/waz.html') %] # ../../wiz/waz.html + +=back + +=head1 EXAMPLES + + [% USE file('/foo/bar/baz.html') %] + + [% file.path %] # /foo/bar/baz.html + [% file.dir %] # /foo/bar + [% file.name %] # baz.html + [% file.home %] # ../.. + [% file.root %] # '' + [% file.abspath %] # /foo/bar/baz.html + [% file.ext %] # html + [% file.mtime %] # 987654321 + [% file.atime %] # 987654321 + [% file.uid %] # 500 + [% file.user %] # abw + + [% USE file('foo.html') %] + + [% file.path %] # foo.html + [% file.dir %] # '' + [% file.name %] # foo.html + [% file.root %] # '' + [% file.home %] # '' + [% file.abspath %] # foo.html + + [% USE file('foo/bar/baz.html') %] + + [% file.path %] # foo/bar/baz.html + [% file.dir %] # foo/bar + [% file.name %] # baz.html + [% file.root %] # '' + [% file.home %] # ../.. + [% file.abspath %] # foo/bar/baz.html + + [% USE file('foo/bar/baz.html', root='/tmp') %] + + [% file.path %] # foo/bar/baz.html + [% file.dir %] # foo/bar + [% file.name %] # baz.html + [% file.root %] # /tmp + [% file.home %] # ../.. + [% file.abspath %] # /tmp/foo/bar/baz.html + + # calculate other file paths relative to this file and its root + [% USE file('foo/bar/baz.html', root => '/tmp/tt2') %] + [% file.path('baz/qux.html') %] # ../../baz/qux.html + [% file.dir('wiz/woz.html') %] # ../../wiz/woz.html + + +=head1 AUTHORS + +Michael Stevens E<lt>michael@etla.orgE<gt> wrote the original Directory plugin +on which this is based. Andy Wardley E<lt>abw@wardley.orgE<gt> split it into +separate File and Directory plugins, added some extra code and documentation +for VIEW support, and made a few other minor tweaks. + +=head1 VERSION + +2.64, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + + + +=head1 COPYRIGHT + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::Directory|Template::Plugin::Directory>, L<Template::View|Template::View> + diff --git a/lib/Template/Plugin/Filter.pm b/lib/Template/Plugin/Filter.pm new file mode 100644 index 0000000..38da7ba --- /dev/null +++ b/lib/Template/Plugin/Filter.pm @@ -0,0 +1,436 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Filter +# +# DESCRIPTION +# Template Toolkit module implementing a base class plugin +# object which acts like a filter and can be used with the +# FILTER directive. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2001 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: Filter.pm,v 1.30 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Filter; + +require 5.004; + +use strict; +use Template::Plugin; + +use base qw( Template::Plugin ); +use vars qw( $VERSION $DYNAMIC ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.30 $ =~ /(\d+)\.(\d+)/); +$DYNAMIC = 0 unless defined $DYNAMIC; + + +sub new { + my ($class, $context, @args) = @_; + my $config = @args && ref $args[-1] eq 'HASH' ? pop(@args) : { }; + + # look for $DYNAMIC + my $dynamic; + { + no strict 'refs'; + $dynamic = ${"$class\::DYNAMIC"}; + } + $dynamic = $DYNAMIC unless defined $dynamic; + + my $self = bless { + _CONTEXT => $context, + _DYNAMIC => $dynamic, + _ARGS => \@args, + _CONFIG => $config, + }, $class; + + return $self->init($config) + || $class->error($self->error()); +} + + +sub init { + my ($self, $config) = @_; + return $self; +} + + +sub factory { + my $self = shift; + + if ($self->{ _DYNAMIC }) { + return $self->{ _DYNAMIC_FILTER } ||= [ sub { + my ($context, @args) = @_; + my $config = ref $args[-1] eq 'HASH' ? pop(@args) : { }; + + return sub { + $self->filter(shift, \@args, $config); + }; + }, 1 ]; + } + else { + return $self->{ _STATIC_FILTER } ||= sub { + $self->filter(shift); + }; + } +} + + +sub filter { + my ($self, $text, $args, $config) = @_; + return $text; +} + + +sub merge_config { + my ($self, $newcfg) = @_; + my $owncfg = $self->{ _CONFIG }; + return $owncfg unless $newcfg; + return { %$owncfg, %$newcfg }; +} + + +sub merge_args { + my ($self, $newargs) = @_; + my $ownargs = $self->{ _ARGS }; + return $ownargs unless $newargs; + return [ @$ownargs, @$newargs ]; +} + + +sub install_filter { + my ($self, $name) = @_; + $self->{ _CONTEXT }->define_filter( $name => $self->factory() ); + return $self; +} + + + +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::Filter - Base class for plugin filters + +=head1 SYNOPSIS + + 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 %] + +=head1 DESCRIPTION + +This module implements a base class for plugin filters. It hides +the underlying complexity involved in creating and using filters +that get defined and made available by loading a plugin. + +To use the module, simply create your own plugin module that is +inherited from the Template::Plugin::Filter class. + + package MyOrg::Template::Plugin::MyFilter; + + use Template::Plugin::Filter; + use base qw( Template::Plugin::Filter ); + +Then simply define your filter() method. When called, you get +passed a reference to your plugin object ($self) and the text +to be filtered. + + sub filter { + my ($self, $text) = @_; + + # ...mungify $text... + + return $text; + } + +To use your custom plugin, you have to make sure that the Template +Toolkit knows about your plugin namespace. + + my $tt2 = Template->new({ + PLUGIN_BASE => 'MyOrg::Template::Plugin', + }); + +Or for individual plugins you can do it like this: + + my $tt2 = Template->new({ + PLUGINS => { + MyFilter => 'MyOrg::Template::Plugin::MyFilter', + }, + }); + +Then you USE your plugin in the normal way. + + [% USE MyFilter %] + +The object returned is stored in the variable of the same name, +'MyFilter'. When you come to use it as a FILTER, you should add +a dollar prefix. This indicates that you want to use the filter +stored in the variable 'MyFilter' rather than the filter named +'MyFilter', which is an entirely different thing (see later for +information on defining filters by name). + + [% FILTER $MyFilter %] + ...text to be filtered... + [% END %] + +You can, of course, assign it to a different variable. + + [% USE blat = MyFilter %] + + [% FILTER $blat %] + ...text to be filtered... + [% END %] + +Any configuration parameters passed to the plugin constructor from the +USE directive are stored internally in the object for inspection by +the filter() method (or indeed any other method). Positional +arguments are stored as a reference to a list in the _ARGS item while +named configuration parameters are stored as a reference to a hash +array in the _CONFIG item. + +For example, loading a plugin as shown here: + + [% USE blat = MyFilter 'foo' 'bar' baz = 'blam' %] + +would allow the filter() method to do something like this: + + sub filter { + my ($self, $text) = @_; + + my $args = $self->{ _ARGS }; # [ 'foo', 'bar' ] + my $conf = $self->{ _CONFIG }; # { baz => 'blam' } + + # ...munge $text... + + return $text; + } + +By default, plugins derived from this module will create static +filters. A static filter is created once when the plugin gets +loaded via the USE directive and re-used for all subsequent +FILTER operations. That means that any argument specified with +the FILTER directive are ignored. + +Dynamic filters, on the other hand, are re-created each time +they are used by a FILTER directive. This allows them to act +on any parameters passed from the FILTER directive and modify +their behaviour accordingly. + +There are two ways to create a dynamic filter. The first is to +define a $DYNAMIC class variable set to a true value. + + package MyOrg::Template::Plugin::MyFilter; + + use Template::Plugin::Filter; + use base qw( Template::Plugin::Filter ); + use vars qw( $DYNAMIC ); + + $DYNAMIC = 1; + +The other way is to set the internal _DYNAMIC value within the init() +method which gets called by the new() constructor. + + sub init { + my $self = shift; + $self->{ _DYNAMIC } = 1; + return $self; + } + +When this is set to a true value, the plugin will automatically +create a dynamic filter. The outcome is that the filter() method +will now also get passed a reference to an array of postional +arguments and a reference to a hash array of named parameters. + +So, using a plugin filter like this: + + [% FILTER $blat 'foo' 'bar' baz = 'blam' %] + +would allow the filter() method to work like this: + + sub filter { + my ($self, $text, $args, $conf) = @_; + + # $args = [ 'foo', 'bar' ] + # $conf = { baz => 'blam' } + + } + +In this case can pass parameters to both the USE and FILTER directives, +so your filter() method should probably take that into account. + + [% USE MyFilter 'foo' wiz => 'waz' %] + + [% FILTER $MyFilter 'bar' biz => 'baz' %] + ... + [% END %] + +You can use the merge_args() and merge_config() methods to do a quick +and easy job of merging the local (e.g. FILTER) parameters with the +internal (e.g. USE) values and returning new sets of conglomerated +data. + + sub filter { + my ($self, $text, $args, $conf) = @_; + + $args = $self->merge_args($args); + $conf = $self->merge_config($conf); + + # $args = [ 'foo', 'bar' ] + # $conf = { wiz => 'waz', biz => 'baz' } + ... + } + +You can also have your plugin install itself as a named filter by +calling the install_filter() method from the init() method. You +should provide a name for the filter, something that you might +like to make a configuration option. + + sub init { + my $self = shift; + my $name = $self->{ _CONFIG }->{ name } || 'myfilter'; + $self->install_filter($name); + return $self; + } + +This allows the plugin filter to be used as follows: + + [% USE MyFilter %] + + [% FILTER myfilter %] + ... + [% END %] + +or + + [% USE MyFilter name = 'swipe' %] + + [% FILTER swipe %] + ... + [% END %] + +Alternately, you can allow a filter name to be specified as the +first positional argument. + + sub init { + my $self = shift; + my $name = $self->{ _ARGS }->[0] || 'myfilter'; + $self->install_filter($name); + return $self; + } + + [% USE MyFilter 'swipe' %] + + [% FILTER swipe %] + ... + [% END %] + +=head1 EXAMPLE + +Here's a complete example of a plugin filter module. + + package My::Template::Plugin::Change; + use Template::Plugin::Filter; + use base qw( Template::Plugin::Filter ); + + sub init { + my $self = shift; + + $self->{ _DYNAMIC } = 1; + + # first arg can specify filter name + $self->install_filter($self->{ _ARGS }->[0] || 'change'); + + return $self; + } + + + sub filter { + my ($self, $text, $args, $config) = @_; + + $config = $self->merge_config($config); + my $regex = join('|', keys %$config); + + $text =~ s/($regex)/$config->{ $1 }/ge; + + return $text; + } + + 1; + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +1.30, 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<Template::Plugin|Template::Plugin>, L<Template::Filters|Template::Filters>, L<Template::Manual::Filters|Template::Manual::Filters> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Format.pm b/lib/Template/Plugin/Format.pm new file mode 100644 index 0000000..bba55d2 --- /dev/null +++ b/lib/Template/Plugin/Format.pm @@ -0,0 +1,124 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Format +# +# DESCRIPTION +# +# Simple Template Toolkit Plugin which creates formatting functions. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# 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: Format.pm,v 2.64 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Format; + +require 5.004; + +use strict; +use vars qw( @ISA $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + + +sub new { + my ($class, $context, $format) = @_;; + return defined $format + ? make_formatter($format) + : \&make_formatter; +} + + +sub make_formatter { + my $format = shift; + $format = '%s' unless defined $format; + return sub { + my @args = @_; + push(@args, '') unless @args; + return sprintf($format, @args); + } +} + + +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::Format - Plugin to create formatting functions + +=head1 SYNOPSIS + + [% USE format %] + [% commented = format('# %s') %] + [% commented('The cat sat on the mat') %] + + [% USE bold = format('<b>%s</b>') %] + [% bold('Hello') %] + +=head1 DESCRIPTION + +The format plugin constructs sub-routines which format text according to +a printf()-like format string. + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.64, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Constants.pm b/lib/Template/Plugin/GD/Constants.pm new file mode 100644 index 0000000..6fc8e7c --- /dev/null +++ b/lib/Template/Plugin/GD/Constants.pm @@ -0,0 +1,138 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Constants +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD constants +# in the GD.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Constants.pm,v 1.55 2004/01/13 16:20:46 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Constants; + +require 5.004; + +use strict; +use GD qw(/^gd/ /^GD/); +use Template::Plugin; +use base qw( Template::Plugin ); +use vars qw( @ISA $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + my $self = { }; + bless $self, $class; + + # + # GD has exported various gd* and GD_* contstants. Find them. + # + foreach my $v ( keys(%Template::Plugin::GD::Constants::) ) { + $self->{$v} = eval($v) if ( $v =~ /^gd/ || $v =~ /^GD_/ ); + } + return $self; +} + +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::GD::Constants - Interface to GD module constants + +=head1 SYNOPSIS + + [% USE gdc = GD.Constants %] + + # --> the constants gdc.gdBrushed, gdc.gdSmallFont, gdc.GD_CMP_IMAGE + # are now available + +=head1 EXAMPLES + + [% FILTER null; + USE gdc = GD.Constants; + USE im = GD.Image(200,100); + black = im.colorAllocate(0 ,0, 0); + red = im.colorAllocate(255,0, 0); + r = im.string(gdc.gdLargeFont, 10, 10, "Large Red Text", red); + im.png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Constants plugin provides access to the various GD module's +constants (such as gdBrushed, gdSmallFont, gdTransparent, GD_CMP_IMAGE +etc). When GD.pm is used in perl it exports various contstants +into the caller's namespace. This plugin makes those exported +constants available as template variables. + +See L<Template::Plugin::GD::Image> and L<GD> for further examples and +details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +Lincoln D. Stein wrote the GD.pm interface to the GD library. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +The GD.pm interface is copyright 1995-2000, Lincoln D. Stein. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Image|Template::Plugin::GD::Image>, L<Template::Plugin::GD::Polygon|Template::Plugin::GD::Polygon>, L<GD|GD> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/area.pm b/lib/Template/Plugin/GD/Graph/area.pm new file mode 100644 index 0000000..d09d024 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/area.pm @@ -0,0 +1,148 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::area +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::area +# package in the GD::Graph.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: area.pm,v 1.57 2004/01/13 16:20:51 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::area; + +require 5.004; + +use strict; +use GD::Graph::area; +use Template::Plugin; +use base qw( GD::Graph::area Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::area - Create area graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.area(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + data = [ + ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"], + [ 5, 12, 24, 33, 19, 8, 6, 15, 21], + [ -1, -2, -5, -6, -3, 1.5, 1, 1.3, 2] + ]; + + USE my_graph = GD.Graph.area(); + my_graph.set( + two_axes => 1, + zero_axis => 1, + transparent => 0, + ); + my_graph.set_legend('left axis', 'right axis' ); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.area plugin provides an interface to the GD::Graph::area +class defined by the GD::Graph module. It allows one or more (x,y) data +sets to be plotted as lines with the area between the line and x-axis +shaded, in addition to axes and legends. + +See L<GD::Graph> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/bars.pm b/lib/Template/Plugin/GD/Graph/bars.pm new file mode 100644 index 0000000..9bc08c5 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/bars.pm @@ -0,0 +1,191 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::bars +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::bars +# package in the GD::Graph.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: bars.pm,v 1.57 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::bars; + +require 5.004; + +use strict; +use GD::Graph::bars; +use Template::Plugin; +use base qw( GD::Graph::bars Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::bars - Create bar graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.bars(x_size, y_size); %] + +=head1 EXAMPLES + + [% 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.bars(); + + my_graph.set( + x_label => 'X Label', + y_label => 'Y label', + title => 'A Simple 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; + -%] + + [% FILTER null; + data = [ + ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"], + [ 5, 12, 24, 33, 19, 8, 6, 15, 21], + [ 1, 2, 5, 6, 3, 1.5, 1, 3, 4], + ]; + + USE my_graph = GD.Graph.bars(); + + my_graph.set( + x_label => 'X Label', + y_label => 'Y label', + title => 'Two data sets', + + # shadows + bar_spacing => 8, + shadow_depth => 4, + shadowclr => 'dred', + + long_ticks => 1, + y_max_value => 40, + y_tick_number => 8, + y_label_skip => 2, + bar_spacing => 3, + + accent_treshold => 200, + + transparent => 0, + ); + my_graph.set_legend( 'Data set 1', 'Data set 2' ); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.bars plugin provides an interface to the GD::Graph::bars +class defined by the GD::Graph module. It allows one or more (x,y) data +sets to be plotted with each point represented by a bar, in addition +to axes and legends. + +See L<GD::Graph> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/bars3d.pm b/lib/Template/Plugin/GD/Graph/bars3d.pm new file mode 100644 index 0000000..79a930b --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/bars3d.pm @@ -0,0 +1,166 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::bars3d +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::bars3d +# package in the GD::Graph3D.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: bars3d.pm,v 1.57 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::bars3d; + +require 5.004; + +use strict; +use GD::Graph::bars3d; +use Template::Plugin; +use base qw( GD::Graph::bars3d Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::bars3d - Create 3D bar graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.bars3d(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + data = [ + ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec", ], + [-5, -4, -3, -3, -1, 0, 2, 1, 3, 4, 6, 7], + [4, 3, 5, 6, 3,1.5, -1, -3, -4, -6, -7, -8], + [1, 2, 2, 3, 4, 3, 1, -1, 0, 2, 3, 2], + ]; + + USE my_graph = GD.Graph.bars3d(); + + my_graph.set( + x_label => 'Month', + y_label => 'Measure of success', + title => 'A 3d Bar Chart', + + y_max_value => 8, + y_min_value => -8, + y_tick_number => 16, + y_label_skip => 2, + box_axis => 0, + line_width => 3, + zero_axis_only => 1, + x_label_position => 1, + y_label_position => 1, + + x_label_skip => 3, + x_tick_offset => 2, + + transparent => 0, + ); + my_graph.set_legend("Us", "Them", "Others"); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.bars3d plugin provides an interface to the GD::Graph::bars3d +class defined by the GD::Graph3d module. It allows one or more (x,y) data +sets to be plotted as y versus x bars with a 3-dimensional appearance, +together with axes and legends. + +See L<GD::Graph3d> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph3d module was written by Jeremy Wadsack. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph3d is copyright (C) 1999,2000 Wadsack-Allen. All Rights Reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph>, L<GD::Graph3d|GD::Graph3d> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/lines.pm b/lib/Template/Plugin/GD/Graph/lines.pm new file mode 100644 index 0000000..678cc64 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/lines.pm @@ -0,0 +1,178 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::lines +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::lines +# package in the GD::Graph.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: lines.pm,v 1.57 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::lines; + +require 5.004; + +use strict; +use GD::Graph::lines; +use Template::Plugin; +use base qw( GD::Graph::lines Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::lines - Create line graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.lines(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + USE g = GD.Graph.lines(300,200); + x = [1, 2, 3, 4]; + y = [5, 4, 2, 3]; + g.set( + x_label => 'X Label', + y_label => 'Y label', + title => 'Title' + ); + g.plot([x, y]).png | stdout(1); + END; + -%] + + [% FILTER null; + data = [ + ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec", ], + [-5, -4, -3, -3, -1, 0, 2, 1, 3, 4, 6, 7], + [4, 3, 5, 6, 3,1.5, -1, -3, -4, -6, -7, -8], + [1, 2, 2, 3, 4, 3, 1, -1, 0, 2, 3, 2], + ]; + + USE my_graph = GD.Graph.lines(); + + my_graph.set( + x_label => 'Month', + y_label => 'Measure of success', + title => 'A Simple Line Graph', + + y_max_value => 8, + y_min_value => -8, + y_tick_number => 16, + y_label_skip => 2, + box_axis => 0, + line_width => 3, + zero_axis_only => 1, + x_label_position => 1, + y_label_position => 1, + + x_label_skip => 3, + x_tick_offset => 2, + + transparent => 0, + ); + my_graph.set_legend("Us", "Them", "Others"); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.lines plugin provides an interface to the GD::Graph::lines +class defined by the GD::Graph module. It allows one or more (x,y) data +sets to be plotted as y versus x lines with axes and legends. + +See L<GD::Graph> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/lines3d.pm b/lib/Template/Plugin/GD/Graph/lines3d.pm new file mode 100644 index 0000000..1f12715 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/lines3d.pm @@ -0,0 +1,166 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::lines3d +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::lines3d +# package in the GD::Graph3D.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: lines3d.pm,v 1.57 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::lines3d; + +require 5.004; + +use strict; +use GD::Graph::lines3d; +use Template::Plugin; +use base qw( GD::Graph::lines3d Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::lines3d - Create 3D line graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.lines3d(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + data = [ + ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec", ], + [-5, -4, -3, -3, -1, 0, 2, 1, 3, 4, 6, 7], + [4, 3, 5, 6, 3,1.5, -1, -3, -4, -6, -7, -8], + [1, 2, 2, 3, 4, 3, 1, -1, 0, 2, 3, 2], + ]; + + USE my_graph = GD.Graph.lines3d(); + + my_graph.set( + x_label => 'Month', + y_label => 'Measure of success', + title => 'A 3d Line Graph', + + y_max_value => 8, + y_min_value => -8, + y_tick_number => 16, + y_label_skip => 2, + box_axis => 0, + line_width => 3, + zero_axis_only => 1, + x_label_position => 1, + y_label_position => 1, + + x_label_skip => 3, + x_tick_offset => 2, + + transparent => 0, + ); + my_graph.set_legend("Us", "Them", "Others"); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.lines3d plugin provides an interface to the GD::Graph::lines3d +class defined by the GD::Graph3d module. It allows one or more (x,y) data +sets to be plotted as y versus x lines with a 3-dimensional appearance, +together with axes and legends. + +See L<GD::Graph3d> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph3d module was written by Jeremy Wadsack. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph3d is copyright (C) 1999,2000 Wadsack-Allen. All Rights Reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph>, L<GD::Graph3d|GD::Graph3d> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/linespoints.pm b/lib/Template/Plugin/GD/Graph/linespoints.pm new file mode 100644 index 0000000..8dc48d9 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/linespoints.pm @@ -0,0 +1,158 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::linespoints +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::linespoints +# package in the GD::Graph.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: linespoints.pm,v 1.57 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::linespoints; + +require 5.004; + +use strict; +use GD::Graph::linespoints; +use Template::Plugin; +use base qw( GD::Graph::linespoints Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::linespoints - Create line/point graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.linespoints(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + data = [ + ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"], + [50, 52, 53, 54, 55, 56, 57, 58, 59], + [60, 61, 61, 63, 68, 66, 65, 61, 58], + [70, 72, 71, 74, 78, 73, 75, 71, 68], + ]; + + USE my_graph = GD.Graph.linespoints; + + my_graph.set( + x_label => 'X Label', + y_label => 'Y label', + title => 'A Lines and Points Graph', + y_max_value => 80, + y_tick_number => 6, + y_label_skip => 2, + y_long_ticks => 1, + x_tick_length => 2, + markers => [ 1, 5 ], + skip_undef => 1, + transparent => 0, + ); + my_graph.set_legend('data set 1', 'data set 2', 'data set 3'); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.linespoints plugin provides an interface to the +GD::Graph::linespoints class defined by the GD::Graph module. It allows +one or more (x,y) data sets to be plotted as y versus x lines, plus +symbols placed at each point, in addition to axes and legends. + +See L<GD::Graph> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/mixed.pm b/lib/Template/Plugin/GD/Graph/mixed.pm new file mode 100644 index 0000000..10dd533 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/mixed.pm @@ -0,0 +1,176 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::mixed +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::mixed +# package in the GD::Graph.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: mixed.pm,v 1.57 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::mixed; + +require 5.004; + +use strict; +use GD::Graph::mixed; +use Template::Plugin; +use base qw( GD::Graph::mixed Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::mixed - Create mixed graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.mixed(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + data = [ + ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"], + [ 1, 2, 5, 6, 3, 1.5, -1, -3, -4], + [ -4, -3, 1, 1, -3, -1.5, -2, -1, 0], + [ 9, 8, 9, 8.4, 7.1, 7.5, 8, 3, -3], + [ 0.1, 0.2, 0.5, 0.4, 0.3, 0.5, 0.1, 0, 0.4], + [ -0.1, 2, 5, 4, -3, 2.5, 3.2, 4, -4], + ]; + + USE my_graph = GD.Graph.mixed(); + + my_graph.set( + types => ['lines', 'lines', 'points', 'area', 'linespoints'], + default_type => 'points', + ); + + my_graph.set( + + x_label => 'X Label', + y_label => 'Y label', + title => 'A Mixed Type Graph', + + y_max_value => 10, + y_min_value => -5, + y_tick_number => 3, + y_label_skip => 0, + x_plot_values => 0, + y_plot_values => 0, + + long_ticks => 1, + x_ticks => 0, + + legend_marker_width => 24, + line_width => 3, + marker_size => 5, + + bar_spacing => 8, + + transparent => 0, + ); + + my_graph.set_legend('one', 'two', 'three', 'four', 'five', 'six'); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.mixed plugin provides an interface to the GD::Graph::mixed +class defined by the GD::Graph module. It allows one or more (x,y) data +sets to be plotted with various styles (lines, points, bars, areas etc). + +See L<GD::Graph> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/pie.pm b/lib/Template/Plugin/GD/Graph/pie.pm new file mode 100644 index 0000000..e72e26c --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/pie.pm @@ -0,0 +1,141 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::pie +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::pie +# package in the GD::Graph.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: pie.pm,v 1.55 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::pie; + +require 5.004; + +use strict; +use GD::Graph::pie; +use Template::Plugin; +use base qw( GD::Graph::pie Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + +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::GD::Graph::pie - Create pie charts with legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.pie(x_size, y_size); %] + +=head1 EXAMPLES + + [% 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; + -%] + +=head1 DESCRIPTION + +The GD.Graph.pie plugin provides an interface to the GD::Graph::pie +class defined by the GD::Graph module. It allows an (x,y) data set to +be plotted as a pie chart. The x values are typically strings. + +See L<GD::Graph> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/pie3d.pm b/lib/Template/Plugin/GD/Graph/pie3d.pm new file mode 100644 index 0000000..5f677e0 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/pie3d.pm @@ -0,0 +1,145 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::pie3d +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::pie3d +# package in the GD::Graph3D.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: pie3d.pm,v 1.55 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::pie3d; + +require 5.004; + +use strict; +use GD::Graph::pie3d; +use Template::Plugin; +use base qw( GD::Graph::pie3d Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + +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::GD::Graph::pie3d - Create 3D pie charts with legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.pie3d(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + data = [ + ["1st","2nd","3rd","4th","5th","6th"], + [ 4, 2, 3, 4, 3, 3.5] + ]; + + USE my_graph = GD.Graph.pie3d( 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; + -%] + +=head1 DESCRIPTION + +The GD.Graph.pie3d plugin provides an interface to the GD::Graph::pie3d +class defined by the GD::Graph module. It allows an (x,y) data set to +be plotted as a 3d pie chart. The x values are typically strings. + +Note that GD::Graph::pie already produces a 3d effect, so GD::Graph::pie3d +is just a wrapper around GD::Graph::pie. Similarly, the plugin +GD.Graph.pie3d is effectively the same as the plugin GD.Graph.pie. + +See L<GD::Graph3d> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph3d module was written by Jeremy Wadsack. The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph3d is copyright (c) 1999,2000 Wadsack-Allen. All Rights Reserved. GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::points|Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<GD::Graph|GD::Graph>, L<GD::Graph3d|GD::Graph3d> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Graph/points.pm b/lib/Template/Plugin/GD/Graph/points.pm new file mode 100644 index 0000000..97acf51 --- /dev/null +++ b/lib/Template/Plugin/GD/Graph/points.pm @@ -0,0 +1,155 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Graph::points +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Graph::points +# package in the GD::Graph.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: points.pm,v 1.57 2004/01/13 16:20:56 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Graph::points; + +require 5.004; + +use strict; +use GD::Graph::points; +use Template::Plugin; +use base qw( GD::Graph::points Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.57 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return $class->SUPER::new(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + + +sub set_legend +{ + my $self = shift; + + $self->SUPER::set_legend(ref $_[0] ? @{$_[0]} : @_); +} + +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::GD::Graph::points - Create point graphs with axes and legends + +=head1 SYNOPSIS + + [% USE g = GD.Graph.points(x_size, y_size); %] + +=head1 EXAMPLES + + [% FILTER null; + data = [ + ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"], + [ 5, 12, 24, 33, 19, 8, 6, 15, 21], + [ 1, 2, 5, 6, 3, 1.5, 2, 3, 4], + ]; + USE my_graph = GD.Graph.points(); + my_graph.set( + x_label => 'X Label', + y_label => 'Y label', + title => 'A Points Graph', + y_max_value => 40, + y_tick_number => 8, + y_label_skip => 2, + legend_placement => 'RC', + long_ticks => 1, + marker_size => 6, + markers => [ 1, 7, 5 ], + + transparent => 0, + ); + my_graph.set_legend('one', 'two'); + my_graph.plot(data).png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Graph.points plugin provides an interface to the GD::Graph::points +class defined by the GD::Graph module. It allows one or more (x,y) data +sets to be plotted as points, in addition to axes and legends. + +See L<GD::Graph> for more details. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Graph module was written by Martien Verbruggen. + + +=head1 VERSION + +1.57, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Graph is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Graph::lines|Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::lines3d|Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars|Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::bars3d|Template::Plugin::GD::Graph::bars3d>, L<Template::Plugin::GD::Graph::linespoints|Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area|Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed|Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie|Template::Plugin::GD::Graph::pie>, L<Template::Plugin::GD::Graph::pie3d|Template::Plugin::GD::Graph::pie3d>, L<GD::Graph|GD::Graph> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Image.pm b/lib/Template/Plugin/GD/Image.pm new file mode 100644 index 0000000..46a06d7 --- /dev/null +++ b/lib/Template/Plugin/GD/Image.pm @@ -0,0 +1,184 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Image +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Image +# class in the GD.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Image.pm,v 1.55 2004/01/13 16:20:46 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Image; + +require 5.004; + +use strict; +use GD; +use Template::Plugin; +use base qw( GD Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return new GD::Image(@_); +} + +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::GD::Image - Interface to GD Graphics Library + +=head1 SYNOPSIS + + [% USE im = GD.Image(x_size, y_size) %] + +=head1 EXAMPLES + + [% FILTER null; + USE gdc = GD.Constants; + USE im = GD.Image(200,100); + black = im.colorAllocate(0 ,0, 0); + red = im.colorAllocate(255,0, 0); + r = im.string(gdc.gdLargeFont, 10, 10, "Large Red Text", red); + im.png | stdout(1); + END; + -%] + + [% 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 binary image in PNG format + im.png | stdout(1); + END; + -%] + + [% FILTER null; + USE im = GD.Image(100,100); + USE c = GD.Constants; + USE poly = GD.Polygon; + + # allocate some colors + white = im.colorAllocate(255,255,255); + black = im.colorAllocate(0, 0, 0); + red = im.colorAllocate(255,0, 0); + blue = im.colorAllocate(0, 0,255); + green = im.colorAllocate(0, 255,0); + + # make the background transparent and interlaced + im.transparent(white); + im.interlaced('true'); + + # Put a black frame around the picture + im.rectangle(0,0,99,99,black); + + # Draw a blue oval + im.arc(50,50,95,75,0,360,blue); + + # And fill it with red + im.fill(50,50,red); + + # Draw a blue triangle + poly.addPt(50,0); + poly.addPt(99,99); + poly.addPt(0,99); + im.filledPolygon(poly, blue); + + # Output binary image in PNG format + im.png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Image plugin provides an interface to GD.pm's GD::Image class. +The GD::Image class is the main interface to GD.pm. + +It is very important that no extraneous template output appear before or +after the image. Since some methods return values that would otherwise +appear in the output, it is recommended that GD.Image code be wrapped in +a null filter. The methods that produce the final output (eg, png, jpeg, +gd etc) can then explicitly make their output appear by using the +stdout filter, with a non-zero argument to force binary mode (required +for non-modern operating systems). + +See L<GD> for a complete description of the GD library and all the +methods that can be called via the GD.Image plugin. +See L<Template::Plugin::GD::Constants> for a plugin that allows you +access to GD.pm's constants. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +Lincoln D. Stein wrote the GD.pm interface to the GD library. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +The GD.pm interface is copyright 1995-2000, Lincoln D. Stein. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Polygon|Template::Plugin::GD::Polygon>, L<Template::Plugin::GD::Constants|Template::Plugin::GD::Constants>, L<GD|GD> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Polygon.pm b/lib/Template/Plugin/GD/Polygon.pm new file mode 100644 index 0000000..0d1d5c6 --- /dev/null +++ b/lib/Template/Plugin/GD/Polygon.pm @@ -0,0 +1,155 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Polygon +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Polygon +# class in the GD.pm module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Polygon.pm,v 1.55 2004/01/13 16:20:46 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Polygon; + +require 5.004; + +use strict; +use GD; +use Template::Plugin; +use base qw( Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + return new GD::Polygon(@_); +} + +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::GD::Polygon - Interface to GD module Polygon class + +=head1 SYNOPSIS + + [% USE poly = GD.Polygon; + poly.addPt(50,0); + poly.addPt(99,99); + %] + +=head1 EXAMPLES + + [% FILTER null; + USE im = GD.Image(100,100); + USE c = GD.Constants; + + # allocate some colors + white = im.colorAllocate(255,255,255); + black = im.colorAllocate(0, 0, 0); + red = im.colorAllocate(255,0, 0); + blue = im.colorAllocate(0, 0,255); + green = im.colorAllocate(0, 255,0); + + # make the background transparent and interlaced + im.transparent(white); + im.interlaced('true'); + + # Put a black frame around the picture + im.rectangle(0,0,99,99,black); + + # Draw a blue oval + im.arc(50,50,95,75,0,360,blue); + + # And fill it with red + im.fill(50,50,red); + + # Draw a blue triangle by defining a polygon + USE poly = GD.Polygon; + poly.addPt(50,0); + poly.addPt(99,99); + poly.addPt(0,99); + im.filledPolygon(poly, blue); + + # Output binary image in PNG format + im.png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Polygon plugin provides an interface to GD.pm's GD::Polygon class. + +See L<GD> for a complete description of the GD library and all the +methods that can be called via the GD.Polygon plugin. +See L<Template::Plugin::GD::Image> for the main interface to the +GD functions. +See L<Template::Plugin::GD::Constants> for a plugin that allows you +access to GD.pm's constants. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +Lincoln D. Stein wrote the GD.pm interface to the GD library. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +The GD.pm interface is copyright 1995-2000, Lincoln D. Stein. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Image|Template::Plugin::GD::Image>, L<Template::Plugin::GD::Constants|Template::Plugin::GD::Constants>, L<GD|GD> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Text.pm b/lib/Template/Plugin/GD/Text.pm new file mode 100644 index 0000000..f18b2e0 --- /dev/null +++ b/lib/Template/Plugin/GD/Text.pm @@ -0,0 +1,140 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Text +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Text +# module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Text.pm,v 1.55 2004/01/13 16:20:46 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Text; + +require 5.004; + +use strict; +use GD::Text; +use Template::Plugin; +use base qw( GD::Text Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + return new GD::Text(@_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + +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::GD::Text - Text utilities for use with GD + +=head1 SYNOPSIS + + [% USE gd_text = GD.Text %] + +=head1 EXAMPLES + + [% + USE gd_c = GD.Constants; + USE t = GD.Text; + x = t.set_text('Some text'); + r = t.get('width', 'height', 'char_up', 'char_down'); + r.join(":"); "\n"; # returns 54:13:13:0. + -%] + + [% + USE gd_c = GD.Constants; + USE t = GD.Text(text => 'FooBar Banana', font => gd_c.gdGiantFont); + t.get('width'); "\n"; # returns 117. + -%] + +=head1 DESCRIPTION + +The GD.Text plugin provides an interface to the GD::Text module. +It allows attributes of strings such as width and height in pixels +to be computed. + +See L<GD::Text> for more details. See +L<Template::Plugin::GD::Text::Align> and +L<Template::Plugin::GD::Text::Wrap> for plugins that +allow you to render aligned or wrapped text in GD images. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Text module was written by Martien Verbruggen. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Text is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Text::Wrap|Template::Plugin::GD::Text::Wrap>, L<Template::Plugin::GD::Text::Align|Template::Plugin::GD::Text::Align>, L<GD|GD>, L<GD::Text|GD::Text> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Text/Align.pm b/lib/Template/Plugin/GD/Text/Align.pm new file mode 100644 index 0000000..8b79069 --- /dev/null +++ b/lib/Template/Plugin/GD/Text/Align.pm @@ -0,0 +1,147 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Text::Align +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Text::Align +# module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Align.pm,v 1.55 2004/01/13 16:21:46 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Text::Align; + +require 5.004; + +use strict; +use GD::Text::Align; +use Template::Plugin; +use base qw( GD::Text::Align Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + my $gd = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + return $class->SUPER::new($gd, @_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + +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::GD::Text::Align - Draw aligned strings in GD images + +=head1 SYNOPSIS + + [% USE align = GD.Text.Align(gd_image); %] + +=head1 EXAMPLES + + [% FILTER null; + USE im = GD.Image(100,100); + USE gdc = GD.Constants; + # 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); + + USE a = GD.Text.Align(im); + a.set_font(gdc.gdLargeFont); + a.set_text("Hello"); + a.set(colour => red, halign => "center"); + a.draw(50,70,0); + + # Output image in PNG format + im.png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Text.Align plugin provides an interface to the GD::Text::Align +module. It allows text to be drawn in GD images with various alignments +and orientations. + +See L<GD::Text::Align> for more details. See +L<Template::Plugin::GD::Text::Wrap> for a plugin +that allow you to render wrapped text in GD images. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Text module was written by Martien Verbruggen. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Text is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Text|Template::Plugin::GD::Text>, L<Template::Plugin::GD::Text::Wrap|Template::Plugin::GD::Text::Wrap>, L<GD|GD>, L<GD::Text::Align|GD::Text::Align> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/GD/Text/Wrap.pm b/lib/Template/Plugin/GD/Text/Wrap.pm new file mode 100644 index 0000000..0438599 --- /dev/null +++ b/lib/Template/Plugin/GD/Text/Wrap.pm @@ -0,0 +1,183 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::GD::Text::Wrap +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the GD::Text::Wrap +# module. +# +# AUTHOR +# Craig Barratt <craig@arraycomm.com> +# +# COPYRIGHT +# Copyright (C) 2001 Craig Barratt. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Wrap.pm,v 1.55 2004/01/13 16:21:46 abw Exp $ +# +#============================================================================ + +package Template::Plugin::GD::Text::Wrap; + +require 5.004; + +use strict; +use GD::Text::Wrap; +use Template::Plugin; +use base qw( GD::Text::Wrap Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.55 $ =~ /(\d+)\.(\d+)/); + +sub new +{ + my $class = shift; + my $context = shift; + my $gd = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + return $class->SUPER::new($gd, @_); +} + +sub set +{ + my $self = shift; + + push(@_, %{pop(@_)}) if ( @_ & 1 && ref($_[@_-1]) eq "HASH" ); + $self->SUPER::set(@_); +} + +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::GD::Text::Wrap - Break and wrap strings in GD images + +=head1 SYNOPSIS + + [% USE align = GD.Text.Wrap(gd_image); %] + +=head1 EXAMPLES + + [% 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; + -%] + + [% txt = BLOCK -%] + Lorem ipsum dolor sit amet, consectetuer adipiscing elit, + sed diam nonummy nibh euismod tincidunt ut laoreet dolore + magna aliquam erat volutpat. + [% END -%] + [% FILTER null; + # + # This example follows the example in GD::Text::Wrap, except + # we create a second image that is a copy just enough of the + # first image to hold the final text, plus a border. + # + USE gd = GD.Image(400,400); + USE gdc = GD.Constants; + green = gd.colorAllocate(0, 255, 0); + blue = gd.colorAllocate(0, 0, 255); + USE wrapbox = GD.Text.Wrap(gd, + line_space => 4, + color => green, + text => txt, + ); + wrapbox.set_font(gdc.gdMediumBoldFont); + wrapbox.set(align => 'center', width => 140); + rect = wrapbox.get_bounds(5, 5); + x0 = rect.0; + y0 = rect.1; + x1 = rect.2 + 9; + y1 = rect.3 + 9; + gd.filledRectangle(0, 0, x1, y1, blue); + gd.rectangle(0, 0, x1, y1, green); + wrapbox.draw(x0, y0); + nx = x1 + 1; + ny = y1 + 1; + USE gd2 = GD.Image(nx, ny); + gd2.copy(gd, 0, 0, 0, 0, x1, y1); + gd2.png | stdout(1); + END; + -%] + +=head1 DESCRIPTION + +The GD.Text.Wrap plugin provides an interface to the GD::Text::Wrap +module. It allows multiples line of text to be drawn in GD images with +various wrapping and alignment. + +See L<GD::Text::Wrap> for more details. See +L<Template::Plugin::GD::Text::Align> for a plugin +that allow you to draw text with various alignment +and orientation. + +=head1 AUTHOR + +Craig Barratt E<lt>craig@arraycomm.comE<gt> + + +The GD::Text module was written by Martien Verbruggen. + + +=head1 VERSION + +1.55, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2001 Craig Barratt E<lt>craig@arraycomm.comE<gt> + +GD::Text is copyright 1999 Martien Verbruggen. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<Template::Plugin::GD|Template::Plugin::GD>, L<Template::Plugin::GD::Text::Align|Template::Plugin::GD::Text::Align>, L<GD|GD>, L<GD::Text::Wrap|GD::Text::Wrap> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/HTML.pm b/lib/Template/Plugin/HTML.pm new file mode 100644 index 0000000..5cb63e0 --- /dev/null +++ b/lib/Template/Plugin/HTML.pm @@ -0,0 +1,197 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::HTML +# +# DESCRIPTION +# +# Template Toolkit plugin providing useful functionality for generating +# HTML. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# 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. +# +#---------------------------------------------------------------------------- +# +# $Id: HTML.pm,v 2.56 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::HTML; + +require 5.004; + +use strict; +use vars qw( $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.56 $ =~ /(\d+)\.(\d+)/); + +sub new { + my ($class, $context, @args) = @_; + my $hash = ref $args[-1] eq 'HASH' ? pop @args : { }; + bless { + _SORTED => $hash->{ sorted } || 0, + }, $class; +} + +sub element { + my ($self, $name, $attr) = @_; + ($name, $attr) = %$name if ref $name eq 'HASH'; + return '' unless defined $name and length $name; + $attr = $self->attributes($attr); + $attr = " $attr" if $attr; + return "<$name$attr>"; +} + +sub attributes { + my ($self, $hash) = @_; + return '' unless UNIVERSAL::isa($hash, 'HASH'); + + my @keys = keys %$hash; + @keys = sort @keys if $self->{ _SORTED }; + + join(' ', map { + "$_=\"" . $self->escape( $hash->{ $_ } ) . '"'; + } @keys); +} + +sub escape { + my ($self, $text) = @_; + for ($text) { + s/&/&/g; + s/</</g; + s/>/>/g; + s/"/"/g; + } + $text; +} + +sub url { + my ($self, $text) = @_; + return undef unless defined $text; + $text =~ s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg; + return $text; +} + + +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::HTML - Plugin to create HTML elements + +=head1 SYNOPSIS + + [% USE HTML %] + + [% HTML.escape("if (a < b && c > d) ..." %] + + [% HTML.element(table => { border => 1, cellpadding => 2 }) %] + + [% HTML.attributes(border => 1, cellpadding => 2) %] + +=head1 DESCRIPTION + +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). + +=head1 METHODS + +=head2 escape(text) + +Returns the source text with any HTML reserved characters such as +E<lt>, E<gt>, etc., correctly esacped to their entity equivalents. + +=head2 attributes(hash) + +Returns the elements of the hash array passed by reference correctly +formatted (e.g. values quoted and correctly escaped) as attributes for +an HTML element. + +=head2 element(type, attributes) + +Generates an HTML element of the specified type and with the attributes +provided as an optional hash array reference as the second argument or +as named arguments. + + [% HTML.element(table => { border => 1, cellpadding => 2 }) %] + [% HTML.element('table', border=1, cellpadding=2) %] + [% HTML.element(table => attribs) %] + +=head1 DEBUGGING + +The HTML plugin accepts a 'sorted' option as a constructor argument +which, when set to any true value, causes the attributes generated by +the attributes() method (either directly or via element()) to be +returned in sorted order. Order of attributes isn't important in +HTML, but this is provided mainly for the purposes of debugging where +it is useful to have attributes generated in a deterministic order +rather than whatever order the hash happened to feel like returning +the keys in. + + [% USE HTML(sorted=1) %] + [% HTML.element( foo => { charlie => 1, bravo => 2, alpha => 3 } ) %] + +generates: + + <foo alpha="3" bravo="2" charlie="1"> + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.56, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Image.pm b/lib/Template/Plugin/Image.pm new file mode 100644 index 0000000..4eb509c --- /dev/null +++ b/lib/Template/Plugin/Image.pm @@ -0,0 +1,425 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Image +# +# DESCRIPTION +# Plugin for encapsulating information about an image. +# +# AUTHOR +# Andy Wardley <abw@wardley.org> +# +# COPYRIGHT +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: Image.pm,v 1.13 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Image; + +require 5.004; + +use strict; +use Template::Exception; +use Template::Plugin; +use File::Spec; +#use Image::Info; +#use Image::Size; + +use base qw( Template::Plugin ); +use vars qw( $VERSION $AUTOLOAD ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.13 $ =~ /(\d+)\.(\d+)/); + +BEGIN { + if (eval { require Image::Info; }) { + *img_info = \&Image::Info::image_info; + } + elsif (eval { require Image::Size; }) { + *img_info = sub { + my $file = shift; + my @stuff = Image::Size::imgsize($file); + return { "width" => $stuff[0], + "height" => $stuff[1], + "error" => + # imgsize returns either a three letter file type + # or an error message as third value + (defined($stuff[2]) && length($stuff[2]) > 3 + ? $stuff[2] + : undef), + }; + } + } + else { + die(Template::Exception->new("image", + "Couldn't load Image::Info or Image::Size: $@")); + } + +} + +#------------------------------------------------------------------------ +# new($context, $name, \%config) +# +# Create a new Image object. Takes the pathname of the file as +# the argument following the context and an optional +# hash reference of configuration parameters. +#------------------------------------------------------------------------ + +sub new { + my $config = ref($_[-1]) eq 'HASH' ? pop(@_) : { }; + my ($class, $context, $name) = @_; + my ($root, $file, $type); + + # name can be a positional or named argument + $name = $config->{ name } unless defined $name; + + return $class->throw('no image file specified') + unless defined $name and length $name; + + # name can be specified as an absolute path or relative + # to a root directory + + if ($root = $config->{ root }) { + $file = File::Spec->catfile($root, $name); + } + else { + $file = $name; + } + + # Make a note of whether we are using Image::Size or + # Image::Info -- at least for the test suite + $type = $INC{"Image/Size.pm"} ? "Image::Size" : "Image::Info"; + + # do we want to check to see if file exists? + + bless { + name => $name, + file => $file, + root => $root, + type => $type, + }, $class; +} + +#------------------------------------------------------------------------ +# init() +# +# Calls image_info on $self->{ file } +#------------------------------------------------------------------------ + +sub init { + my $self = shift; + return $self if $self->{ size }; + + my $image = img_info($self->{ file }); + return $self->throw($image->{ error }) if defined $image->{ error }; + + @$self{ keys %$image } = values %$image; + $self->{ size } = [ $image->{ width }, $image->{ height } ]; + + $self->{ modtime } = (stat $self->{ file })[10]; + + return $self; +} + +#------------------------------------------------------------------------ +# attr() +# +# Return the width and height as HTML/XML attributes. +#------------------------------------------------------------------------ + +sub attr { + my $self = shift; + my $size = $self->size(); + return "width=\"$size->[0]\" height=\"$size->[1]\""; +} + +#------------------------------------------------------------------------ +# modtime() +# +# Return last modification time as a time_t: +# +# [% date.format(image.modtime, "%Y/%m/%d") %] +#------------------------------------------------------------------------ + +sub modtime { + my $self = shift; + $self->init; + return $self->{ modtime }; +} + +#------------------------------------------------------------------------ +# tag(\%options) +# +# Return an XHTML img tag. +#------------------------------------------------------------------------ + +sub tag { + my $self = shift; + my $options = ref $_[0] eq 'HASH' ? shift : { @_ }; + + my $tag = "<img src=\"$self->{ name }\" " . $self->attr(); + + if (%$options) { + while (my ($key, $val) = each %$options) { + $tag .= " $key=\"$val\""; + } + } + + $tag .= ' />'; + + return $tag; +} + + +sub throw { + my ($self, $error) = @_; + die (Template::Exception->new('Image', $error)); +} + +sub AUTOLOAD { + my $self = shift; + (my $a = $AUTOLOAD) =~ s/.*:://; + + $self->init; + return $self->{ $a }; +} + +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::Image - Plugin access to image sizes + +=head1 SYNOPSIS + + [% USE Image(filename) %] + [% Image.width %] + [% Image.height %] + [% Image.size.join(', ') %] + [% Image.attr %] + [% Image.tag %] + +=head1 DESCRIPTION + +This plugin provides an interface to the Image::Info or Image::Size +modules for determining the size of image files. + +You can specify the plugin name as either 'Image' or 'image'. The +plugin object created will then have the same name. The file name of +the image should be specified as a positional or named argument. + + [% # all these are valid, take your pick %] + [% USE Image('foo.gif') %] + [% USE image('bar.gif') %] + [% USE Image 'ping.gif' %] + [% USE image(name='baz.gif') %] + [% USE Image name='pong.gif' %] + +You can also provide an alternate name for an Image plugin object. + + [% USE img1 = image 'foo.gif' %] + [% USE img2 = image 'bar.gif' %] + +The 'width' and 'height' methods return the width and height of the +image, respectively. The 'size' method returns a reference to a 2 +element list containing the width and height. + + [% USE image 'foo.gif' %] + width: [% image.width %] + height: [% image.height %] + size: [% image.size.join(', ') %] + +The 'attr' method returns the height and width as HTML/XML attributes. + + [% USE image 'foo.gif' %] + [% image.attr %] + +Typical output: + + width="60" height="20" + +The 'tag' method returns a complete XHTML tag referencing the image. + + [% USE image 'foo.gif' %] + [% image.tag %] + +Typical output: + + <img src="foo.gif" width="60" height="20" /> + +You can provide any additional attributes that should be added to the +XHTML tag. + + + [% USE image 'foo.gif' %] + [% image.tag(border=0, class="logo") %] + +Typical output: + + <img src="foo.gif" width="60" height="20" border="0" class="logo" /> + +The 'modtime' method returns the ctime of the file in question, suitable +for use with date.format: + + [% USE image 'foo.gif' %] + [% USE date %] + [% date.format(image.modtime, "%B, %e %Y") %] + +=head1 CATCHING ERRORS + +If the image file cannot be found then the above methods will throw an +'Image' error. You can enclose calls to these methods in a +TRY...CATCH block to catch any potential errors. + + [% TRY; + image.width; + CATCH; + error; # print error + END + %] + +=head1 USING Image::Info + +At run time, the plugin tries to load Image::Info in preference to +Image::Size. If Image::Info is found, then some additional methods are +available, in addition to 'size', 'width', 'height', 'attr', and 'tag'. +These additional methods are named after the elements that Image::Info +retrieves from the image itself; see L<Image::Info> for more details +-- the types of methods available depend on the type of image. +These additional methods will always include the following: + +=over 4 + +=item file_media_type + +This is the MIME type that is appropriate for the given file format. +The corresponding value is a string like: "image/png" or "image/jpeg". + +=item file_ext + +The is the suggested file name extention for a file of the given +file format. The value is a 3 letter, lowercase string like +"png", "jpg". + + +=item color_type + +The value is a short string describing what kind of values the pixels +encode. The value can be one of the following: + + Gray + GrayA + RGB + RGBA + CMYK + YCbCr + CIELab + +These names can also be prefixed by "Indexed-" if the image is +composed of indexes into a palette. Of these, only "Indexed-RGB" is +likely to occur. + +(It is similar to the TIFF field PhotometricInterpretation, but this +name was found to be too long, so we used the PNG inpired term +instead.) + +=item resolution + +The value of this field normally gives the physical size of the image +on screen or paper. When the unit specifier is missing then this field +denotes the squareness of pixels in the image. + +The syntax of this field is: + + <res> <unit> + <xres> "/" <yres> <unit> + <xres> "/" <yres> + +The E<lt>resE<gt>, E<lt>xresE<gt> and E<lt>yresE<gt> fields are +numbers. The E<lt>unitE<gt> is a string like C<dpi>, C<dpm> or +C<dpcm> (denoting "dots per inch/cm/meter). + +=item SamplesPerPixel + +This says how many channels there are in the image. For some image +formats this number might be higher than the number implied from the +C<color_type>. + +=item BitsPerSample + +This says how many bits are used to encode each of samples. The value +is a reference to an array containing numbers. The number of elements +in the array should be the same as C<SamplesPerPixel>. + +=item Comment + +Textual comments found in the file. The value is a reference to an +array if there are multiple comments found. + +=item Interlace + +If the image is interlaced, then this tell which interlace method is +used. + +=item Compression + +This tell which compression algorithm is used. + +=item Gamma + +A number. + + +=back + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +1.13, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Iterator.pm b/lib/Template/Plugin/Iterator.pm new file mode 100644 index 0000000..0f33b2f --- /dev/null +++ b/lib/Template/Plugin/Iterator.pm @@ -0,0 +1,118 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Iterator +# +# DESCRIPTION +# +# Plugin to create a Template::Iterator from a list of items and optional +# configuration parameters. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Iterator.pm,v 2.62 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Iterator; + +require 5.004; + +use strict; +use vars qw( $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; +use Template::Iterator; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.62 $ =~ /(\d+)\.(\d+)/); + +#------------------------------------------------------------------------ +# new($context, \@data, \%args) +#------------------------------------------------------------------------ + +sub new { + my $class = shift; + my $context = shift; + Template::Iterator->new(@_); +} + +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::Iterator - Plugin to create iterators (Template::Iterator) + +=head1 SYNOPSIS + + [% USE iterator(list, args) %] + + [% FOREACH item = iterator %] + [% '<ul>' IF iterator.first %] + <li>[% item %] + [% '</ul>' IF iterator.last %] + [% END %] + +=head1 DESCRIPTION + +The iterator plugin provides a way to create a Template::Iterator object +to iterate over a data set. An iterator is implicitly automatically by the +FOREACH directive. This plugin allows the iterator to be explicitly created +with a given name. + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.62, 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<Template::Plugin|Template::Plugin>, L<Template::Iterator|Template::Iterator> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Pod.pm b/lib/Template/Plugin/Pod.pm new file mode 100644 index 0000000..e5f82c2 --- /dev/null +++ b/lib/Template/Plugin/Pod.pm @@ -0,0 +1,116 @@ +#============================================================================== +# +# Template::Plugin::Pod +# +# DESCRIPTION +# Pod parser and object model. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: Pod.pm,v 2.62 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Pod; + +require 5.004; + +use strict; +use Template::Plugin; +use vars qw( $VERSION ); +use base qw( Template::Plugin ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.62 $ =~ /(\d+)\.(\d+)/); + +use Pod::POM; + +#------------------------------------------------------------------------ +# new($context, \%config) +#------------------------------------------------------------------------ + +sub new { + my $class = shift; + my $context = shift; + + Pod::POM->new(@_); +} + + +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::Pod - Plugin interface to Pod::POM (Pod Object Model) + +=head1 SYNOPSIS + + [% USE Pod(podfile) %] + + [% FOREACH head1 = Pod.head1; + FOREACH head2 = head1/head2; + ... + END; + END + %] + +=head1 DESCRIPTION + +This plugin is an interface to the Pod::POM module. + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.62, 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<Template::Plugin|Template::Plugin>, L<Pod::POM|Pod::POM> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Procedural.pm b/lib/Template/Plugin/Procedural.pm new file mode 100644 index 0000000..8601225 --- /dev/null +++ b/lib/Template/Plugin/Procedural.pm @@ -0,0 +1,170 @@ +#============================================================================== +# +# Template::Plugin::Procedural +# +# DESCRIPTION +# +# A Template Plugin to provide a Template Interface to Data::Dumper +# +# AUTHOR +# Mark Fowler <mark@twoshortplanks.com> +# +# COPYRIGHT +# +# Copyright (C) 2002 Mark Fowler. All Rights Reserved +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#------------------------------------------------------------------------------ +# +# $Id: Procedural.pm,v 1.11 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================== + +package Template::Plugin::Procedural; + +require 5.004; + +use strict; + +use vars qw( $VERSION $DEBUG $AUTOLOAD ); +use base qw( Template::Plugin ); + +$VERSION = sprintf("%d.%02d", q$Revision: 1.11 $ =~ /(\d+)\.(\d+)/); +$DEBUG = 0 unless defined $DEBUG; + +#------------------------------------------------------------------------ +# load +#------------------------------------------------------------------------ + +sub load +{ + my ($class, $context) = @_; + + # create a proxy namespace that will be used for objects + my $proxy = "Template::Plugin::" . $class; + + # okay, in our proxy create the autoload routine that will + # call the right method in the real class + no strict "refs"; + *{ $proxy . "::AUTOLOAD" } = + sub + { + # work out what the method is called + $AUTOLOAD =~ s!^.*::!!; + + print STDERR "Calling '$AUTOLOAD' in '$class'\n" + if $DEBUG; + + # look up the sub for that method (but in a OO way) + my $uboat = $class->can($AUTOLOAD); + + # if it existed call it as a subroutine, not as a method + if ($uboat) + { + shift @_; + return $uboat->(@_); + } + + print STDERR "Eeek, no such method '$AUTOLOAD'\n" + if $DEBUG; + + return ""; + }; + + # create a simple new method that simply returns a blessed + # scalar as the object. + *{ $proxy . "::new" } = + sub + { + my $this; + return bless \$this, $_[0]; + }; + + return $proxy; +} + +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::Procedural - Base class for procedural plugins + +=head1 SYNOPSIS + + package Template::Plugin::LWPSimple; + use base qw(Template::Plugin::Procedural); + use LWP::Simple; # exports 'get' + 1; + + [% USE LWPSimple %] + [% LWPSimple.get("http://www.tt2.org/") %] + +=head1 DESCRIPTION + +B<Template::Plugin::Procedural> is a base class for Template Toolkit +plugins that causes defined subroutines to be called directly rather +than as a method. Essentially this means that subroutines will not +receive the class name or object as its first argument. + +This is most useful when creating plugins for modules that normally +work by exporting subroutines that do not expect such additional +arguments. + +Despite the fact that subroutines will not be called in an OO manner, +inheritance still function as normal. A class that uses +B<Template::Plugin::Procedural> can be subclassed and both subroutines +defined in the subclass and subroutines defined in the original class +will be available to the Template Toolkit and will be called without +the class/object argument. + +=head1 AUTHOR + +Mark Fowler E<lt>mark@twoshortplanks.comE<gt> + +L<http://www.twoshortplanks.com|http://www.twoshortplanks.com> + + + + +=head1 VERSION + +1.11, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + +=head1 COPYRIGHT + + +Copyright (C) 2002 Mark Fowler E<lt>mark@twoshortplanks.comE<gt> + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template|Template>, L<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/String.pm b/lib/Template/Plugin/String.pm new file mode 100644 index 0000000..34dd007 --- /dev/null +++ b/lib/Template/Plugin/String.pm @@ -0,0 +1,796 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::String +# +# DESCRIPTION +# Template Toolkit plugin to implement a basic String object. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2001 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: String.pm,v 2.33 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::String; + +require 5.004; + +use strict; +use Template::Plugin; +use Template::Exception; + +use base qw( Template::Plugin ); +use vars qw( $VERSION $ERROR); +use overload q|""| => "text", + fallback => 1; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.33 $ =~ /(\d+)\.(\d+)/); +$ERROR = ''; + +*centre = \*center; +*append = \*push; +*prepend = \*unshift; + +#------------------------------------------------------------------------ + +sub new { + my ($class, @args) = @_; + my $context = ref $class ? undef : shift(@args); + my $config = @args && ref $args[-1] eq 'HASH' ? pop(@args) : { }; + + $class = ref($class) || $class; + + my $text = defined $config->{ text } + ? $config->{ text } + : (@args ? shift(@args) : ''); + +# print STDERR "text: [$text]\n"; +# print STDERR "class: [$class]\n"; + + my $self = bless { + text => $text, + filters => [ ], + _CONTEXT => $context, + }, $class; + + my $filter = $config->{ filter } || $config->{ filters }; + + # install any output filters specified as 'filter' or 'filters' option + $self->output_filter($filter) + if $filter; + + return $self; +} + + +sub text { + my $self = shift; + return $self->{ text } unless @{ $self->{ filters } }; + + my $text = $self->{ text }; + my $context = $self->{ _CONTEXT }; + + foreach my $dispatch (@{ $self->{ filters } }) { + my ($name, $args) = @$dispatch; + my $code = $context->filter($name, $args) + || $self->throw($context->error()); + $text = &$code($text); + } + return $text; +} + + +sub copy { + my $self = shift; + $self->new($self->{ text }); +} + + +sub throw { + my $self = shift; + + die (Template::Exception->new('String', join('', @_))); +} + + +#------------------------------------------------------------------------ +# output_filter($filter) +# +# Install automatic output filter(s) for the string. $filter can a list: +# [ 'name1', 'name2' => [ ..args.. ], name4 => { ..args.. } ] or a hash +# { name1 => '', name2 => [ args ], name3 => { args } } +#------------------------------------------------------------------------ + +sub output_filter { + my ($self, $filter) = @_; + my ($name, $args, $dispatch); + my $filters = $self->{ filters }; + my $count = 0; + + if (ref $filter eq 'HASH') { + $filter = [ %$filter ]; + } + elsif (ref $filter ne 'ARRAY') { + $filter = [ split(/\s*\W+\s*/, $filter) ]; + } + + while (@$filter) { + $name = shift @$filter; + + # args may follow as a reference (or empty string, e.g. { foo => '' } + if (@$filter && (ref($filter->[0]) || ! length $filter->[0])) { + $args = shift @$filter; + if ($args) { + $args = [ $args ] unless ref $args eq 'ARRAY'; + } + else { + $args = [ ]; + } + } + else { + $args = [ ]; + } + +# $self->DEBUG("adding output filter $name(@$args)\n"); + + push(@$filters, [ $name, $args ]); + $count++; + } + + return ''; +} + + +#------------------------------------------------------------------------ + +sub push { + my $self = shift; + $self->{ text } .= join('', @_); + return $self; +} + + +sub unshift { + my $self = shift; + $self->{ text } = join('', @_) . $self->{ text }; + return $self; +} + + +sub pop { + my $self = shift; + my $strip = shift || return $self; + $self->{ text } =~ s/$strip$//; + return $self; +} + + +sub shift { + my $self = shift; + my $strip = shift || return $self; + $self->{ text } =~ s/^$strip//; + return $self; +} + +#------------------------------------------------------------------------ + +sub center { + my ($self, $width) = @_; + my $text = $self->{ text }; + my $len = length $text; + $width ||= 0; + + if ($len < $width) { + my $lpad = int(($width - $len) / 2); + my $rpad = $width - $len - $lpad; + $self->{ text } = (' ' x $lpad) . $self->{ text } . (' ' x $rpad); + } + + return $self; +} + + +sub left { + my ($self, $width) = @_; + my $len = length $self->{ text }; + $width ||= 0; + + $self->{ text } .= (' ' x ($width - $len)) + if $width > $len; + + return $self; +} + + +sub right { + my ($self, $width) = @_; + my $len = length $self->{ text }; + $width ||= 0; + + $self->{ text } = (' ' x ($width - $len)) . $self->{ text } + if $width > $len; + + return $self; +} + + +sub format { + my ($self, $format) = @_; + $format = '%s' unless defined $format; + $self->{ text } = sprintf($format, $self->{ text }); + return $self; +} + + +sub filter { + my ($self, $name, @args) = @_; + + my $context = $self->{ _CONTEXT }; + + my $code = $context->filter($name, \@args) + || $self->throw($context->error()); + return &$code($self->{ text }); +} + + +#------------------------------------------------------------------------ + +sub upper { + my $self = CORE::shift; + $self->{ text } = uc $self->{ text }; + return $self; +} + + +sub lower { + my $self = CORE::shift; + $self->{ text } = lc $self->{ text }; + return $self; +} + + +sub capital { + my $self = CORE::shift; + $self->{ text } =~ s/^(.)/\U$1/; + return $self; +} + +#------------------------------------------------------------------------ + +sub chop { + my $self = CORE::shift; + chop $self->{ text }; + return $self; +} + + +sub chomp { + my $self = CORE::shift; + chomp $self->{ text }; + return $self; +} + + +sub trim { + my $self = CORE::shift; + for ($self->{ text }) { + s/^\s+//; + s/\s+$//; + } + return $self; +} + + +sub collapse { + my $self = CORE::shift; + for ($self->{ text }) { + s/^\s+//; + s/\s+$//; + s/\s+/ /g + } + return $self; + +} + +#------------------------------------------------------------------------ + +sub length { + my $self = CORE::shift; + return length $self->{ text }; +} + + +sub truncate { + my ($self, $length, $suffix) = @_; + return $self unless defined $length; + $suffix ||= ''; + return $self if CORE::length $self->{ text } <= $length; + $self->{ text } = substr($self->{ text }, 0, + $length - CORE::length($suffix)) . $suffix; + return $self; +} + + +sub repeat { + my ($self, $n) = @_; + return $self unless defined $n; + $self->{ text } = $self->{ text } x $n; + return $self; +} + + +sub replace { + my ($self, $search, $replace) = @_; + return $self unless defined $search; + $replace = '' unless defined $replace; + $self->{ text } =~ s/$search/$replace/g; + return $self; +} + + +sub remove { + my ($self, $search) = @_; + $search = '' unless defined $search; + $self->{ text } =~ s/$search//g; + return $self; +} + + +sub split { + my $self = CORE::shift; + my $split = CORE::shift; + my $limit = CORE::shift || 0; + $split = '\s+' unless defined $split; + return [ split($split, $self->{ text }, $limit) ]; +} + + +sub search { + my ($self, $pattern) = @_; + return $self->{ text } =~ /$pattern/; +} + + +sub equals { + my ($self, $comparison) = @_; + return $self->{ text } eq $comparison; +} + + +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::String - Object oriented interface for string manipulation + +=head1 SYNOPSIS + + # create String objects via USE directive + [% USE String %] + [% USE String 'initial text' %] + [% USE String text => 'initial text' %] + + # or from an existing String via new() + [% newstring = String.new %] + [% newstring = String.new('newstring text') %] + [% newstring = String.new( text => 'newstring text' ) %] + + # or from an existing String via copy() + [% newstring = String.copy %] + + # append text to string + [% String.append('text to append') %] + + # format left, right or center/centre padded + [% String.left(20) %] + [% String.right(20) %] + [% String.center(20) %] # American spelling + [% String.centre(20) %] # European spelling + + # and various other methods... + +=head1 DESCRIPTION + +This module implements a String class for doing stringy things to +text in an object-oriented way. + +You can create a String object via the USE directive, adding any +initial text value as an argument or as the named parameter 'text'. + + [% USE String %] + [% USE String 'initial text' %] + [% USE String text='initial text' %] + +The object created will be referenced as 'String' by default, but you +can provide a different variable name for the object to be assigned +to: + + [% USE greeting = String 'Hello World' %] + +Once you've got a String object, you can use it as a prototype to +create other String objects with the new() method. + + [% USE String %] + [% greeting = String.new('Hello World') %] + +The new() method also accepts an initial text string as an argument +or the named parameter 'text'. + + [% greeting = String.new( text => 'Hello World' ) %] + +You can also call copy() to create a new String as a copy of the +original. + + [% greet2 = greeting.copy %] + +The String object has a text() method to return the content of the +string. + + [% greeting.text %] + +However, it is sufficient to simply print the string and let the +overloaded stringification operator call the text() method +automatically for you. + + [% greeting %] + +Thus, you can treat String objects pretty much like any regular piece +of text, interpolating it into other strings, for example: + + [% msg = "It printed '$greeting' and then dumped core\n" %] + +You also have the benefit of numerous other methods for manipulating +the string. + + [% msg.append("PS Don't eat the yellow snow") %] + +Note that all methods operate on and mutate the contents of the string +itself. If you want to operate on a copy of the string then simply +take a copy first: + + [% msg.copy.append("PS Don't eat the yellow snow") %] + +These methods return a reference to the String object itself. This +allows you to chain multiple methods together. + + [% msg.copy.append('foo').right(72) %] + +It also means that in the above examples, the String is returned which +causes the text() method to be called, which results in the new value of +the string being printed. To suppress printing of the string, you can +use the CALL directive. + + [% foo = String.new('foo') %] + + [% foo.append('bar') %] # prints "foobar" + + [% CALL foo.append('bar') %] # nothing + +=head1 METHODS + +=head2 Construction Methods + +The following methods are used to create new String objects. + +=over 4 + +=item new() + +Creates a new string using an initial value passed as a positional +argument or the named parameter 'text'. + + [% USE String %] + [% msg = String.new('Hello World') %] + [% msg = String.new( text => 'Hello World' ) %] + +=item copy() + +Creates a new String object which contains a copy of the original string. + + [% msg2 = msg.copy %] + +=back + +=head2 Inspection Methods + +These methods are used to inspect the string content or other parameters +relevant to the string. + +=over 4 + +=item text() + +Returns the internal text value of the string. The stringification +operator is overloaded to call this method. Thus the following are +equivalent: + + [% msg.text %] + [% msg %] + +=item length() + +Returns the length of the string. + + [% USE String("foo") %] + + [% String.length %] # => 3 + +=item search($pattern) + +Searches the string for the regular expression specified in $pattern +returning true if found or false otherwise. + + [% item = String.new('foo bar baz wiz waz woz') %] + + [% item.search('wiz') ? 'WIZZY! :-)' : 'not wizzy :-(' %] + +=item split($pattern, $limit) + +Splits the string based on the delimiter $pattern and optional $limit. +Delegates to Perl's internal split() so the parameters are exactly the same. + + [% FOREACH item.split %] + ... + [% END %] + + [% FOREACH item.split('baz|waz') %] + ... + [% END %] + +=back + +=head2 Mutation Methods + +These methods modify the internal value of the string. For example: + + [% USE str=String('foobar') %] + + [% str.append('.html') %] # str => 'foobar.html' + +The value of the String 'str' is now 'foobar.html'. If you don't want +to modify the string then simply take a copy first. + + [% str.copy.append('.html') %] + +These methods all return a reference to the String object itself. This +has two important benefits. The first is that when used as above, the +String object 'str' returned by the append() method will be stringified +with a call to its text() method. This will return the newly modified +string content. In other words, a directive like: + + [% str.append('.html') %] + +will update the string and also print the new value. If you just want +to update the string but not print the new value then use CALL. + + [% CALL str.append('.html') %] + +The other benefit of these methods returning a reference to the String +is that you can chain as many different method calls together as you +like. For example: + + [% String.append('.html').trim.format(href) %] + +Here are the methods: + +=over 4 + +=item push($suffix, ...) / append($suffix, ...) + +Appends all arguments to the end of the string. The +append() method is provided as an alias for push(). + + [% msg.push('foo', 'bar') %] + [% msg.append('foo', 'bar') %] + +=item pop($suffix) + +Removes the suffix passed as an argument from the end of the String. + + [% USE String 'foo bar' %] + [% String.pop(' bar') %] # => 'foo' + +=item unshift($prefix, ...) / prepend($prefix, ...) + +Prepends all arguments to the beginning of the string. The +prepend() method is provided as an alias for unshift(). + + [% msg.unshift('foo ', 'bar ') %] + [% msg.prepend('foo ', 'bar ') %] + +=item shift($prefix) + +Removes the prefix passed as an argument from the start of the String. + + [% USE String 'foo bar' %] + [% String.shift('foo ') %] # => 'bar' + +=item left($pad) + +If the length of the string is less than $pad then the string is left +formatted and padded with spaces to $pad length. + + [% msg.left(20) %] + +=item right($pad) + +As per left() but right padding the String to a length of $pad. + + [% msg.right(20) %] + +=item center($pad) / centre($pad) + +As per left() and right() but formatting the String to be centered within +a space padded string of length $pad. The centre() method is provided as +an alias for center() to keep Yanks and Limeys happy. + + [% msg.center(20) %] # American spelling + [% msg.centre(20) %] # European spelling + +=item format($format) + +Apply a format in the style of sprintf() to the string. + + [% USE String("world") %] + [% String.format("Hello %s\n") %] # => "Hello World\n" + +=item upper() + +Converts the string to upper case. + + [% USE String("foo") %] + + [% String.upper %] # => 'FOO' + +=item lower() + +Converts the string to lower case + + [% USE String("FOO") %] + + [% String.lower %] # => 'foo' + +=item capital() + +Converts the first character of the string to upper case. + + [% USE String("foo") %] + + [% String.capital %] # => 'Foo' + +The remainder of the string is left untouched. To force the string to +be all lower case with only the first letter capitalised, you can do +something like this: + + [% USE String("FOO") %] + + [% String.lower.capital %] # => 'Foo' + +=item chop() + +Removes the last character from the string. + + [% USE String("foop") %] + + [% String.chop %] # => 'foo' + +=item chomp() + +Removes the trailing newline from the string. + + [% USE String("foo\n") %] + + [% String.chomp %] # => 'foo' + +=item trim() + +Removes all leading and trailing whitespace from the string + + [% USE String(" foo \n\n ") %] + + [% String.trim %] # => 'foo' + +=item collapse() + +Removes all leading and trailing whitespace and collapses any sequences +of multiple whitespace to a single space. + + [% USE String(" \n\r \t foo \n \n bar \n") %] + + [% String.collapse %] # => "foo bar" + +=item truncate($length, $suffix) + +Truncates the string to $length characters. + + [% USE String('long string') %] + [% String.truncate(4) %] # => 'long' + +If $suffix is specified then it will be appended to the truncated +string. In this case, the string will be further shortened by the +length of the suffix to ensure that the newly constructed string +complete with suffix is exactly $length characters long. + + [% USE msg = String('Hello World') %] + [% msg.truncate(8, '...') %] # => 'Hello...' + +=item replace($search, $replace) + +Replaces all occurences of $search in the string with $replace. + + [% USE String('foo bar foo baz') %] + [% String.replace('foo', 'wiz') %] # => 'wiz bar wiz baz' + +=item remove($search) + +Remove all occurences of $search in the string. + + [% USE String('foo bar foo baz') %] + [% String.remove('foo ') %] # => 'bar baz' + +=item repeat($count) + +Repeats the string $count times. + + [% USE String('foo ') %] + [% String.repeat(3) %] # => 'foo foo foo ' + +=back + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.33, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Table.pm b/lib/Template/Plugin/Table.pm new file mode 100644 index 0000000..c1fd79a --- /dev/null +++ b/lib/Template/Plugin/Table.pm @@ -0,0 +1,464 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Table +# +# DESCRIPTION +# +# Plugin to order a linear data set into a virtual 2-dimensional table +# from which row and column permutations can be fetched. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Table.pm,v 2.64 2004/01/13 16:20:38 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Table; + +require 5.004; + +use strict; +use vars qw( @ISA $VERSION $AUTOLOAD ); +use base qw( Template::Plugin ); +use Template::Plugin; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + + +#------------------------------------------------------------------------ +# new($context, \@data, \%args) +# +# This constructor method initialises the object to iterate through +# the data set passed by reference to a list as the first parameter. +# It calculates the shape of the permutation table based on the ROWS +# or COLS parameters specified in the $args hash reference. The +# OVERLAP parameter may be provided to specify the number of common +# items that should be shared between subseqent columns. +#------------------------------------------------------------------------ + +sub new { + my ($class, $context, $data, $params) = @_; + my ($size, $rows, $cols, $coloff, $overlap, $error); + + # if the data item is a reference to a Template::Iterator object, + # or subclass thereof, we call its get_all() method to extract all + # the data it contains + if (UNIVERSAL::isa($data, 'Template::Iterator')) { + ($data, $error) = $data->get_all(); + return $class->error("iterator failed to provide data for table: ", + $error) + if $error; + } + + return $class->error('invalid table data, expecting a list') + unless ref $data eq 'ARRAY'; + + $params ||= { }; + return $class->error('invalid table parameters, expecting a hash') + unless ref $params eq 'HASH'; + + # ensure keys are folded to upper case + @$params{ map { uc } keys %$params } = values %$params; + + $size = scalar @$data; + $overlap = $params->{ OVERLAP } || 0; + + # calculate number of columns based on a specified number of rows + if ($rows = $params->{ ROWS }) { + if ($size < $rows) { + $rows = $size; # pad? + $cols = 1; + $coloff = 0; + } + else { + $coloff = $rows - $overlap; + $cols = int ($size / $coloff) + + ($size % $coloff > $overlap ? 1 : 0) + } + } + # calculate number of rows based on a specified number of columns + elsif ($cols = $params->{ COLS }) { + if ($size < $cols) { + $cols = $size; + $rows = 1; + $coloff = 1; + } + else { + $coloff = int ($size / $cols) + + ($size % $cols > $overlap ? 1 : 0); + $rows = $coloff + $overlap; + } + } + else { + $rows = $size; + $cols = 1; + $coloff = 0; + } + + bless { + _DATA => $data, + _SIZE => $size, + _NROWS => $rows, + _NCOLS => $cols, + _COLOFF => $coloff, + _OVERLAP => $overlap, + _PAD => defined $params->{ PAD } ? $params->{ PAD } : 1, + }, $class; +} + + +#------------------------------------------------------------------------ +# row($n) +# +# Returns a reference to a list containing the items in the row whose +# number is specified by parameter. If the row number is undefined, +# it calls rows() to return a list of all rows. +#------------------------------------------------------------------------ + +sub row { + my ($self, $row) = @_; + my ($data, $cols, $offset, $size, $pad) + = @$self{ qw( _DATA _NCOLS _COLOFF _SIZE _PAD) }; + my @set; + + # return all rows if row number not specified + return $self->rows() + unless defined $row; + + return () if $row >= $self->{ _NROWS } || $row < 0; + + my $index = $row; + + for (my $c = 0; $c < $cols; $c++) { + push(@set, $index < $size + ? $data->[$index] + : ($pad ? undef : ())); + $index += $offset; + } + return \@set; +} + + +#------------------------------------------------------------------------ +# col($n) +# +# Returns a reference to a list containing the items in the column whose +# number is specified by parameter. If the column number is undefined, +# it calls cols() to return a list of all columns. +#------------------------------------------------------------------------ + +sub col { + my ($self, $col) = @_; + my ($data, $size) = @$self{ qw( _DATA _SIZE ) }; + my ($start, $end); + my $blanks = 0; + + # return all cols if row number not specified + return $self->cols() + unless defined $col; + + return () if $col >= $self->{ _NCOLS } || $col < 0; + + $start = $self->{ _COLOFF } * $col; + $end = $start + $self->{ _NROWS } - 1; + $end = $start if $end < $start; + if ($end >= $size) { + $blanks = ($end - $size) + 1; + $end = $size - 1; + } + return () if $start >= $size; + return [ @$data[$start..$end], + $self->{ _PAD } ? ((undef) x $blanks) : () ]; +} + + +#------------------------------------------------------------------------ +# rows() +# +# Returns all rows as a reference to a list of rows. +#------------------------------------------------------------------------ + +sub rows { + my $self = shift; + return [ map { $self->row($_) } (0..$self->{ _NROWS }-1) ]; +} + + +#------------------------------------------------------------------------ +# cols() +# +# Returns all rows as a reference to a list of rows. +#------------------------------------------------------------------------ + +sub cols { + my $self = shift; + return [ map { $self->col($_) } (0..$self->{ _NCOLS }-1) ]; +} + + +#------------------------------------------------------------------------ +# AUTOLOAD +# +# Provides read access to various internal data members. +#------------------------------------------------------------------------ + +sub AUTOLOAD { + my $self = shift; + my $item = $AUTOLOAD; + $item =~ s/.*:://; + return if $item eq 'DESTROY'; + + if ($item =~ /^data|size|nrows|ncols|overlap|pad$/) { + return $self->{ $item }; + } + else { + return (undef, "no such table method: $item"); + } +} + + + +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::Table - Plugin to present data in a table + +=head1 SYNOPSIS + + [% USE table(list, rows=n, cols=n, overlap=n, pad=0) %] + + [% FOREACH item = table.row(n) %] + [% item %] + [% END %] + + [% FOREACH item = table.col(n) %] + [% item %] + [% END %] + + [% FOREACH row = table.rows %] + [% FOREACH item = row %] + [% item %] + [% END %] + [% END %] + + [% FOREACH col = table.cols %] + [% col.first %] - [% col.last %] ([% col.size %] entries) + [% END %] + +=head1 DESCRIPTION + +The Table plugin allows you to format a list of data items into a +virtual table. When you create a Table plugin via the USE directive, +simply pass a list reference as the first parameter and then specify +a fixed number of rows or columns. + + [% USE Table(list, rows=5) %] + [% USE table(list, cols=5) %] + +The 'Table' plugin name can also be specified in lower case as shown +in the second example above. You can also specify an alternative variable +name for the plugin as per regular Template Toolkit syntax. + + [% USE mydata = table(list, rows=5) %] + +The plugin then presents a table based view on the data set. The data +isn't actually reorganised in any way but is available via the row(), +col(), rows() and cols() as if formatted into a simple two dimensional +table of n rows x n columns. Thus, if our sample 'alphabet' list +contained the letters 'a' to 'z', the above USE directives would +create plugins that represented the following views of the alphabet. + + [% USE table(alphabet, ... %] + + rows=5 cols=5 + a f k p u z a g m s y + b g l q v b h n t z + c h m r w c i o u + d i n s x d j p v + e j o t y e k q w + f l r x + +We can request a particular row or column using the row() and col() +methods. + + [% USE table(alphabet, rows=5) %] + [% FOREACH item = table.row(0) %] + # [% item %] set to each of [ a f k p u z ] in turn + [% END %] + + [% FOREACH item = table.col(2) %] + # [% item %] set to each of [ m n o p q r ] in turn + [% END %] + +Data in rows is returned from left to right, columns from top to +bottom. The first row/column is 0. By default, rows or columns that +contain empty values will be padded with the undefined value to fill +it to the same size as all other rows or columns. For example, the +last row (row 4) in the first example would contain the values [ e j o +t y undef ]. The Template Toolkit will safely accept these undefined +values and print a empty string. You can also use the IF directive to +test if the value is set. + + [% FOREACH item = table.row(4) %] + [% IF item %] + Item: [% item %] + [% END %] + [% END %] + +You can explicitly disable the 'pad' option when creating the plugin to +returned shortened rows/columns where the data is empty. + + [% USE table(alphabet, cols=5, pad=0) %] + [% FOREACH item = table.col(4) %] + # [% item %] set to each of 'y z' + [% END %] + +The rows() method returns all rows/columns in the table as a reference +to a list of rows (themselves list references). The row() methods +when called without any arguments calls rows() to return all rows in +the table. + +Ditto for cols() and col(). + + [% USE table(alphabet, cols=5) %] + [% FOREACH row = table.rows %] + [% FOREACH item = row %] + [% item %] + [% END %] + [% END %] + +The Template Toolkit provides the first(), last() and size() methods +that can be called on list references to return the first/last entry +or the number of entried. The following example shows how we might +use this to provide an alphabetical index split into 3 even parts. + + [% USE table(alphabet, cols=3, pad=0) %] + [% FOREACH group = table.col %] + [ [% group.first %] - [% group.last %] ([% group.size %] letters) ] + [% END %] + +This produces the following output: + + [ a - i (9 letters) ] + [ j - r (9 letters) ] + [ s - z (8 letters) ] + +We can also use the general purpose join() list method which joins +the items of the list using the connecting string specified. + + [% USE table(alphabet, cols=5) %] + [% FOREACH row = table.rows %] + [% row.join(' - ') %] + [% END %] + +Data in the table is ordered downwards rather than across but can easily +be transformed on output. For example, to format our data in 5 columns +with data ordered across rather than down, we specify 'rows=5' to order +the data as such: + + a f . . + b g . + c h + d i + e j + +and then iterate down through each column (a-e, f-j, etc.) printing +the data across. + + a b c d e + f g h i j + . . + . + +Example code to do so would be much like the following: + + [% USE table(alphabet, rows=3) %] + [% FOREACH cols = table.cols %] + [% FOREACH item = cols %] + [% item %] + [% END %] + [% END %] + + a b c + d e f + g h i + j . . + . + +In addition to a list reference, the Table plugin constructor may be +passed a reference to a Template::Iterator object or subclass thereof. +The get_all() method is first called on the iterator to return all +remaining items. These are then available via the usual Table interface. + + [% USE DBI(dsn,user,pass) -%] + + # query() returns an iterator + [% results = DBI.query('SELECT * FROM alphabet ORDER BY letter') %] + + # pass into Table plugin + [% USE table(results, rows=8 overlap=1 pad=0) -%] + + [% FOREACH row = table.cols -%] + [% row.first.letter %] - [% row.last.letter %]: + [% row.join(', ') %] + [% END %] + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.64, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/URL.pm b/lib/Template/Plugin/URL.pm new file mode 100644 index 0000000..c2246b7 --- /dev/null +++ b/lib/Template/Plugin/URL.pm @@ -0,0 +1,236 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::URL +# +# DESCRIPTION +# +# Template Toolkit Plugin for constructing URL's from a base stem +# and adaptable parameters. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: URL.pm,v 2.64 2004/01/13 16:20:39 abw Exp $ +# +#============================================================================ + +package Template::Plugin::URL; + +require 5.004; + +use strict; +use vars qw( @ISA $VERSION ); +use Template::Plugin; + +@ISA = qw( Template::Plugin ); +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + + +#------------------------------------------------------------------------ +# new($context, $baseurl, \%url_params) +# +# Constructor method which returns a sub-routine closure for constructing +# complex URL's from a base part and hash of additional parameters. +#------------------------------------------------------------------------ + +sub new { + my ($class, $context, $base, $args) = @_; + $args ||= { }; + + return sub { + my $newbase = shift unless ref $_[0] eq 'HASH'; + my $newargs = shift || { }; + my $combo = { %$args, %$newargs }; + my $urlargs = join('&', +# map { "$_=" . escape($combo->{ $_ }) } + map { args($_, $combo->{ $_ }) } + grep { defined $combo->{ $_ } } + sort keys %$combo); + + my $query = $newbase || $base || ''; + $query .= '?' if length $query && length $urlargs; + $query .= $urlargs if length $urlargs; + + return $query + } +} + + +sub args { + my ($key, $val) = @_; + $key = escape($key); + return map { + "$key=" . escape($_); + } ref $val eq 'ARRAY' ? @$val : $val; + +} + +#------------------------------------------------------------------------ +# escape($url) +# +# URL-encode data. Borrowed with minor modifications from CGI.pm. +# Kudos to Lincold Stein. +#------------------------------------------------------------------------ + +sub escape { + my $toencode = shift; + return undef unless defined($toencode); + $toencode=~s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg; + return $toencode; +} + +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::URL - Plugin to construct complex URLs + +=head1 SYNOPSIS + + [% USE url('/cgi-bin/foo.pl') %] + + [% url(debug = 1, id = 123) %] + # ==> /cgi/bin/foo.pl?debug=1&id=123 + + + [% USE mycgi = url('/cgi-bin/bar.pl', mode='browse', debug=1) %] + + [% mycgi %] + # ==> /cgi/bin/bar.pl?mode=browse&debug=1 + + [% mycgi(mode='submit') %] + # ==> /cgi/bin/bar.pl?mode=submit&debug=1 + + [% mycgi(debug='d2 p0', id='D4-2k[4]') %] + # ==> /cgi-bin/bar.pl?mode=browse&debug=d2%20p0&id=D4-2k%5B4%5D + + +=head1 DESCRIPTION + +The URL plugin can be used to construct complex URLs from a base stem +and a hash array of additional query parameters. + +The constructor should be passed a base URL and optionally, a hash array +reference of default parameters and values. Used from with a Template +Documents, this would look something like the following: + + [% USE url('http://www.somewhere.com/cgi-bin/foo.pl') %] + [% USE url('/cgi-bin/bar.pl', mode='browse') %] + [% USE url('/cgi-bin/baz.pl', mode='browse', debug=1) %] + +When the plugin is then called without any arguments, the default base +and parameters are returned as a formatted query string. + + [% url %] + +For the above three examples, these will produce the following outputs: + + http://www.somewhere.com/cgi-bin/foo.pl + /cgi-bin/bar.pl?mode=browse + /cgi-bin/baz.pl?mode=browse&debug=1 + +Additional parameters may be also be specified: + + [% url(mode='submit', id='wiz') %] + +Which, for the same three examples, produces: + + http://www.somewhere.com/cgi-bin/foo.pl?mode=submit&id=wiz + /cgi-bin/bar.pl?mode=browse&id=wiz + /cgi-bin/baz.pl?mode=browse&debug=1&id=wiz + +A new base URL may also be specified as the first option: + + [% url('/cgi-bin/waz.pl', test=1) %] + +producing + + /cgi-bin/waz.pl?test=1 + /cgi-bin/waz.pl?mode=browse&test=1 + /cgi-bin/waz.pl?mode=browse&debug=1&test=1 + + +The ordering of the parameters is non-deterministic due to fact that +Perl's hashes themselves are unordered. This isn't a problem as the +ordering of CGI parameters is insignificant (to the best of my knowledge). +All values will be properly escaped thanks to some code borrowed from +Lincoln Stein's CGI.pm. e.g. + + [% USE url('/cgi-bin/woz.pl') %] + [% url(name="Elrich von Benjy d'Weiro") %] + +Here the spaces and "'" character are escaped in the output: + + /cgi-bin/woz.pl?name=Elrich%20von%20Benjy%20d%27Weiro + +Alternate name may be provided for the plugin at construction time +as per regular Template Toolkit syntax. + + [% USE mycgi = url('cgi-bin/min.pl') %] + + [% mycgi(debug=1) %] + +Note that in the following line, additional parameters are seperated +by '&', while common usage on the Web is to just use '&'. '&' +is actually the Right Way to do it. See this URL for more information: +http://ppewww.ph.gla.ac.uk/~flavell/www/formgetbyurl.html + + /cgi-bin/waz.pl?mode=browse&debug=1&test=1 + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.64, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/View.pm b/lib/Template/Plugin/View.pm new file mode 100644 index 0000000..c22ba16 --- /dev/null +++ b/lib/Template/Plugin/View.pm @@ -0,0 +1,127 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::View +# +# DESCRIPTION +# A user-definable view based on templates. Similar to the concept of +# a "Skin". +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: View.pm,v 2.63 2004/01/13 16:20:39 abw Exp $ +# +#============================================================================ + +package Template::Plugin::View; + +require 5.004; + +use strict; +use Template::Plugin; +use vars qw( $VERSION ); +use base qw( Template::Plugin ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.63 $ =~ /(\d+)\.(\d+)/); + +use Template::View; + +#------------------------------------------------------------------------ +# new($context, \%config) +#------------------------------------------------------------------------ + +sub new { + my $class = shift; + my $context = shift; + my $view = Template::View->new($context, @_) + || return $class->error($Template::View::ERROR); + $view->seal(); + return $view; +} + + + +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::View - Plugin to create views (Template::View) + +=head1 SYNOPSIS + + [% USE view( + prefix = 'splash/' # template prefix/suffix + suffix = '.tt2' + bgcol = '#ffffff' # and any other variables you + style = 'Fancy HTML' # care to define as view metadata, + items = [ foo, bar.baz ] # including complex data and + foo = bar ? baz : x.y.z # expressions + %] + + [% view.title %] # access view metadata + + [% view.header(title = 'Foo!') %] # view "methods" process blocks or + [% view.footer %] # templates with prefix/suffix added + +=head1 DESCRIPTION + +This plugin module creates Template::View objects. Views are an +experimental feature and are subject to change in the near future. +In the mean time, please consult L<Template::View> for further info. + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.63, 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<Template::Plugin|Template::Plugin>, L<Template::View|Template::View> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/Wrap.pm b/lib/Template/Plugin/Wrap.pm new file mode 100644 index 0000000..96c600a --- /dev/null +++ b/lib/Template/Plugin/Wrap.pm @@ -0,0 +1,162 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::Wrap +# +# DESCRIPTION +# Plugin for wrapping text via the Text::Wrap module. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Wrap.pm,v 2.63 2004/01/13 16:20:40 abw Exp $ +# +#============================================================================ + +package Template::Plugin::Wrap; + +require 5.004; + +use strict; +use vars qw( @ISA $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; +use Text::Wrap; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.63 $ =~ /(\d+)\.(\d+)/); + +sub new { + my ($class, $context, $format) = @_;; + $context->define_filter('wrap', [ \&wrap_filter_factory => 1 ]); + return \&tt_wrap; +} + +sub tt_wrap { + my $text = shift; + my $width = shift || 72; + my $itab = shift; + my $ntab = shift; + $itab = '' unless defined $itab; + $ntab = '' unless defined $ntab; + $Text::Wrap::columns = $width; + Text::Wrap::wrap($itab, $ntab, $text); +} + +sub wrap_filter_factory { + my ($context, @args) = @_; + return sub { + my $text = shift; + tt_wrap($text, @args); + } +} + + +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::Wrap - Plugin interface to Text::Wrap + +=head1 SYNOPSIS + + [% USE wrap %] + + # call wrap subroutine + [% wrap(mytext, width, initial_tab, subsequent_tab) %] + + # or use wrap FILTER + [% mytext FILTER wrap(width, initital_tab, subsequent_tab) %] + +=head1 DESCRIPTION + +This plugin provides an interface to the Text::Wrap module which +provides simple paragraph formatting. + +It defines a 'wrap' subroutine which can be called, passing the input +text and further optional parameters to specify the page width (default: +72), and tab characters for the first and subsequent lines (no defaults). + + [% USE wrap %] + + [% text = BLOCK %] + First, attach the transmutex multiplier to the cross-wired + quantum homogeniser. + [% END %] + + [% wrap(text, 40, '* ', ' ') %] + +Output: + + * First, attach the transmutex + multiplier to the cross-wired quantum + homogeniser. + +It also registers a 'wrap' filter which accepts the same three optional +arguments but takes the input text directly via the filter input. + + [% FILTER bullet = wrap(40, '* ', ' ') -%] + First, attach the transmutex multiplier to the cross-wired quantum + homogeniser. + [%- END %] + + [% FILTER bullet -%] + Then remodulate the shield to match the harmonic frequency, taking + care to correct the phase difference. + [% END %] + +Output: + + * First, attach the transmutex + multiplier to the cross-wired quantum + homogeniser. + + * Then remodulate the shield to match + the harmonic frequency, taking + care to correct the phase difference. + +=head1 AUTHOR + +Andy Wardley E<lt>abw@wardley.orgE<gt> + +The Text::Wrap module was written by David Muir Sharnoff +E<lt>muir@idiom.comE<gt> with help from Tim Pierce and many +others. + +=head1 VERSION + +2.63, 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<Template::Plugin|Template::Plugin>, L<Text::Wrap|Text::Wrap> + diff --git a/lib/Template/Plugin/XML/DOM.pm b/lib/Template/Plugin/XML/DOM.pm new file mode 100644 index 0000000..30bac3b --- /dev/null +++ b/lib/Template/Plugin/XML/DOM.pm @@ -0,0 +1,841 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::XML::DOM +# +# DESCRIPTION +# +# Simple Template Toolkit plugin interfacing to the XML::DOM.pm module. +# +# AUTHORS +# Andy Wardley <abw@kfs.org> +# Simon Matthews <sam@knowledgepool.com> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley, Simon Matthews. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: DOM.pm,v 2.54 2004/01/13 16:21:50 abw Exp $ +# +#============================================================================ + +package Template::Plugin::XML::DOM; + +require 5.004; + +use strict; +use Template::Plugin; +use XML::DOM; + +use base qw( Template::Plugin ); +use vars qw( $VERSION $DEBUG ); + +$VERSION = 2.6; +$DEBUG = 0 unless defined $DEBUG; + + +#------------------------------------------------------------------------ +# new($context, \%config) +# +# Constructor method for XML::DOM plugin. Creates an XML::DOM::Parser +# object and initialise plugin configuration. +#------------------------------------------------------------------------ + +sub new { + my $class = shift; + my $context = shift; + my $args = ref $_[-1] eq 'HASH' ? pop(@_) : { }; + + my $parser ||= XML::DOM::Parser->new(%$args) + || return $class->_throw("failed to create XML::DOM::Parser\n"); + + # we've had to deprecate the old usage because it broke things big time + # with DOM trees never getting cleaned up. + return $class->_throw("XML::DOM usage has changed - you must now call parse()\n") + if @_; + + bless { + _PARSER => $parser, + _DOCS => [ ], + _CONTEXT => $context, + _PREFIX => $args->{ prefix } || '', + _SUFFIX => $args->{ suffix } || '', + _DEFAULT => $args->{ default } || '', + _VERBOSE => $args->{ verbose } || 0, + _NOSPACE => $args->{ nospace } || 0, + _DEEP => $args->{ deep } || 0, + }, $class; +} + + +#------------------------------------------------------------------------ +# parse($content, \%named_params) +# +# Parses an XML stream, provided as the first positional argument (assumed +# to be a filename unless it contains a '<' character) or specified in +# the named parameter hash as one of 'text', 'xml' (same as text), 'file' +# or 'filename'. +#------------------------------------------------------------------------ + +sub parse { + my $self = shift; + my $args = ref $_[-1] eq 'HASH' ? pop(@_) : { }; + my $parser = $self->{ _PARSER }; + my ($content, $about, $method, $doc); + + # determine the input source from a positional parameter (may be a + # filename or XML text if it contains a '<' character) or by using + # named parameters which may specify one of 'file', 'filename', 'text' + # or 'xml' + + if ($content = shift) { + if ($content =~ /\</) { + $about = 'xml text'; + $method = 'parse'; + } + else { + $about = "xml file $content"; + $method = 'parsefile'; + } + } + elsif ($content = $args->{ text } || $args->{ xml }) { + $about = 'xml text'; + $method = 'parse'; + } + elsif ($content = $args->{ file } || $args->{ filename }) { + $about = "xml file $content"; + $method = 'parsefile'; + } + else { + return $self->_throw('no filename or xml text specified'); + } + + # parse the input source using the appropriate method determined above + eval { $doc = $parser->$method($content) } and not $@ + or return $self->_throw("failed to parse $about: $@"); + + # update XML::DOM::Document _UserData to contain config details + $doc->[ XML::DOM::Node::_UserData ] = { + map { ( $_ => $self->{ $_ } ) } + qw( _CONTEXT _PREFIX _SUFFIX _VERBOSE _NOSPACE _DEEP _DEFAULT ), + }; + + # keep track of all DOM docs for subsequent dispose() +# print STDERR "DEBUG: $self adding doc: $doc\n" +# if $DEBUG; + + push(@{ $self->{ _DOCS } }, $doc); + + return $doc; +} + + +#------------------------------------------------------------------------ +# _throw($errmsg) +# +# Raised a Template::Exception of type XML.DOM via die(). +#------------------------------------------------------------------------ + +sub _throw { + my ($self, $error) = @_; + die (Template::Exception->new('XML.DOM', $error)); +} + + +#------------------------------------------------------------------------ +# DESTROY +# +# Cleanup method which calls dispose() on any and all DOM documents +# created by this object. Also breaks any circular references that +# may exist with the context object. +#------------------------------------------------------------------------ + +sub DESTROY { + my $self = shift; + + # call dispose() on each document produced by this parser + foreach my $doc (@{ $self->{ _DOCS } }) { +# print STDERR "DEBUG: $self destroying $doc\n" +# if $DEBUG; + if (ref $doc) { +# print STDERR "disposing of $doc\n"; + undef $doc->[ XML::DOM::Node::_UserData ]->{ _CONTEXT }; + $doc->dispose(); + } + } + delete $self->{ _CONTEXT }; + delete $self->{ _PARSER }; +} + + + +#======================================================================== +package XML::DOM::Node; +#======================================================================== + + +#------------------------------------------------------------------------ +# present($view) +# +# Method to present node via a view (supercedes all that messy toTemplate +# stuff below). +#------------------------------------------------------------------------ + +sub present { + my ($self, $view) = @_; + + if ($self->getNodeType() == XML::DOM::ELEMENT_NODE) { + # it's an element + $view->view($self->getTagName(), $self); + } + else { + my $text = $self->toString(); + $view->view('text', $text); + } +} + +sub content { + my ($self, $view) = @_; + my $output = ''; + foreach my $node (@{ $self->getChildNodes }) { + $output .= $node->present($view); + +# abw test passing args, Aug 2001 +# $output .= $view->print($node); + } + return $output; +} + + +#------------------------------------------------------------------------ +# toTemplate($prefix, $suffix, \%named_params) +# +# Process the current node as a template. +#------------------------------------------------------------------------ + +sub toTemplate { + my $self = shift; + _template_node($self, $self->_args(@_)); +} + + +#------------------------------------------------------------------------ +# childrenToTemplate($prefix, $suffix, \%named_params) +# +# Process all the current node's children as templates. +#------------------------------------------------------------------------ + +sub childrenToTemplate { + my $self = shift; + _template_kids($self, $self->_args(@_)); +} + + +#------------------------------------------------------------------------ +# allChildrenToTemplate($prefix, $suffix, \%named_params) +# +# Process all the current node's children, and their children, and +# their children, etc., etc., as templates. Same effect as calling the +# childrenToTemplate() method with the 'deep' option set. +#------------------------------------------------------------------------ + +sub allChildrenToTemplate { + my $self = shift; + my $args = $self->_args(@_); + $args->{ deep } = 1; + _template_kids($self, $args); +} + + +#------------------------------------------------------------------------ +# _args($prefix, $suffix, \%name_params) +# +# Reads the optional positional parameters, $prefix and $suffix, and +# also examines any named parameters hash to construct a set of +# current configuration parameters. Where not specified directly, the +# object defaults are used. +#------------------------------------------------------------------------ + +sub _args { + my $self = shift; + my $args = ref $_[-1] eq 'HASH' ? pop(@_) : { }; + my $doc = $self->getOwnerDocument() || $self; + my $data = $doc->[ XML::DOM::Node::_UserData ]; + + return { + prefix => @_ ? shift : $args->{ prefix } || $data->{ _PREFIX }, + suffix => @_ ? shift : $args->{ suffix } || $data->{ _SUFFIX }, + verbose => $args->{ verbose } || $data->{ _VERBOSE }, + nospace => $args->{ nospace } || $data->{ _NOSPACE }, + deep => $args->{ deep } || $data->{ _DEEP }, + default => $args->{ default } || $data->{ _DEFAULT }, + context => $data->{ _CONTEXT }, + }; +} + + + +#------------------------------------------------------------------------ +# _template_node($node, $args, $vars) +# +# Process a template for the current DOM node where the template name +# is taken from the node TagName, with any specified 'prefix' and/or +# 'suffix' applied. The 'default' argument can also be provided to +# specify a default template to be used when a specific template can't +# be found. The $args parameter referenced a hash array through which +# these configuration items are passed (see _args()). The current DOM +# node is made available to the template as the variable 'node', along +# with any other variables passed in the optional $vars hash reference. +# To permit the 'children' and 'prune' callbacks to be raised as node +# methods (see _template_kids() below), these items, if defined in the +# $vars hash, are copied into the node object where its AUTOLOAD method +# can find them. +#------------------------------------------------------------------------ + +sub _template_node { + my $node = shift || die "no XML::DOM::Node reference\n"; + my $args = shift || die "no XML::DOM args passed to _template_node\n"; + my $vars = shift || { }; + my $context = $args->{ context } || die "no context in XML::DOM args\n"; + my $template; + my $output = ''; + + # if this is not an element then it is text so output it + unless ($node->getNodeType() == XML::DOM::ELEMENT_NODE ) { + if ($args->{ verbose }) { + $output = $node->toString(); + $output =~ s/\s+$// if $args->{ nospace }; + } + } + else { + my $element = ( $args->{ prefix } || '' ) + . $node->getTagName() + . ( $args->{ suffix } || '' ); + + # locate a template by name built from prefix, tagname and suffix + # or fall back on any default template specified + eval { $template = $context->template($element) }; + eval { $template = $context->template($args->{ default }) } + if $@ && $args->{ default }; + $template = $element unless $template; + + # copy 'children' and 'prune' callbacks into node object (see AUTOLOAD) + my $doc = $node->getOwnerDocument() || $node; + my $data = $doc->[ XML::DOM::Node::_UserData ]; + + $data->{ _TT_CHILDREN } = $vars->{ children }; + $data->{ _TT_PRUNE } = $vars->{ prune }; + + # add node reference to existing vars hash + $vars->{ node } = $node; + + $output = $context->include($template, $vars); + + # break any circular references + delete $vars->{ node }; + delete $data->{ _TT_CHILDREN }; + delete $data->{ _TT_PRUNE }; + } + + return $output; +} + + +#------------------------------------------------------------------------ +# _template_kids($node, $args) +# +# Process all the children of the current node as templates, via calls +# to _template_node(). If the 'deep' argument is set, then the process +# will continue recursively. In this case, the node template is first +# processed, followed by any children of that node (i.e. depth first, +# parent before). A closure called 'children' is created and added +# to the Stash variables passed to _template_node(). This can be called +# from the parent template to process all child nodes at the current point. +# This then "prunes" the tree preventing the children from being processed +# after the parent template. A 'prune' callback is also added to prune +# the tree without processing the children. Note that _template_node() +# copies these callbacks into each parent node, allowing them to be called +# as [% node. +#------------------------------------------------------------------------ + +sub _template_kids { + my $node = shift || die "no XML::DOM::Node reference\n"; + my $args = shift || die "no XML::DOM args passed to _template_kids\n"; + my $context = $args->{ context } || die "no context in XML::DOM args\n"; + my $output = ''; + + foreach my $kid ( $node->getChildNodes() ) { + # define some callbacks to allow template to call [% content %] + # or [% prune %]. They are also inserted into each node reference + # so they can be called as [% node.content %] and [% node.prune %] + my $prune = 0; + my $vars = { }; + $vars->{ children } = sub { + $prune = 1; + _template_kids($kid, $args); + }; + $vars->{ prune } = sub { + $prune = 1; + return ''; + }; + + $output .= _template_node($kid, $args, $vars); + $output .= _template_kids($kid, $args) + if $args->{ deep } && ! $prune; + } + return $output; +} + + +#======================================================================== +package XML::DOM::Element; +#======================================================================== + +use vars qw( $AUTOLOAD ); + +sub AUTOLOAD { + my $self = shift; + my $method = $AUTOLOAD; + my $attrib; + + $method =~ s/.*:://; + return if $method eq 'DESTROY'; + + my $doc = $self->getOwnerDocument() || $self; + my $data = $doc->[ XML::DOM::Node::_UserData ]; + + # call 'content' or 'prune' callbacks, if defined (see _template_node()) + return &$attrib() + if ($method =~ /^children|prune$/) + && defined($attrib = $data->{ "_TT_\U$method" }) + && ref $attrib eq 'CODE'; + + return $attrib + if defined ($attrib = $self->getAttribute($method)); + + return ''; +} + + +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::XML::DOM - Plugin interface to XML::DOM + +=head1 SYNOPSIS + + # load plugin + [% USE dom = XML.DOM %] + + # also provide XML::Parser options + [% USE dom = XML.DOM(ProtocolEncoding =E<gt> 'ISO-8859-1') %] + + # parse an XML file + [% doc = dom.parse(filename) %] + [% doc = dom.parse(file => filename) %] + + # parse XML text + [% doc = dom.parse(xmltext) %] + [% doc = dom.parse(text => xmltext) %] + + # call any XML::DOM methods on document/element nodes + [% FOREACH node = doc.getElementsByTagName('report') %] + * [% node.getAttribute('title') %] # or just '[% node.title %]' + [% END %] + + # define VIEW to present node(s) + [% VIEW report notfound='xmlstring' %] + # handler block for a <report>...</report> element + [% BLOCK report %] + [% item.content(view) %] + [% END %] + + # handler block for a <section title="...">...</section> element + [% BLOCK section %] + <h1>[% item.title %]</h1> + [% item.content(view) %] + [% END %] + + # default template block converts item to string representation + [% BLOCK xmlstring; item.toString; END %] + + # block to generate simple text + [% BLOCK text; item; END %] + [% END %] + + # now present node (and children) via view + [% report.print(node) %] + + # or print node content via view + [% node.content(report) %] + + # following methods are soon to be deprecated in favour of views + [% node.toTemplate %] + [% node.childrenToTemplate %] + [% node.allChildrenToTemplate %] + +=head1 PRE-REQUISITES + +This plugin requires that the XML::Parser (2.19 or later) and XML::DOM +(1.27 or later) modules be installed. These are available from CPAN: + + http://www.cpan.org/modules/by-module/XML + +Note that the XML::DOM module is now distributed as part of the +'libxml-enno' bundle. + +=head1 DESCRIPTION + +This is a Template Toolkit plugin interfacing to the XML::DOM module. +The plugin loads the XML::DOM module and creates an XML::DOM::Parser +object which is stored internally. The parse() method can then be +called on the plugin to parse an XML stream into a DOM document. + + [% USE dom = XML.DOM %] + [% doc = dom.parse('/tmp/myxmlfile') %] + +NOTE: earlier versions of this XML::DOM plugin expected a filename to +be passed as an argument to the constructor. This is no longer +supported due to the fact that it caused a serious memory leak. We +apologise for the inconvenience but must insist that you change your +templates as shown: + + # OLD STYLE: now fails with a warning + [% USE dom = XML.DOM('tmp/myxmlfile') %] + + # NEW STYLE: do this instead + [% USE dom = XML.DOM %] + [% doc = dom.parse('tmp/myxmlfile') %] + +The root of the problem lies in XML::DOM creating massive circular +references in the object models it constructs. The dispose() method +must be called on each document to release the memory that it would +otherwise hold indefinately. The XML::DOM plugin object (i.e. 'dom' +in these examples) acts as a sentinel for the documents it creates +('doc' and any others). When the plugin object goes out of scope at +the end of the current template, it will automatically call dispose() +on any documents that it has created. Note that if you dispose of the +the plugin object before the end of the block (i.e. by assigning a +new value to the 'dom' variable) then the documents will also be +disposed at that point and should not be used thereafter. + + [% USE dom = XML.DOM %] + [% doc = dom.parse('/tmp/myfile') %] + [% dom = 'new value' %] # releases XML.DOM plugin and calls + # dispose() on 'doc', so don't use it! + +Any template processing parameters (see toTemplate() method and +friends, below) can be specified with the constructor and will be used +to define defaults for the object. + + [% USE dom = XML.DOM(prefix => 'theme1/') %] + +The plugin constructor will also accept configuration options destined +for the XML::Parser object: + + [% USE dom = XML.DOM(ProtocolEncoding => 'ISO-8859-1') %] + +=head1 METHODS + +=head2 parse() + +The parse() method accepts a positional parameter which contains a filename +or XML string. It is assumed to be a filename unless it contains a E<lt> +character. + + [% xmlfile = '/tmp/foo.xml' %] + [% doc = dom.parse(xmlfile) %] + + [% xmltext = BLOCK %] + <xml> + <blah><etc/></blah> + ... + </xml> + [% END %] + [% doc = dom.parse(xmltext) %] + +The named parameters 'file' (or 'filename') and 'text' (or 'xml') can also +be used: + + [% doc = dom.parse(file = xmlfile) %] + [% doc = dom.parse(text = xmltext) %] + +The parse() method returns an instance of the XML::DOM::Document object +representing the parsed document in DOM form. You can then call any +XML::DOM methods on the document node and other nodes that its methods +may return. See L<XML::DOM> for full details. + + [% FOREACH node = doc.getElementsByTagName('CODEBASE') %] + * [% node.getAttribute('href') %] + [% END %] + +This plugin also provides an AUTOLOAD method for XML::DOM::Node which +calls getAttribute() for any undefined methods. Thus, you can use the +short form of + + [% node.attrib %] + +in place of + + [% node.getAttribute('attrib') %] + +=head2 toTemplate() + +B<NOTE: This method will soon be deprecated in favour of the VIEW based +approach desribed below.> + +This method will process a template for the current node on which it is +called. The template name is constructed from the node TagName with any +optional 'prefix' and/or 'suffix' options applied. A 'default' template +can be named to be used when the specific template cannot be found. The +node object is available to the template as the 'node' variable. + +Thus, for this XML fragment: + + <page title="Hello World!"> + ... + </page> + +and this template definition: + + [% BLOCK page %] + Page: [% node.title %] + [% END %] + +the output of calling toTemplate() on the E<lt>pageE<gt> node would be: + + Page: Hello World! + +=head2 childrenToTemplate() + +B<NOTE: This method will soon be deprecated in favour of the VIEW based +approach desribed below.> + +Effectively calls toTemplate() for the current node and then for each of +the node's children. By default, the parent template is processed first, +followed by each of the children. The 'children' closure can be called +from within the parent template to have them processed and output +at that point. This then suppresses the children from being processed +after the parent template. + +Thus, for this XML fragment: + + <foo> + <bar id="1"/> + <bar id="2"/> + </foo> + +and these template definitions: + + [% BLOCK foo %] + start of foo + end of foo + [% END %] + + [% BLOCK bar %] + bar [% node.id %] + [% END %] + +the output of calling childrenToTemplate() on the parent E<lt>fooE<gt> node +would be: + + start of foo + end of foo + bar 1 + bar 2 + +Adding a call to [% children %] in the 'foo' template: + + [% BLOCK foo %] + start of foo + [% children %] + end of foo + [% END %] + +then creates output as: + + start of foo + bar 1 + bar 2 + end of foo + +The 'children' closure can also be called as a method of the node, if you +prefer: + + [% BLOCK foo %] + start of foo + [% node.children %] + end of foo + [% END %] + +The 'prune' closure is also defined and can be called as [% prune %] or +[% node.prune %]. It prunes the currrent node, preventing any descendants +from being further processed. + + [% BLOCK anynode %] + [% node.toString; node.prune %] + [% END %] + +=head2 allChildrenToTemplate() + +B<NOTE: This method will soon be deprecated in favour of the VIEW based +approach desribed below.> + +Similar to childrenToTemplate() but processing all descendants (i.e. children +of children and so on) recursively. This is identical to calling the +childrenToTemplate() method with the 'deep' flag set to any true value. + +=head1 PRESENTING DOM NODES USING VIEWS + +You can define a VIEW to present all or part of a DOM tree by automatically +mapping elements onto templates. Consider a source document like the +following: + + <report> + <section title="Introduction"> + <p> + Blah blah. + <ul> + <li>Item 1</li> + <li>item 2</li> + </ul> + </p> + </section> + <section title="The Gory Details"> + ... + </section> + </report> + +We can load it up via the XML::DOM plugin and fetch the node for the +E<lt>reportE<gt> element. + + [% USE dom = XML.DOM; + doc = dom.parse(file => filename); + report = doc.getElementsByTagName('report') + %] + +We can then define a VIEW as follows to present this document fragment in +a particular way. The L<Template::Manual::Views> documentation +contains further details on the VIEW directive and various configuration +options it supports. + + [% VIEW report_view notfound='xmlstring' %] + # handler block for a <report>...</report> element + [% BLOCK report %] + [% item.content(view) %] + [% END %] + + # handler block for a <section title="...">...</section> element + [% BLOCK section %] + <h1>[% item.title %]</h1> + [% item.content(view) %] + [% END %] + + # default template block converts item to string representation + [% BLOCK xmlstring; item.toString; END %] + + # block to generate simple text + [% BLOCK text; item; END %] + [% END %] + +Each BLOCK defined within the VIEW represents a presentation style for +a particular element or elements. The current node is available via the +'item' variable. Elements that contain other content can generate it +according to the current view by calling [% item.content(view) %]. +Elements that don't have a specific template defined are mapped to the +'xmlstring' template via the 'notfound' parameter specified in the VIEW +header. This replicates the node as an XML string, effectively allowing +general XML/XHTML markup to be passed through unmodified. + +To present the report node via the view, we simply call: + + [% report_view.print(report) %] + +The output from the above example would look something like this: + + <h1>Introduction</h1> + <p> + Blah blah. + <ul> + <li>Item 1</li> + <li>item 2</li> + </ul> + </p> + + <h1>The Gory Details</h1> + ... + +To print just the content of the report node (i.e. don't process the +'report' template for the report node), you can call: + + [% report.content(report_view) %] + +=head1 AUTHORS + +This plugin module was written by Andy Wardley E<lt>abw@wardley.orgE<gt> +and Simon Matthews E<lt>sam@knowledgepool.comE<gt>. + +The XML::DOM module is by Enno Derksen E<lt>enno@att.comE<gt> and Clark +Cooper E<lt>coopercl@sch.ge.comE<gt>. It extends the the XML::Parser +module, also by Clark Cooper which itself is built on James Clark's expat +library. + +=head1 VERSION + +2.6, distributed as part of the +Template Toolkit version 2.13, released on 30 January 2004. + + + +=head1 HISTORY + +Version 2.5 : updated for use with version 1.27 of the XML::DOM module. + +=over 4 + +=item * + +XML::DOM 1.27 now uses array references as the underlying data type +for DOM nodes instead of hash array references. User data is now +bound to the _UserData node entry instead of being forced directly +into the node hash. + +=back + +=head1 BUGS + +The childrenToTemplate() and allChildrenToTemplate() methods can easily +slip into deep recursion. + +The 'verbose' and 'nospace' options are not documented. They may +change in the near future. + +=head1 COPYRIGHT + +Copyright (C) 2000-2001 Andy Wardley, Simon Matthews. All Rights Reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Template::Plugin|Template::Plugin>, L<XML::DOM|XML::DOM>, L<XML::Parser|XML::Parser> + diff --git a/lib/Template/Plugin/XML/RSS.pm b/lib/Template/Plugin/XML/RSS.pm new file mode 100644 index 0000000..32da7d8 --- /dev/null +++ b/lib/Template/Plugin/XML/RSS.pm @@ -0,0 +1,194 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::XML::RSS +# +# DESCRIPTION +# +# Template Toolkit plugin which interfaces to Jonathan Eisenzopf's XML::RSS +# module. RSS is the Rich Site Summary format. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: RSS.pm,v 2.64 2004/01/13 16:21:50 abw Exp $ +# +#============================================================================ + +package Template::Plugin::XML::RSS; + +require 5.004; + +use strict; +use vars qw( $VERSION ); +use base qw( Template::Plugin ); +use Template::Plugin; +use XML::RSS; + +$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); + +sub load { + return $_[0]; +} + +sub new { + my ($class, $context, $filename) = @_; + + return $class->fail('No filename specified') + unless $filename; + + my $rss = XML::RSS->new + or return $class->fail('failed to create XML::RSS'); + + # Attempt to determine if $filename is an XML string or + # a filename. Based on code from the XML.XPath plugin. + eval { + if ($filename =~ /\</) { + $rss->parse($filename); + } + else { + $rss->parsefile($filename) + } + } and not $@ + or return $class->fail("failed to parse $filename: $@"); + + return $rss; +} + +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::XML::RSS - Plugin interface to XML::RSS + +=head1 SYNOPSIS + + [% USE news = XML.RSS($filename) %] + + [% FOREACH item = news.items %] + [% item.title %] + [% item.link %] + [% END %] + +=head1 PRE-REQUISITES + +This plugin requires that the XML::Parser and XML::RSS modules be +installed. These are available from CPAN: + + http://www.cpan.org/modules/by-module/XML + +=head1 DESCRIPTION + +This Template Toolkit plugin provides a simple interface to the +XML::RSS module. + + [% USE news = XML.RSS('mysite.rdf') %] + +It creates an XML::RSS object, which is then used to parse the RSS +file specified as a parameter in the USE directive. A reference to +the XML::RSS object is then returned. + +An RSS (Rich Site Summary) file is typically used to store short news +'headlines' describing different links within a site. This example is +extracted from http://slashdot.org/slashdot.rdf. + + <?xml version="1.0"?><rdf:RDF + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns="http://my.netscape.com/rdf/simple/0.9/"> + + <channel> + <title>Slashdot:News for Nerds. Stuff that Matters.</title> + <link>http://slashdot.org</link> + <description>News for Nerds. Stuff that Matters</description> + </channel> + + <image> + <title>Slashdot</title> + <url>http://slashdot.org/images/slashdotlg.gif</url> + <link>http://slashdot.org</link> + </image> + + <item> + <title>DVD CCA Battle Continues Next Week</title> + <link>http://slashdot.org/article.pl?sid=00/01/12/2051208</link> + </item> + + <item> + <title>Matrox to fund DRI Development</title> + <link>http://slashdot.org/article.pl?sid=00/01/13/0718219</link> + </item> + + <item> + <title>Mike Shaver Leaving Netscape</title> + <link>http://slashdot.org/article.pl?sid=00/01/13/0711258</link> + </item> + + </rdf:RDF> + +The attributes of the channel and image elements can be retrieved directly +from the plugin object using the familiar dotted compound notation: + + [% news.channel.title %] + [% news.channel.link %] + [% news.channel.etc... %] + + [% news.image.title %] + [% news.image.url %] + [% news.image.link %] + [% news.image.etc... %] + +The list of news items can be retrieved using the 'items' method: + + [% FOREACH item = news.items %] + [% item.title %] + [% item.link %] + [% END %] + +=head1 AUTHORS + +This plugin was written by Andy Wardley E<lt>abw@wardley.orgE<gt>, +inspired by an article in Web Techniques by Randal Schwartz +E<lt>merlyn@stonehenge.comE<gt>. + +The XML::RSS module, which implements all of the functionality that +this plugin delegates to, was written by Jonathan Eisenzopf +E<lt>eisen@pobox.comE<gt>. + +=head1 VERSION + +2.64, 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<Template::Plugin|Template::Plugin>, L<XML::RSS|XML::RSS>, L<XML::Parser|XML::Parser> + diff --git a/lib/Template/Plugin/XML/Simple.pm b/lib/Template/Plugin/XML/Simple.pm new file mode 100644 index 0000000..aaa4479 --- /dev/null +++ b/lib/Template/Plugin/XML/Simple.pm @@ -0,0 +1,124 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::XML::Simple +# +# DESCRIPTION +# Template Toolkit plugin interfacing to the XML::Simple.pm module. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2001 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: Simple.pm,v 2.63 2004/01/13 16:21:50 abw Exp $ +# +#============================================================================ + +package Template::Plugin::XML::Simple; + +require 5.004; + +use strict; +use Template::Plugin; +use XML::Simple; + +use base qw( Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.63 $ =~ /(\d+)\.(\d+)/); + + +#------------------------------------------------------------------------ +# new($context, $file_or_text, \%config) +#------------------------------------------------------------------------ + +sub new { + my $class = shift; + my $context = shift; + my $input = shift; + my $args = ref $_[-1] eq 'HASH' ? pop(@_) : { }; + + XMLin($input, %$args); +} + + + +#------------------------------------------------------------------------ +# _throw($errmsg) +# +# Raise a Template::Exception of type XML.Simple via die(). +#------------------------------------------------------------------------ + +sub _throw { + my ($self, $error) = @_; + die (Template::Exception->new('XML.Simple', $error)); +} + + +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::XML::Simple - Plugin interface to XML::Simple + +=head1 SYNOPSIS + + # load plugin and specify XML file to parse + [% USE xml = XML.Simple(xml_file_or_text) %] + +=head1 DESCRIPTION + +This is a Template Toolkit plugin interfacing to the XML::Simple module. + +=head1 PRE-REQUISITES + +This plugin requires that the XML::Parser and XML::Simple modules be +installed. These are available from CPAN: + + http://www.cpan.org/modules/by-module/XML + +=head1 AUTHORS + +This plugin wrapper module was written by Andy Wardley +E<lt>abw@wardley.orgE<gt>. + +The XML::Simple module which implements all the core functionality +was written by Grant McLean E<lt>grantm@web.co.nzE<gt>. + +=head1 VERSION + +2.63, 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<Template::Plugin|Template::Plugin>, L<XML::Simple|XML::Simple>, L<XML::Parser|XML::Parser> + diff --git a/lib/Template/Plugin/XML/Style.pm b/lib/Template/Plugin/XML/Style.pm new file mode 100644 index 0000000..7613f2f --- /dev/null +++ b/lib/Template/Plugin/XML/Style.pm @@ -0,0 +1,357 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::XML::Style +# +# DESCRIPTION +# Template Toolkit plugin which performs some basic munging of XML +# to perform simple stylesheet like transformations. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2001 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +# REVISION +# $Id: Style.pm,v 2.34 2004/01/13 16:21:50 abw Exp $ +# +#============================================================================ + +package Template::Plugin::XML::Style; + +require 5.004; + +use strict; +use Template::Plugin::Filter; + +use base qw( Template::Plugin::Filter ); +use vars qw( $VERSION $DYNAMIC $FILTER_NAME ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.34 $ =~ /(\d+)\.(\d+)/); +$DYNAMIC = 1; +$FILTER_NAME = 'xmlstyle'; + + +#------------------------------------------------------------------------ +# new($context, \%config) +#------------------------------------------------------------------------ + +sub init { + my $self = shift; + my $name = $self->{ _ARGS }->[0] || $FILTER_NAME; + $self->install_filter($name); + return $self; +} + + +sub filter { + my ($self, $text, $args, $config) = @_; + + # munge start tags + $text =~ s/ < ([\w\.\:]+) ( \s+ [^>]+ )? > + / $self->start_tag($1, $2, $config) + /gsex; + + # munge end tags + $text =~ s/ < \/ ([\w\.\:]+) > + / $self->end_tag($1, $config) + /gsex; + + return $text; + +} + + +sub start_tag { + my ($self, $elem, $textattr, $config) = @_; + $textattr ||= ''; + my ($pre, $post); + + # look for an element match in the stylesheet + my $match = $config->{ $elem } + || $self->{ _CONFIG }->{ $elem } + || return "<$elem$textattr>"; + + # merge element attributes into copy of stylesheet attributes + my $attr = { %{ $match->{ attributes } || { } } }; + while ($textattr =~ / \s* ([\w\.\:]+) = " ([^"]+) " /gsx ) { + $attr->{ $1 } = $2; + } + $textattr = join(' ', map { "$_=\"$attr->{$_}\"" } keys %$attr); + $textattr = " $textattr" if $textattr; + + $elem = $match->{ element } || $elem; + $pre = $match->{ pre_start } || ''; + $post = $match->{ post_start } || ''; + + return "$pre<$elem$textattr>$post"; +} + + +sub end_tag { + my ($self, $elem, $config) = @_; + my ($pre, $post); + + # look for an element match in the stylesheet + my $match = $config->{ $elem } + || $self->{ _CONFIG }->{ $elem } + || return "</$elem>"; + + $elem = $match->{ element } || $elem; + $pre = $match->{ pre_end } || ''; + $post = $match->{ post_end } || ''; + + return "$pre</$elem>$post"; +} + + +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::XML::Style - Simple XML stylesheet transfomations + +=head1 SYNOPSIS + + [% USE xmlstyle + table = { + attributes = { + border = 0 + cellpadding = 4 + cellspacing = 1 + } + } + %] + + [% FILTER xmlstyle %] + <table> + <tr> + <td>Foo</td> <td>Bar</td> <td>Baz</td> + </tr> + </table> + [% END %] + +=head1 DESCRIPTION + +This plugin defines a filter for performing simple stylesheet based +transformations of XML text. + +Named parameters are used to define those XML elements which require +transformation. These may be specified with the USE directive when +the plugin is loaded and/or with the FILTER directive when the plugin +is used. + +This example shows how the default attributes C<border="0"> and +C<cellpadding="4"> can be added to E<lt>tableE<gt> elements. + + [% USE xmlstyle + table = { + attributes = { + border = 0 + cellpadding = 4 + } + } + %] + + [% FILTER xmlstyle %] + <table> + ... + </table> + [% END %] + +This produces the output: + + <table border="0" cellpadding="4"> + ... + </table> + +Parameters specified within the USE directive are applied automatically each +time the C<xmlstyle> FILTER is used. Additional parameters passed to the +FILTER directive apply for only that block. + + [% USE xmlstyle + table = { + attributes = { + border = 0 + cellpadding = 4 + } + } + %] + + [% FILTER xmlstyle + tr = { + attributes = { + valign="top" + } + } + %] + <table> + <tr> + ... + </tr> + </table> + [% END %] + +Of course, you may prefer to define your stylesheet structures once and +simply reference them by name. Passing a hash reference of named parameters +is just the same as specifying the named parameters as far as the Template +Toolkit is concerned. + + [% style_one = { + table = { ... } + tr = { ... } + } + style_two = { + table = { ... } + td = { ... } + } + style_three = { + th = { ... } + tv = { ... } + } + %] + + [% USE xmlstyle style_one %] + + [% FILTER xmlstyle style_two %] + # style_one and style_two applied here + [% END %] + + [% FILTER xmlstyle style_three %] + # style_one and style_three applied here + [% END %] + +Any attributes defined within the source tags will override those specified +in the style sheet. + + [% USE xmlstyle + div = { attributes = { align = 'left' } } + %] + + + [% FILTER xmlstyle %] + <div>foo</div> + <div align="right">bar</div> + [% END %] + +The output produced is: + + <div align="left">foo</div> + <div align="right">bar</div> + +The filter can also be used to change the element from one type to another. + + [% FILTER xmlstyle + th = { + element = 'td' + attributes = { bgcolor='red' } + } + %] + <tr> + <th>Heading</th> + </tr> + <tr> + <td>Value</td> + </tr> + [% END %] + +The output here is as follows. Notice how the end tag C<E<lt>/thE<gt>> is +changed to C<E<lt>/tdE<gt>> as well as the start tag. + + <tr> + <td bgcolor="red">Heading</td> + </tr> + <tr> + <td>Value</td> + </tr> + +You can also define text to be added immediately before or after the +start or end tags. For example: + + [% FILTER xmlstyle + table = { + pre_start = '<div align="center">' + post_end = '</div>' + } + th = { + element = 'td' + attributes = { bgcolor='red' } + post_start = '<b>' + pre_end = '</b>' + } + %] + <table> + <tr> + <th>Heading</th> + </tr> + <tr> + <td>Value</td> + </tr> + </table> + [% END %] + +The output produced is: + + <div align="center"> + <table> + <tr> + <td bgcolor="red"><b>Heading</b></td> + </tr> + <tr> + <td>Value</td> + </tr> + </table> + </div> + +=head1 AUTHOR + +Andy Wardley E<lt>abw@andywardley.comE<gt> + +L<http://www.andywardley.com/|http://www.andywardley.com/> + + + + +=head1 VERSION + +2.34, 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<Template::Plugin|Template::Plugin> + +=cut + +# Local Variables: +# mode: perl +# perl-indent-level: 4 +# indent-tabs-mode: nil +# End: +# +# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Plugin/XML/XPath.pm b/lib/Template/Plugin/XML/XPath.pm new file mode 100644 index 0000000..adf9292 --- /dev/null +++ b/lib/Template/Plugin/XML/XPath.pm @@ -0,0 +1,284 @@ +#============================================================= -*-Perl-*- +# +# Template::Plugin::XML::XPath +# +# DESCRIPTION +# +# Template Toolkit plugin interfacing to the XML::XPath.pm module. +# +# AUTHOR +# Andy Wardley <abw@kfs.org> +# +# COPYRIGHT +# Copyright (C) 2000 Andy Wardley. All Rights Reserved. +# +# This module is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# +#---------------------------------------------------------------------------- +# +# $Id: XPath.pm,v 2.69 2004/01/13 16:21:50 abw Exp $ +# +#============================================================================ + +package Template::Plugin::XML::XPath; + +require 5.004; + +use strict; +use Template::Exception; +use Template::Plugin; +use XML::XPath; + +use base qw( Template::Plugin ); +use vars qw( $VERSION ); + +$VERSION = sprintf("%d.%02d", q$Revision: 2.69 $ =~ /(\d+)\.(\d+)/); + + +#------------------------------------------------------------------------ +# new($context, \%config) +# +# Constructor method for XML::XPath plugin. Creates an XML::XPath +# object and initialises plugin configuration. +#------------------------------------------------------------------------ + +sub new { + my $class = shift; + my $context = shift; + my $args = ref $_[-1] eq 'HASH' ? pop(@_) : { }; + my ($content, $about); + + # determine the input source from a positional parameter (may be a + # filename or XML text if it contains a '<' character) or by using + # named parameters which may specify one of 'file', 'filename', 'text' + # or 'xml' + + if ($content = shift) { + if ($content =~ /\</) { + $about = 'xml text'; + $args->{ xml } = $content; + } + else { + $about = "xml file $content"; + $args->{ filename } = $content; + } + } + elsif ($content = $args->{ text } || $args->{ xml }) { + $about = 'xml text'; + $args->{ xml } = $content; + } + elsif ($content = $args->{ file } || $args->{ filename }) { + $about = "xml file $content"; + $args->{ filename } = $content; + } + else { + return $class->_throw('no filename or xml text specified'); + } + + return XML::XPath->new(%$args) + or $class->_throw("failed to create XML::XPath::Parser\n"); +} + + + +#------------------------------------------------------------------------ +# _throw($errmsg) +# +# Raise a Template::Exception of type XML.XPath via die(). +#------------------------------------------------------------------------ + +sub _throw { + my ($self, $error) = @_; +# print STDERR "about to throw $error\n"; + die (Template::Exception->new('XML.XPath', $error)); +} + + +#======================================================================== +package XML::XPath::Node::Element; +#======================================================================== + +#------------------------------------------------------------------------ +# present($view) +# +# Method to present an element node via a view. +#------------------------------------------------------------------------ + +sub present { + my ($self, $view) = @_; + $view->view($self->getName(), $self); +} + +sub content { + my ($self, $view) = @_; + my $output = ''; + foreach my $node (@{ $self->getChildNodes }) { + $output .= $node->present($view); + } + return $output; +} + +#---------------------------------------------------------------------- +# starttag(), endtag() +# +# Methods to output the start & end tag, e.g. <foo bar="baz"> & </foo> +#---------------------------------------------------------------------- + +sub starttag { + my ($self) = @_; + my $output = "<". $self->getName(); + foreach my $attr ($self->getAttributes()) + { + $output .= $attr->toString(); + } + $output .= ">"; + return $output; +} + +sub endtag { + my ($self) = @_; + return "</". $self->getName() . ">"; +} + +#======================================================================== +package XML::XPath::Node::Text; +#======================================================================== + +#------------------------------------------------------------------------ +# present($view) +# +# Method to present a text node via a view. +#------------------------------------------------------------------------ + +sub present { + my ($self, $view) = @_; + $view->view('text', $self->string_value); +} + + +#======================================================================== +package XML::XPath::Node::Comment; +#======================================================================== + +sub present { return ''; } +sub starttag { return ''; } +sub endtag { return ''; } + + +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::XML::XPath - Plugin interface to XML::XPath + +=head1 SYNOPSIS + + # load plugin and specify XML file to parse + [% USE xpath = XML.XPath(xmlfile) %] + [% USE xpath = XML.XPath(file => xmlfile) %] + [% USE xpath = XML.XPath(filename => xmlfile) %] + + # load plugin and specify XML text to parse + [% USE xpath = XML.XPath(xmltext) %] + [% USE xpath = XML.XPath(xml => xmltext) %] + [% USE xpath = XML.XPath(text => xmltext) %] + + # then call any XPath methods (see XML::XPath docs) + [% FOREACH page = xpath.findnodes('/html/body/page') %] + [% page.getAttribute('title') %] + [% END %] + + # define VIEW to present node(s) + [% VIEW repview notfound='xmlstring' %] + # handler block for a <report>...</report> element + [% BLOCK report %] + [% item.content(view) %] + [% END %] + + # handler block for a <section title="...">...</section> element + [% BLOCK section %] + <h1>[% item.getAttribute('title') | html %]</h1> + [% item.content(view) %] + [% END %] + + # default template block passes tags through and renders + # out the children recursivly + [% BLOCK xmlstring; + item.starttag; item.content(view); item.endtag; + END %] + + # block to generate simple text + [% BLOCK text; item | html; END %] + [% END %] + + # now present node (and children) via view + [% repview.print(page) %] + + # or print node content via view + [% page.content(repview) %] + +=head1 PRE-REQUISITES + +This plugin requires that the XML::Parser and XML::XPath modules be +installed. These are available from CPAN: + + http://www.cpan.org/modules/by-module/XML + +=head1 DESCRIPTION + +This is a Template Toolkit plugin interfacing to the XML::XPath module. + +All methods implemented by the XML::XPath modules are available. In +addition, the XML::XPath::Node::Element module implements +present($view) and content($view) methods method for seamless +integration with Template Toolkit VIEWs. The XML::XPath::Node::Text +module is also adorned with a present($view) method which presents +itself via the view using the 'text' template. + +To aid the reconstruction of XML, methods starttag and endtag are +added to XML::XPath::Node::Element which return the start and +end tag for that element. This means that you can easily do: + + [% item.starttag %][% item.content(view) %][% item.endtag %] + +To render out the start tag, followed by the content rendered in the +view "view", followed by the end tag. + +=head1 AUTHORS + +This plugin module was written by Andy Wardley E<lt>abw@wardley.orgE<gt>. + +The XML::XPath module is by Matt Sergeant E<lt>matt@sergeant.orgE<gt>. + +=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<Template::Plugin|Template::Plugin>, L<XML::XPath|XML::XPath>, L<XML::Parser|XML::Parser> + |
