diff options
| author | Andreas Brachold <vdr07@deltab.de> | 2007-11-11 06:55:13 +0000 |
|---|---|---|
| committer | Andreas Brachold <vdr07@deltab.de> | 2007-11-11 06:55:13 +0000 |
| commit | 3282be229999dc36c197b264d63063a18d136331 (patch) | |
| tree | 98a42db29d955b39e7bed1b599fdcc56c3a29de9 /lib/Template/Provider.pm | |
| parent | cfdd733c17cfa4f1a43b827a656e9e53cc2524ac (diff) | |
| download | xxv-3282be229999dc36c197b264d63063a18d136331.tar.gz xxv-3282be229999dc36c197b264d63063a18d136331.tar.bz2 | |
* Update installation list with required modules
* Remove unused/doubled provided external perl moduls
Diffstat (limited to 'lib/Template/Provider.pm')
| -rw-r--r-- | lib/Template/Provider.pm | 1449 |
1 files changed, 0 insertions, 1449 deletions
diff --git a/lib/Template/Provider.pm b/lib/Template/Provider.pm deleted file mode 100644 index 0826a18..0000000 --- a/lib/Template/Provider.pm +++ /dev/null @@ -1,1449 +0,0 @@ -#============================================================= -*-Perl-*- -# -# Template::Provider -# -# DESCRIPTION -# This module implements a class which handles the loading, compiling -# and caching of templates. Multiple Template::Provider objects can -# be stacked and queried in turn to effect a Chain-of-Command between -# them. A provider will attempt to return the requested template, -# an error (STATUS_ERROR) or decline to provide the template -# (STATUS_DECLINE), allowing subsequent providers to attempt to -# deliver it. See 'Design Patterns' for further details. -# -# AUTHOR -# Andy Wardley <abw@wardley.org> -# -# COPYRIGHT -# Copyright (C) 1996-2003 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. -# -# TODO: -# * optional provider prefix (e.g. 'http:') -# * fold ABSOLUTE and RELATIVE test cases into one regex? -# -#---------------------------------------------------------------------------- -# -# $Id: Provider.pm,v 2.79 2004/01/13 16:19:16 abw Exp $ -# -#============================================================================ - -package Template::Provider; - -require 5.004; - -use strict; -use vars qw( $VERSION $DEBUG $ERROR $DOCUMENT $STAT_TTL $MAX_DIRS ); -use base qw( Template::Base ); -use Template::Config; -use Template::Constants; -use Template::Document; -use File::Basename; -use File::Spec; - -$VERSION = sprintf("%d.%02d", q$Revision: 2.79 $ =~ /(\d+)\.(\d+)/); - -# name of document class -$DOCUMENT = 'Template::Document' unless defined $DOCUMENT; - -# maximum time between performing stat() on file to check staleness -$STAT_TTL = 1 unless defined $STAT_TTL; - -# maximum number of directories in an INCLUDE_PATH, to prevent runaways -$MAX_DIRS = 64 unless defined $MAX_DIRS; - -use constant PREV => 0; -use constant NAME => 1; -use constant DATA => 2; -use constant LOAD => 3; -use constant NEXT => 4; -use constant STAT => 5; - -$DEBUG = 0 unless defined $DEBUG; - -#======================================================================== -# -- PUBLIC METHODS -- -#======================================================================== - -#------------------------------------------------------------------------ -# fetch($name) -# -# Returns a compiled template for the name specified by parameter. -# The template is returned from the internal cache if it exists, or -# loaded and then subsequently cached. The ABSOLUTE and RELATIVE -# configuration flags determine if absolute (e.g. '/something...') -# and/or relative (e.g. './something') paths should be honoured. The -# INCLUDE_PATH is otherwise used to find the named file. $name may -# also be a reference to a text string containing the template text, -# or a file handle from which the content is read. The compiled -# template is not cached in these latter cases given that there is no -# filename to cache under. A subsequent call to store($name, -# $compiled) can be made to cache the compiled template for future -# fetch() calls, if necessary. -# -# Returns a compiled template or (undef, STATUS_DECLINED) if the -# template could not be found. On error (e.g. the file was found -# but couldn't be read or parsed), the pair ($error, STATUS_ERROR) -# is returned. The TOLERANT configuration option can be set to -# downgrade any errors to STATUS_DECLINE. -#------------------------------------------------------------------------ - -sub fetch { - my ($self, $name) = @_; - my ($data, $error); - - if (ref $name) { - # $name can be a reference to a scalar, GLOB or file handle - ($data, $error) = $self->_load($name); - ($data, $error) = $self->_compile($data) - unless $error; - $data = $data->{ data } - unless $error; - } - elsif (File::Spec->file_name_is_absolute($name)) { - # absolute paths (starting '/') allowed if ABSOLUTE set - ($data, $error) = $self->{ ABSOLUTE } - ? $self->_fetch($name) - : $self->{ TOLERANT } - ? (undef, Template::Constants::STATUS_DECLINED) - : ("$name: absolute paths are not allowed (set ABSOLUTE option)", - Template::Constants::STATUS_ERROR); - } - elsif ($name =~ m[^\.+/]) { - # anything starting "./" is relative to cwd, allowed if RELATIVE set - ($data, $error) = $self->{ RELATIVE } - ? $self->_fetch($name) - : $self->{ TOLERANT } - ? (undef, Template::Constants::STATUS_DECLINED) - : ("$name: relative paths are not allowed (set RELATIVE option)", - Template::Constants::STATUS_ERROR); - } - else { - # otherwise, it's a file name relative to INCLUDE_PATH - ($data, $error) = $self->{ INCLUDE_PATH } - ? $self->_fetch_path($name) - : (undef, Template::Constants::STATUS_DECLINED); - } - -# $self->_dump_cache() -# if $DEBUG > 1; - - return ($data, $error); -} - - -#------------------------------------------------------------------------ -# store($name, $data) -# -# Store a compiled template ($data) in the cached as $name. -#------------------------------------------------------------------------ - -sub store { - my ($self, $name, $data) = @_; - $self->_store($name, { - data => $data, - load => 0, - }); -} - - -#------------------------------------------------------------------------ -# load($name) -# -# Load a template without parsing/compiling it, suitable for use with -# the INSERT directive. There's some duplication with fetch() and at -# some point this could be reworked to integrate them a little closer. -#------------------------------------------------------------------------ - -sub load { - my ($self, $name) = @_; - my ($data, $error); - my $path = $name; - - if (File::Spec->file_name_is_absolute($name)) { - # absolute paths (starting '/') allowed if ABSOLUTE set - $error = "$name: absolute paths are not allowed (set ABSOLUTE option)" - unless $self->{ ABSOLUTE }; - } - elsif ($name =~ m[^\.+/]) { - # anything starting "./" is relative to cwd, allowed if RELATIVE set - $error = "$name: relative paths are not allowed (set RELATIVE option)" - unless $self->{ RELATIVE }; - } - else { - INCPATH: { - # otherwise, it's a file name relative to INCLUDE_PATH - my $paths = $self->paths() - || return ($self->error(), Template::Constants::STATUS_ERROR); - - foreach my $dir (@$paths) { - $path = "$dir/$name"; - last INCPATH - if -f $path; - } - undef $path; # not found - } - } - - if (defined $path && ! $error) { - local $/ = undef; # slurp files in one go - local *FH; - if (open(FH, $path)) { - $data = <FH>; - close(FH); - } - else { - $error = "$name: $!"; - } - } - - if ($error) { - return $self->{ TOLERANT } - ? (undef, Template::Constants::STATUS_DECLINED) - : ($error, Template::Constants::STATUS_ERROR); - } - elsif (! defined $path) { - return (undef, Template::Constants::STATUS_DECLINED); - } - else { - return ($data, Template::Constants::STATUS_OK); - } -} - - - -#------------------------------------------------------------------------ -# include_path(\@newpath) -# -# Accessor method for the INCLUDE_PATH setting. If called with an -# argument, this method will replace the existing INCLUDE_PATH with -# the new value. -#------------------------------------------------------------------------ - -sub include_path { - my ($self, $path) = @_; - $self->{ INCLUDE_PATH } = $path if $path; - return $self->{ INCLUDE_PATH }; -} - - -#------------------------------------------------------------------------ -# paths() -# -# Evaluates the INCLUDE_PATH list, ignoring any blank entries, and -# calling and subroutine or object references to return dynamically -# generated path lists. Returns a reference to a new list of paths -# or undef on error. -#------------------------------------------------------------------------ - -sub paths { - my $self = shift; - my @ipaths = @{ $self->{ INCLUDE_PATH } }; - my (@opaths, $dpaths, $dir); - my $count = $MAX_DIRS; - - while (@ipaths && --$count) { - $dir = shift @ipaths || next; - - # $dir can be a sub or object ref which returns a reference - # to a dynamically generated list of search paths. - - if (ref $dir eq 'CODE') { - eval { $dpaths = &$dir() }; - if ($@) { - chomp $@; - return $self->error($@); - } - unshift(@ipaths, @$dpaths); - next; - } - elsif (UNIVERSAL::can($dir, 'paths')) { - $dpaths = $dir->paths() - || return $self->error($dir->error()); - unshift(@ipaths, @$dpaths); - next; - } - else { - push(@opaths, $dir); - } - } - return $self->error("INCLUDE_PATH exceeds $MAX_DIRS directories") - if @ipaths; - - return \@opaths; -} - - -#------------------------------------------------------------------------ -# DESTROY -# -# The provider cache is implemented as a doubly linked list which Perl -# cannot free by itself due to the circular references between NEXT <=> -# PREV items. This cleanup method walks the list deleting all the NEXT/PREV -# references, allowing the proper cleanup to occur and memory to be -# repooled. -#------------------------------------------------------------------------ - -sub DESTROY { - my $self = shift; - my ($slot, $next); - - $slot = $self->{ HEAD }; - while ($slot) { - $next = $slot->[ NEXT ]; - undef $slot->[ PREV ]; - undef $slot->[ NEXT ]; - $slot = $next; - } - undef $self->{ HEAD }; - undef $self->{ TAIL }; -} - - - - -#======================================================================== -# -- PRIVATE METHODS -- -#======================================================================== - -#------------------------------------------------------------------------ -# _init() -# -# Initialise the cache. -#------------------------------------------------------------------------ - -sub _init { - my ($self, $params) = @_; - my $size = $params->{ CACHE_SIZE }; - my $path = $params->{ INCLUDE_PATH } || '.'; - my $cdir = $params->{ COMPILE_DIR } || ''; - my $dlim = $params->{ DELIMITER }; - my $debug; - - # tweak delim to ignore C:/ - unless (defined $dlim) { - $dlim = ($^O eq 'MSWin32') ? ':(?!\\/)' : ':'; - } - - # coerce INCLUDE_PATH to an array ref, if not already so - $path = [ split(/$dlim/, $path) ] - unless ref $path eq 'ARRAY'; - - # don't allow a CACHE_SIZE 1 because it breaks things and the - # additional checking isn't worth it - $size = 2 - if defined $size && ($size == 1 || $size < 0); - - if (defined ($debug = $params->{ DEBUG })) { - $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PROVIDER - | Template::Constants::DEBUG_FLAGS ); - } - else { - $self->{ DEBUG } = $DEBUG; - } - - if ($self->{ DEBUG }) { - local $" = ', '; - $self->debug("creating cache of ", - defined $size ? $size : 'unlimited', - " slots for [ @$path ]"); - } - - # create COMPILE_DIR and sub-directories representing each INCLUDE_PATH - # element in which to store compiled files - if ($cdir) { - -# Stas' hack -# # this is a hack to solve the problem with INCLUDE_PATH using -# # relative dirs -# my $segments = 0; -# for (@$path) { -# my $c = 0; -# $c++ while m|\.\.|g; -# $segments = $c if $c > $segments; -# } -# $cdir .= "/".join "/",('hack') x $segments if $segments; -# - - require File::Path; - foreach my $dir (@$path) { - next if ref $dir; - my $wdir = $dir; - $wdir =~ s[:][]g if $^O eq 'MSWin32'; - $wdir =~ /(.*)/; # untaint - &File::Path::mkpath(File::Spec->catfile($cdir, $1)); - } - } - - $self->{ LOOKUP } = { }; - $self->{ SLOTS } = 0; - $self->{ SIZE } = $size; - $self->{ INCLUDE_PATH } = $path; - $self->{ DELIMITER } = $dlim; - $self->{ COMPILE_DIR } = $cdir; - $self->{ COMPILE_EXT } = $params->{ COMPILE_EXT } || ''; - $self->{ ABSOLUTE } = $params->{ ABSOLUTE } || 0; - $self->{ RELATIVE } = $params->{ RELATIVE } || 0; - $self->{ TOLERANT } = $params->{ TOLERANT } || 0; - $self->{ DOCUMENT } = $params->{ DOCUMENT } || $DOCUMENT; - $self->{ PARSER } = $params->{ PARSER }; - $self->{ DEFAULT } = $params->{ DEFAULT }; -# $self->{ PREFIX } = $params->{ PREFIX }; - $self->{ PARAMS } = $params; - - return $self; -} - - -#------------------------------------------------------------------------ -# _fetch($name) -# -# Fetch a file from cache or disk by specification of an absolute or -# relative filename. No search of the INCLUDE_PATH is made. If the -# file is found and loaded, it is compiled and cached. -#------------------------------------------------------------------------ - -sub _fetch { - my ($self, $name) = @_; - my $size = $self->{ SIZE }; - my ($slot, $data, $error); - - $self->debug("_fetch($name)") if $self->{ DEBUG }; - - my $compiled = $self->_compiled_filename($name); - - if (defined $size && ! $size) { - # caching disabled so load and compile but don't cache - if ($compiled && -f $compiled - && (stat($name))[9] <= (stat($compiled))[9]) { - $data = $self->_load_compiled($compiled); - $error = $self->error() unless $data; - } - else { - ($data, $error) = $self->_load($name); - ($data, $error) = $self->_compile($data, $compiled) - unless $error; - $data = $data->{ data } - unless $error; - } - } - elsif ($slot = $self->{ LOOKUP }->{ $name }) { - # cached entry exists, so refresh slot and extract data - ($data, $error) = $self->_refresh($slot); - $data = $slot->[ DATA ] - unless $error; - } - else { - # nothing in cache so try to load, compile and cache - if ($compiled && -f $compiled - && (stat($name))[9] <= (stat($compiled))[9]) { - $data = $self->_load_compiled($compiled); - $error = $self->error() unless $data; - $self->store($name, $data) unless $error; - } - else { - ($data, $error) = $self->_load($name); - ($data, $error) = $self->_compile($data, $compiled) - unless $error; - $data = $self->_store($name, $data) - unless $error; - } - } - - return ($data, $error); -} - - -#------------------------------------------------------------------------ -# _fetch_path($name) -# -# Fetch a file from cache or disk by specification of an absolute cache -# name (e.g. 'header') or filename relative to one of the INCLUDE_PATH -# directories. If the file isn't already cached and can be found and -# loaded, it is compiled and cached under the full filename. -#------------------------------------------------------------------------ - -sub _fetch_path { - my ($self, $name) = @_; - my ($size, $compext, $compdir) = - @$self{ qw( SIZE COMPILE_EXT COMPILE_DIR ) }; - my ($dir, $paths, $path, $compiled, $slot, $data, $error); - local *FH; - - $self->debug("_fetch_path($name)") if $self->{ DEBUG }; - - # caching is enabled if $size is defined and non-zero or undefined - my $caching = (! defined $size || $size); - - INCLUDE: { - - # the template may have been stored using a non-filename name - if ($caching && ($slot = $self->{ LOOKUP }->{ $name })) { - # cached entry exists, so refresh slot and extract data - ($data, $error) = $self->_refresh($slot); - $data = $slot->[ DATA ] - unless $error; - last INCLUDE; - } - - $paths = $self->paths() || do { - $error = Template::Constants::STATUS_ERROR; - $data = $self->error(); - last INCLUDE; - }; - - # search the INCLUDE_PATH for the file, in cache or on disk - foreach $dir (@$paths) { - $path = File::Spec->catfile($dir, $name); - - $self->debug("searching path: $path\n") if $self->{ DEBUG }; - - if ($caching && ($slot = $self->{ LOOKUP }->{ $path })) { - # cached entry exists, so refresh slot and extract data - ($data, $error) = $self->_refresh($slot); - $data = $slot->[ DATA ] - unless $error; - last INCLUDE; - } - elsif (-f $path) { - $compiled = $self->_compiled_filename($path) - if $compext || $compdir; - - if ($compiled && -f $compiled - && (stat($path))[9] <= (stat($compiled))[9]) { - if ($data = $self->_load_compiled($compiled)) { - # store in cache - $data = $self->store($path, $data); - $error = Template::Constants::STATUS_OK; - last INCLUDE; - } - else { - warn($self->error(), "\n"); - } - } - # $compiled is set if an attempt to write the compiled - # template to disk should be made - - ($data, $error) = $self->_load($path, $name); - ($data, $error) = $self->_compile($data, $compiled) - unless $error; - $data = $self->_store($path, $data) - unless $error || ! $caching; - $data = $data->{ data } if ! $caching; - # all done if $error is OK or ERROR - last INCLUDE if ! $error - || $error == Template::Constants::STATUS_ERROR; - } - } - # template not found, so look for a DEFAULT template - my $default; - if (defined ($default = $self->{ DEFAULT }) && $name ne $default) { - $name = $default; - redo INCLUDE; - } - ($data, $error) = (undef, Template::Constants::STATUS_DECLINED); - } # INCLUDE - - return ($data, $error); -} - - - -sub _compiled_filename { - my ($self, $file) = @_; - my ($compext, $compdir) = @$self{ qw( COMPILE_EXT COMPILE_DIR ) }; - my ($path, $compiled); - - return undef - unless $compext || $compdir; - - $path = $file; - $path =~ /^(.+)$/s or die "invalid filename: $path"; - $path =~ s[:][]g if $^O eq 'MSWin32'; - - $compiled = "$path$compext"; - $compiled = File::Spec->catfile($compdir, $compiled) if length $compdir; - - return $compiled; -} - - -sub _load_compiled { - my ($self, $file) = @_; - my $compiled; - - # load compiled template via require(); we zap any - # %INC entry to ensure it is reloaded (we don't - # want 1 returned by require() to say it's in memory) - delete $INC{ $file }; - eval { $compiled = require $file; }; - return $@ - ? $self->error("compiled template $compiled: $@") - : $compiled; -} - - - -#------------------------------------------------------------------------ -# _load($name, $alias) -# -# Load template text from a string ($name = scalar ref), GLOB or file -# handle ($name = ref), or from an absolute filename ($name = scalar). -# Returns a hash array containing the following items: -# name filename or $alias, if provided, or 'input text', etc. -# text template text -# time modification time of file, or current time for handles/strings -# load time file was loaded (now!) -# -# On error, returns ($error, STATUS_ERROR), or (undef, STATUS_DECLINED) -# if TOLERANT is set. -#------------------------------------------------------------------------ - -sub _load { - my ($self, $name, $alias) = @_; - my ($data, $error); - my $tolerant = $self->{ TOLERANT }; - my $now = time; - local $/ = undef; # slurp files in one go - local *FH; - - $alias = $name unless defined $alias or ref $name; - - $self->debug("_load($name, ", defined $alias ? $alias : '<no alias>', - ')') if $self->{ DEBUG }; - - LOAD: { - if (ref $name eq 'SCALAR') { - # $name can be a SCALAR reference to the input text... - $data = { - name => defined $alias ? $alias : 'input text', - text => $$name, - time => $now, - load => 0, - }; - } - elsif (ref $name) { - # ...or a GLOB or file handle... - my $text = <$name>; - $data = { - name => defined $alias ? $alias : 'input file handle', - text => $text, - time => $now, - load => 0, - }; - } - elsif (-f $name) { - if (open(FH, $name)) { - my $text = <FH>; - $data = { - name => $alias, - path => $name, - text => $text, - time => (stat $name)[9], - load => $now, - }; - } - elsif ($tolerant) { - ($data, $error) = (undef, Template::Constants::STATUS_DECLINED); - } - else { - $data = "$alias: $!"; - $error = Template::Constants::STATUS_ERROR; - } - } - else { - ($data, $error) = (undef, Template::Constants::STATUS_DECLINED); - } - } - - $data->{ path } = $data->{ name } - if $data and ! defined $data->{ path }; - - return ($data, $error); -} - - -#------------------------------------------------------------------------ -# _refresh(\@slot) -# -# Private method called to mark a cache slot as most recently used. -# A reference to the slot array should be passed by parameter. The -# slot is relocated to the head of the linked list. If the file from -# which the data was loaded has been upated since it was compiled, then -# it is re-loaded from disk and re-compiled. -#------------------------------------------------------------------------ - -sub _refresh { - my ($self, $slot) = @_; - my ($head, $file, $data, $error); - - - $self->debug("_refresh([ ", - join(', ', map { defined $_ ? $_ : '<undef>' } @$slot), - '])') if $self->{ DEBUG }; - - # if it's more than $STAT_TTL seconds since we last performed a - # stat() on the file then we need to do it again and see if the file - # time has changed - if ( (time - $slot->[ STAT ]) > $STAT_TTL && stat $slot->[ NAME ] ) { - $slot->[ STAT ] = time; - - if ( (stat(_))[9] != $slot->[ LOAD ]) { - - $self->debug("refreshing cache file ", $slot->[ NAME ]) - if $self->{ DEBUG }; - - ($data, $error) = $self->_load($slot->[ NAME ], - $slot->[ DATA ]->{ name }); - ($data, $error) = $self->_compile($data) - unless $error; - - unless ($error) { - $slot->[ DATA ] = $data->{ data }; - $slot->[ LOAD ] = $data->{ time }; - } - } - } - - unless( $self->{ HEAD } == $slot ) { - # remove existing slot from usage chain... - if ($slot->[ PREV ]) { - $slot->[ PREV ]->[ NEXT ] = $slot->[ NEXT ]; - } - else { - $self->{ HEAD } = $slot->[ NEXT ]; - } - if ($slot->[ NEXT ]) { - $slot->[ NEXT ]->[ PREV ] = $slot->[ PREV ]; - } - else { - $self->{ TAIL } = $slot->[ PREV ]; - } - - # ..and add to start of list - $head = $self->{ HEAD }; - $head->[ PREV ] = $slot if $head; - $slot->[ PREV ] = undef; - $slot->[ NEXT ] = $head; - $self->{ HEAD } = $slot; - } - - return ($data, $error); -} - - -#------------------------------------------------------------------------ -# _store($name, $data) -# -# Private method called to add a data item to the cache. If the cache -# size limit has been reached then the oldest entry at the tail of the -# list is removed and its slot relocated to the head of the list and -# reused for the new data item. If the cache is under the size limit, -# or if no size limit is defined, then the item is added to the head -# of the list. -#------------------------------------------------------------------------ - -sub _store { - my ($self, $name, $data, $compfile) = @_; - my $size = $self->{ SIZE }; - my ($slot, $head); - - # extract the load time and compiled template from the data -# my $load = $data->{ load }; - my $load = (stat($name))[9]; - $data = $data->{ data }; - - $self->debug("_store($name, $data)") if $self->{ DEBUG }; - - if (defined $size && $self->{ SLOTS } >= $size) { - # cache has reached size limit, so reuse oldest entry - - $self->debug("reusing oldest cache entry (size limit reached: $size)\nslots: $self->{ SLOTS }") if $self->{ DEBUG }; - - # remove entry from tail of list - $slot = $self->{ TAIL }; - $slot->[ PREV ]->[ NEXT ] = undef; - $self->{ TAIL } = $slot->[ PREV ]; - - # remove name lookup for old node - delete $self->{ LOOKUP }->{ $slot->[ NAME ] }; - - # add modified node to head of list - $head = $self->{ HEAD }; - $head->[ PREV ] = $slot if $head; - @$slot = ( undef, $name, $data, $load, $head, time ); - $self->{ HEAD } = $slot; - - # add name lookup for new node - $self->{ LOOKUP }->{ $name } = $slot; - } - else { - # cache is under size limit, or none is defined - - $self->debug("adding new cache entry") if $self->{ DEBUG }; - - # add new node to head of list - $head = $self->{ HEAD }; - $slot = [ undef, $name, $data, $load, $head, time ]; - $head->[ PREV ] = $slot if $head; - $self->{ HEAD } = $slot; - $self->{ TAIL } = $slot unless $self->{ TAIL }; - - # add lookup from name to slot and increment nslots - $self->{ LOOKUP }->{ $name } = $slot; - $self->{ SLOTS }++; - } - - return $data; -} - - -#------------------------------------------------------------------------ -# _compile($data) -# -# Private method called to parse the template text and compile it into -# a runtime form. Creates and delegates a Template::Parser object to -# handle the compilation, or uses a reference passed in PARSER. On -# success, the compiled template is stored in the 'data' item of the -# $data hash and returned. On error, ($error, STATUS_ERROR) is returned, -# or (undef, STATUS_DECLINED) if the TOLERANT flag is set. -# The optional $compiled parameter may be passed to specify -# the name of a compiled template file to which the generated Perl -# code should be written. Errors are (for now...) silently -# ignored, assuming that failures to open a file for writing are -# intentional (e.g directory write permission). -#------------------------------------------------------------------------ - -sub _compile { - my ($self, $data, $compfile) = @_; - my $text = $data->{ text }; - my ($parsedoc, $error); - - $self->debug("_compile($data, ", - defined $compfile ? $compfile : '<no compfile>', ')') - if $self->{ DEBUG }; - - my $parser = $self->{ PARSER } - ||= Template::Config->parser($self->{ PARAMS }) - || return (Template::Config->error(), Template::Constants::STATUS_ERROR); - - # discard the template text - we don't need it any more - delete $data->{ text }; - - # call parser to compile template into Perl code - if ($parsedoc = $parser->parse($text, $data)) { - - $parsedoc->{ METADATA } = { - 'name' => $data->{ name }, - 'modtime' => $data->{ time }, - %{ $parsedoc->{ METADATA } }, - }; - - # write the Perl code to the file $compfile, if defined - if ($compfile) { - my $basedir = &File::Basename::dirname($compfile); - $basedir =~ /(.*)/; - $basedir = $1; - &File::Path::mkpath($basedir) unless -d $basedir; - - my $docclass = $self->{ DOCUMENT }; - $error = 'cache failed to write ' - . &File::Basename::basename($compfile) - . ': ' . $docclass->error() - unless $docclass->write_perl_file($compfile, $parsedoc); - - # set atime and mtime of newly compiled file, don't bother - # if time is undef - if (!defined($error) && defined $data->{ time }) { - my ($cfile) = $compfile =~ /^(.+)$/s or do { - return("invalid filename: $compfile", - Template::Constants::STATUS_ERROR); - }; - - my ($ctime) = $data->{ time } =~ /^(\d+)$/; - unless ($ctime || $ctime eq 0) { - return("invalid time: $ctime", - Template::Constants::STATUS_ERROR); - } - utime($ctime, $ctime, $cfile); - } - } - - unless ($error) { - return $data ## RETURN ## - if $data->{ data } = $DOCUMENT->new($parsedoc); - $error = $Template::Document::ERROR; - } - } - else { - $error = Template::Exception->new( 'parse', "$data->{ name } " . - $parser->error() ); - } - - # return STATUS_ERROR, or STATUS_DECLINED if we're being tolerant - return $self->{ TOLERANT } - ? (undef, Template::Constants::STATUS_DECLINED) - : ($error, Template::Constants::STATUS_ERROR) -} - - -#------------------------------------------------------------------------ -# _dump() -# -# Debug method which returns a string representing the internal object -# state. -#------------------------------------------------------------------------ - -sub _dump { - my $self = shift; - my $size = $self->{ SIZE }; - my $parser = $self->{ PARSER }; - $parser = $parser ? $parser->_dump() : '<no parser>'; - $parser =~ s/\n/\n /gm; - $size = 'unlimited' unless defined $size; - - my $output = "[Template::Provider] {\n"; - my $format = " %-16s => %s\n"; - my $key; - - $output .= sprintf($format, 'INCLUDE_PATH', - '[ ' . join(', ', @{ $self->{ INCLUDE_PATH } }) . ' ]'); - $output .= sprintf($format, 'CACHE_SIZE', $size); - - foreach $key (qw( ABSOLUTE RELATIVE TOLERANT DELIMITER - COMPILE_EXT COMPILE_DIR )) { - $output .= sprintf($format, $key, $self->{ $key }); - } - $output .= sprintf($format, 'PARSER', $parser); - - - local $" = ', '; - my $lookup = $self->{ LOOKUP }; - $lookup = join('', map { - sprintf(" $format", $_, defined $lookup->{ $_ } - ? ('[ ' . join(', ', map { defined $_ ? $_ : '<undef>' } - @{ $lookup->{ $_ } }) . ' ]') : '<undef>'); - } sort keys %$lookup); - $lookup = "{\n$lookup }"; - - $output .= sprintf($format, LOOKUP => $lookup); - - $output .= '}'; - return $output; -} - - -#------------------------------------------------------------------------ -# _dump_cache() -# -# Debug method which prints the current state of the cache to STDERR. -#------------------------------------------------------------------------ - -sub _dump_cache { - my $self = shift; - my ($node, $lut, $count); - - $count = 0; - if ($node = $self->{ HEAD }) { - while ($node) { - $lut->{ $node } = $count++; - $node = $node->[ NEXT ]; - } - $node = $self->{ HEAD }; - print STDERR "CACHE STATE:\n"; - print STDERR " HEAD: ", $self->{ HEAD }->[ NAME ], "\n"; - print STDERR " TAIL: ", $self->{ TAIL }->[ NAME ], "\n"; - while ($node) { - my ($prev, $name, $data, $load, $next) = @$node; -# $name = '...' . substr($name, -10) if length $name > 10; - $prev = $prev ? "#$lut->{ $prev }<-": '<undef>'; - $next = $next ? "->#$lut->{ $next }": '<undef>'; - print STDERR " #$lut->{ $node } : [ $prev, $name, $data, $load, $next ]\n"; - $node = $node->[ NEXT ]; - } - } -} - -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::Provider - Provider module for loading/compiling templates - -=head1 SYNOPSIS - - $provider = Template::Provider->new(\%options); - - ($template, $error) = $provider->fetch($name); - -=head1 DESCRIPTION - -The Template::Provider is used to load, parse, compile and cache template -documents. This object may be sub-classed to provide more specific -facilities for loading, or otherwise providing access to templates. - -The Template::Context objects maintain a list of Template::Provider -objects which are polled in turn (via fetch()) to return a requested -template. Each may return a compiled template, raise an error, or -decline to serve the reqest, giving subsequent providers a chance to -do so. - -This is the "Chain of Responsiblity" pattern. See 'Design Patterns' for -further information. - -This documentation needs work. - -=head1 PUBLIC METHODS - -=head2 new(\%options) - -Constructor method which instantiates and returns a new Template::Provider -object. The optional parameter may be a hash reference containing any of -the following items: - -=over 4 - - - - -=item INCLUDE_PATH - -The INCLUDE_PATH is used to specify one or more directories in which -template files are located. When a template is requested that isn't -defined locally as a BLOCK, each of the INCLUDE_PATH directories is -searched in turn to locate the template file. Multiple directories -can be specified as a reference to a list or as a single string where -each directory is delimited by ':'. - - my $provider = Template::Provider->new({ - INCLUDE_PATH => '/usr/local/templates', - }); - - my $provider = Template::Provider->new({ - INCLUDE_PATH => '/usr/local/templates:/tmp/my/templates', - }); - - my $provider = Template::Provider->new({ - INCLUDE_PATH => [ '/usr/local/templates', - '/tmp/my/templates' ], - }); - -On Win32 systems, a little extra magic is invoked, ignoring delimiters -that have ':' followed by a '/' or '\'. This avoids confusion when using -directory names like 'C:\Blah Blah'. - -When specified as a list, the INCLUDE_PATH path can contain elements -which dynamically generate a list of INCLUDE_PATH directories. These -generator elements can be specified as a reference to a subroutine or -an object which implements a paths() method. - - my $provider = Template::Provider->new({ - INCLUDE_PATH => [ '/usr/local/templates', - \&incpath_generator, - My::IncPath::Generator->new( ... ) ], - }); - -Each time a template is requested and the INCLUDE_PATH examined, the -subroutine or object method will be called. A reference to a list of -directories should be returned. Generator subroutines should report -errors using die(). Generator objects should return undef and make an -error available via its error() method. - -For example: - - sub incpath_generator { - - # ...some code... - - if ($all_is_well) { - return \@list_of_directories; - } - else { - die "cannot generate INCLUDE_PATH...\n"; - } - } - -or: - - package My::IncPath::Generator; - - # Template::Base (or Class::Base) provides error() method - use Template::Base; - use base qw( Template::Base ); - - sub paths { - my $self = shift; - - # ...some code... - - if ($all_is_well) { - return \@list_of_directories; - } - else { - return $self->error("cannot generate INCLUDE_PATH...\n"); - } - } - - 1; - - - - - -=item DELIMITER - -Used to provide an alternative delimiter character sequence for -separating paths specified in the INCLUDE_PATH. The default -value for DELIMITER is ':'. - - # tolerate Silly Billy's file system conventions - my $provider = Template::Provider->new({ - DELIMITER => '; ', - INCLUDE_PATH => 'C:/HERE/NOW; D:/THERE/THEN', - }); - - # better solution: install Linux! :-) - -On Win32 systems, the default delimiter is a little more intelligent, -splitting paths only on ':' characters that aren't followed by a '/'. -This means that the following should work as planned, splitting the -INCLUDE_PATH into 2 separate directories, C:/foo and C:/bar. - - # on Win32 only - my $provider = Template::Provider->new({ - INCLUDE_PATH => 'C:/Foo:C:/Bar' - }); - -However, if you're using Win32 then it's recommended that you -explicitly set the DELIMITER character to something else (e.g. ';') -rather than rely on this subtle magic. - - - - -=item ABSOLUTE - -The ABSOLUTE flag is used to indicate if templates specified with -absolute filenames (e.g. '/foo/bar') should be processed. It is -disabled by default and any attempt to load a template by such a -name will cause a 'file' exception to be raised. - - my $provider = Template::Provider->new({ - ABSOLUTE => 1, - }); - - # this is why it's disabled by default - [% INSERT /etc/passwd %] - -On Win32 systems, the regular expression for matching absolute -pathnames is tweaked slightly to also detect filenames that start -with a driver letter and colon, such as: - - C:/Foo/Bar - - - - - - -=item RELATIVE - -The RELATIVE flag is used to indicate if templates specified with -filenames relative to the current directory (e.g. './foo/bar' or -'../../some/where/else') should be loaded. It is also disabled by -default, and will raise a 'file' error if such template names are -encountered. - - my $provider = Template::Provider->new({ - RELATIVE => 1, - }); - - [% INCLUDE ../logs/error.log %] - - - - - -=item DEFAULT - -The DEFAULT option can be used to specify a default template which should -be used whenever a specified template can't be found in the INCLUDE_PATH. - - my $provider = Template::Provider->new({ - DEFAULT => 'notfound.html', - }); - -If a non-existant template is requested through the Template process() -method, or by an INCLUDE, PROCESS or WRAPPER directive, then the -DEFAULT template will instead be processed, if defined. Note that the -DEFAULT template is not used when templates are specified with -absolute or relative filenames, or as a reference to a input file -handle or text string. - - - - - -=item CACHE_SIZE - -The Template::Provider module caches compiled templates to avoid the need -to re-parse template files or blocks each time they are used. The CACHE_SIZE -option is used to limit the number of compiled templates that the module -should cache. - -By default, the CACHE_SIZE is undefined and all compiled templates are -cached. When set to any positive value, the cache will be limited to -storing no more than that number of compiled templates. When a new -template is loaded and compiled and the cache is full (i.e. the number -of entries == CACHE_SIZE), the least recently used compiled template -is discarded to make room for the new one. - -The CACHE_SIZE can be set to 0 to disable caching altogether. - - my $provider = Template::Provider->new({ - CACHE_SIZE => 64, # only cache 64 compiled templates - }); - - my $provider = Template::Provider->new({ - CACHE_SIZE => 0, # don't cache any compiled templates - }); - - - - - - -=item COMPILE_EXT - -From version 2 onwards, the Template Toolkit has the ability to -compile templates to Perl code and save them to disk for subsequent -use (i.e. cache persistence). The COMPILE_EXT option may be -provided to specify a filename extension for compiled template files. -It is undefined by default and no attempt will be made to read or write -any compiled template files. - - my $provider = Template::Provider->new({ - COMPILE_EXT => '.ttc', - }); - -If COMPILE_EXT is defined (and COMPILE_DIR isn't, see below) then compiled -template files with the COMPILE_EXT extension will be written to the same -directory from which the source template files were loaded. - -Compiling and subsequent reuse of templates happens automatically -whenever the COMPILE_EXT or COMPILE_DIR options are set. The Template -Toolkit will automatically reload and reuse compiled files when it -finds them on disk. If the corresponding source file has been modified -since the compiled version as written, then it will load and re-compile -the source and write a new compiled version to disk. - -This form of cache persistence offers significant benefits in terms of -time and resources required to reload templates. Compiled templates can -be reloaded by a simple call to Perl's require(), leaving Perl to handle -all the parsing and compilation. This is a Good Thing. - -=item COMPILE_DIR - -The COMPILE_DIR option is used to specify an alternate directory root -under which compiled template files should be saved. - - my $provider = Template::Provider->new({ - COMPILE_DIR => '/tmp/ttc', - }); - -The COMPILE_EXT option may also be specified to have a consistent file -extension added to these files. - - my $provider1 = Template::Provider->new({ - COMPILE_DIR => '/tmp/ttc', - COMPILE_EXT => '.ttc1', - }); - - my $provider2 = Template::Provider->new({ - COMPILE_DIR => '/tmp/ttc', - COMPILE_EXT => '.ttc2', - }); - - -When COMPILE_EXT is undefined, the compiled template files have the -same name as the original template files, but reside in a different -directory tree. - -Each directory in the INCLUDE_PATH is replicated in full beneath the -COMPILE_DIR directory. This example: - - my $provider = Template::Provider->new({ - COMPILE_DIR => '/tmp/ttc', - INCLUDE_PATH => '/home/abw/templates:/usr/share/templates', - }); - -would create the following directory structure: - - /tmp/ttc/home/abw/templates/ - /tmp/ttc/usr/share/templates/ - -Files loaded from different INCLUDE_PATH directories will have their -compiled forms save in the relevant COMPILE_DIR directory. - -On Win32 platforms a filename may by prefixed by a drive letter and -colon. e.g. - - C:/My Templates/header - -The colon will be silently stripped from the filename when it is added -to the COMPILE_DIR value(s) to prevent illegal filename being generated. -Any colon in COMPILE_DIR elements will be left intact. For example: - - # Win32 only - my $provider = Template::Provider->new({ - DELIMITER => ';', - COMPILE_DIR => 'C:/TT2/Cache', - INCLUDE_PATH => 'C:/TT2/Templates;D:/My Templates', - }); - -This would create the following cache directories: - - C:/TT2/Cache/C/TT2/Templates - C:/TT2/Cache/D/My Templates - - - - -=item TOLERANT - -The TOLERANT flag is used by the various Template Toolkit provider -modules (Template::Provider, Template::Plugins, Template::Filters) to -control their behaviour when errors are encountered. By default, any -errors are reported as such, with the request for the particular -resource (template, plugin, filter) being denied and an exception -raised. When the TOLERANT flag is set to any true values, errors will -be silently ignored and the provider will instead return -STATUS_DECLINED. This allows a subsequent provider to take -responsibility for providing the resource, rather than failing the -request outright. If all providers decline to service the request, -either through tolerated failure or a genuine disinclination to -comply, then a 'E<lt>resourceE<gt> not found' exception is raised. - - - - - - -=item PARSER - -The Template::Parser module implements a parser object for compiling -templates into Perl code which can then be executed. A default object -of this class is created automatically and then used by the -Template::Provider whenever a template is loaded and requires -compilation. The PARSER option can be used to provide a reference to -an alternate parser object. - - my $provider = Template::Provider->new({ - PARSER => MyOrg::Template::Parser->new({ ... }), - }); - - - -=item DEBUG - -The DEBUG option can be used to enable debugging messages from the -Template::Provider module by setting it to include the DEBUG_PROVIDER -value. - - use Template::Constants qw( :debug ); - - my $template = Template->new({ - DEBUG => DEBUG_PROVIDER, - }); - - - -=back - -=head2 fetch($name) - -Returns a compiled template for the name specified. If the template -cannot be found then (undef, STATUS_DECLINED) is returned. If an error -occurs (e.g. read error, parse error) then ($error, STATUS_ERROR) is -returned, where $error is the error message generated. If the TOLERANT -flag is set the the method returns (undef, STATUS_DECLINED) instead of -returning an error. - -=head2 store($name, $template) - -Stores the compiled template, $template, in the cache under the name, -$name. Susbequent calls to fetch($name) will return this template in -preference to any disk-based file. - -=head2 include_path(\@newpath)) - -Accessor method for the INCLUDE_PATH setting. If called with an -argument, this method will replace the existing INCLUDE_PATH with -the new value. - -=head2 paths() - -This method generates a copy of the INCLUDE_PATH list. Any elements in the -list which are dynamic generators (e.g. references to subroutines or objects -implementing a paths() method) will be called and the list of directories -returned merged into the output list. - -It is possible to provide a generator which returns itself, thus sending -this method into an infinite loop. To detect and prevent this from happening, -the C<$MAX_DIRS> package variable, set to 64 by default, limits the maximum -number of paths that can be added to, or generated for the output list. If -this number is exceeded then the method will immediately return an error -reporting as much. - -=head1 AUTHOR - -Andy Wardley E<lt>abw@andywardley.comE<gt> - -L<http://www.andywardley.com/|http://www.andywardley.com/> - - - - -=head1 VERSION - -2.79, 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|Template>, L<Template::Parser|Template::Parser>, L<Template::Context|Template::Context> - -=cut - -# Local Variables: -# mode: perl -# perl-indent-level: 4 -# indent-tabs-mode: nil -# End: -# -# vim: expandtab shiftwidth=4: |
