📄 template.pm
字号:
=item *
loop_context_vars - when this parameter is set to true (it is false by
default) four loop context variables are made available inside a loop:
__first__, __last__, __inner__, __odd__. They can be used with
<TMPL_IF>, <TMPL_UNLESS> and <TMPL_ELSE> to control how a loop is
output.
In addition to the above, a __counter__ var is also made available
when loop context variables are turned on.
Example:
<TMPL_LOOP NAME="FOO">
<TMPL_IF NAME="__first__">
This only outputs on the first pass.
</TMPL_IF>
<TMPL_IF NAME="__odd__">
This outputs every other pass, on the odd passes.
</TMPL_IF>
<TMPL_UNLESS NAME="__odd__">
This outputs every other pass, on the even passes.
</TMPL_UNLESS>
<TMPL_IF NAME="__inner__">
This outputs on passes that are neither first nor last.
</TMPL_IF>
This is pass number <TMPL_VAR NAME="__counter__">.
<TMPL_IF NAME="__last__">
This only outputs on the last pass.
</TMPL_IF>
</TMPL_LOOP>
One use of this feature is to provide a "separator" similar in effect
to the perl function join(). Example:
<TMPL_LOOP FRUIT>
<TMPL_IF __last__> and </TMPL_IF>
<TMPL_VAR KIND><TMPL_UNLESS __last__>, <TMPL_ELSE>.</TMPL_UNLESS>
</TMPL_LOOP>
Would output (in a browser) something like:
Apples, Oranges, Brains, Toes, and Kiwi.
Given an appropriate param() call, of course. NOTE: A loop with only
a single pass will get both __first__ and __last__ set to true, but
not __inner__.
=item *
no_includes - set this option to 1 to disallow the <TMPL_INCLUDE> tag
in the template file. This can be used to make opening untrusted
templates B<slightly> less dangerous. Defaults to 0.
=item *
max_includes - set this variable to determine the maximum depth that
includes can reach. Set to 10 by default. Including files to a depth
greater than this value causes an error message to be displayed. Set
to 0 to disable this protection.
=item *
global_vars - normally variables declared outside a loop are not
available inside a loop. This option makes <TMPL_VAR>s like global
variables in Perl - they have unlimited scope. This option also
affects <TMPL_IF> and <TMPL_UNLESS>.
Example:
This is a normal variable: <TMPL_VAR NORMAL>.<P>
<TMPL_LOOP NAME=FROOT_LOOP>
Here it is inside the loop: <TMPL_VAR NORMAL><P>
</TMPL_LOOP>
Normally this wouldn't work as expected, since <TMPL_VAR NORMAL>'s
value outside the loop is not available inside the loop.
The global_vars option also allows you to access the values of an
enclosing loop within an inner loop. For example, in this loop the
inner loop will have access to the value of OUTER_VAR in the correct
iteration:
<TMPL_LOOP OUTER_LOOP>
OUTER: <TMPL_VAR OUTER_VAR>
<TMPL_LOOP INNER_LOOP>
INNER: <TMPL_VAR INNER_VAR>
INSIDE OUT: <TMPL_VAR OUTER_VAR>
</TMPL_LOOP>
</TMPL_LOOP>
B<NOTE>: C<global_vars> is not C<global_loops> (which does not exist).
That means that loops you declare at one scope are not available
inside other loops even when C<global_vars> is on.
=item *
filter - this option allows you to specify a filter for your template
files. A filter is a subroutine that will be called after
HTML::Template reads your template file but before it starts parsing
template tags.
In the most simple usage, you simply assign a code reference to the
filter parameter. This subroutine will recieve a single arguement - a
reference to a string containing the template file text. Here is an
example that accepts templates with tags that look like "!!!ZAP_VAR
FOO!!!" and transforms them into HTML::Template tags:
my $filter = sub {
my $text_ref = shift;
$$text_ref =~ s/!!!ZAP_(.*?)!!!/<TMPL_$1>/g;
};
# open zap.tmpl using the above filter
my $template = HTML::Template->new(filename => 'zap.tmpl',
filter => $filter);
More complicated usages are possible. You can request that your
filter receieve the template text as an array of lines rather than as
a single scalar. To do that you need to specify your filter using a
hash-ref. In this form you specify the filter using the "sub" key and
the desired argument format using the "format" key. The available
formats are "scalar" and "array". Using the "array" format will incur
a performance penalty but may be more convenient in some situations.
my $template = HTML::Template->new(filename => 'zap.tmpl',
filter => { sub => $filter,
format => 'array' });
You may also have multiple filters. This allows simple filters to be
combined for more elaborate functionality. To do this you specify an
array of filters. The filters are applied in the order they are
specified.
my $template = HTML::Template->new(filename => 'zap.tmpl',
filter => [
{ sub => \&decompress,
format => 'scalar' },
{ sub => \&remove_spaces,
format => 'array' }
]);
The specified filters will be called for any TMPL_INCLUDEed files just
as they are for the main template file.
=item *
default_escape - Set this parameter to "HTML", "URL" or "JS" and
HTML::Template will apply the specified escaping to all variables
unless they declare a different escape in the template.
=back
=back 4
=cut
use integer; # no floating point math so far!
use strict; # and no funny business, either.
use Carp; # generate better errors with more context
use File::Spec; # generate paths that work on all platforms
use Digest::MD5 qw(md5_hex); # generate cache keys
# define accessor constants used to improve readability of array
# accesses into "objects". I used to use 'use constant' but that
# seems to cause occasional irritating warnings in older Perls.
package HTML::Template::LOOP;
sub TEMPLATE_HASH () { 0 };
sub PARAM_SET () { 1 };
package HTML::Template::COND;
sub VARIABLE () { 0 };
sub VARIABLE_TYPE () { 1 };
sub VARIABLE_TYPE_VAR () { 0 };
sub VARIABLE_TYPE_LOOP () { 1 };
sub JUMP_IF_TRUE () { 2 };
sub JUMP_ADDRESS () { 3 };
sub WHICH () { 4 };
sub UNCONDITIONAL_JUMP () { 5 };
sub IS_ELSE () { 6 };
sub WHICH_IF () { 0 };
sub WHICH_UNLESS () { 1 };
# back to the main package scope.
package HTML::Template;
# open a new template and return an object handle
sub new {
my $pkg = shift;
my $self; { my %hash; $self = bless(\%hash, $pkg); }
# the options hash
my $options = {};
$self->{options} = $options;
# set default parameters in options hash
%$options = (
debug => 0,
stack_debug => 0,
timing => 0,
search_path_on_include => 0,
cache => 0,
blind_cache => 0,
file_cache => 0,
file_cache_dir => '',
file_cache_dir_mode => 0700,
cache_debug => 0,
shared_cache_debug => 0,
memory_debug => 0,
die_on_bad_params => 1,
vanguard_compatibility_mode => 0,
associate => [],
path => [],
strict => 1,
loop_context_vars => 0,
max_includes => 10,
shared_cache => 0,
double_cache => 0,
double_file_cache => 0,
ipc_key => 'TMPL',
ipc_mode => 0666,
ipc_segment_size => 65536,
ipc_max_size => 0,
global_vars => 0,
no_includes => 0,
case_sensitive => 0,
filter => [],
default_escape => undef,
);
# load in options supplied to new()
for (my $x = 0; $x <= $#_; $x += 2) {
defined($_[($x + 1)]) or croak("HTML::Template->new() called with odd number of option parameters - should be of the form option => value");
$options->{lc($_[$x])} = $_[($x + 1)];
}
# blind_cache = 1 implies cache = 1
$options->{blind_cache} and $options->{cache} = 1;
# shared_cache = 1 implies cache = 1
$options->{shared_cache} and $options->{cache} = 1;
# file_cache = 1 implies cache = 1
$options->{file_cache} and $options->{cache} = 1;
# double_cache is a combination of shared_cache and cache.
$options->{double_cache} and $options->{cache} = 1;
$options->{double_cache} and $options->{shared_cache} = 1;
# double_file_cache is a combination of file_cache and cache.
$options->{double_file_cache} and $options->{cache} = 1;
$options->{double_file_cache} and $options->{file_cache} = 1;
# vanguard_compatibility_mode implies die_on_bad_params = 0
$options->{vanguard_compatibility_mode} and
$options->{die_on_bad_params} = 0;
# handle the "type", "source" parameter format (does anyone use it?)
if (exists($options->{type})) {
exists($options->{source}) or croak("HTML::Template->new() called with 'type' parameter set, but no 'source'!");
($options->{type} eq 'filename' or $options->{type} eq 'scalarref' or
$options->{type} eq 'arrayref' or $options->{type} eq 'filehandle') or
croak("HTML::Template->new() : type parameter must be set to 'filename', 'arrayref', 'scalarref' or 'filehandle'!");
$options->{$options->{type}} = $options->{source};
delete $options->{type};
delete $options->{source};
}
# associate should be an array of one element if it's not
# already an array.
if (ref($options->{associate}) ne 'ARRAY') {
$options->{associate} = [ $options->{associate} ];
}
# path should be an array if it's not already
if (ref($options->{path}) ne 'ARRAY') {
$options->{path} = [ $options->{path} ];
}
# filter should be an array if it's not already
if (ref($options->{filter}) ne 'ARRAY') {
$options->{filter} = [ $options->{filter} ];
}
# make sure objects in associate area support param()
foreach my $object (@{$options->{associate}}) {
defined($object->can('param')) or
croak("HTML::Template->new called with associate option, containing object of type " . ref($object) . " which lacks a param() method!");
}
# check for syntax errors:
my $source_count = 0;
exists($options->{filename}) and $source_count++;
exists($options->{filehandle}) and $source_count++;
exists($options->{arrayref}) and $source_count++;
exists($options->{scalarref}) and $source_count++;
if ($source_count != 1) {
croak("HTML::Template->new called with multiple (or no) template sources specified! A valid call to new() has exactly one filename => 'file' OR exactly one scalarref => \\\$scalar OR exactly one arrayref => \\\@array OR exactly one filehandle => \*FH");
}
# check that filenames aren't empty
if (exists($options->{filename})) {
croak("HTML::Template->new called with empty filename parameter!")
unless defined $options->{filename} and length $options->{filename};
}
# do some memory debugging - this is best started as early as possible
if ($options->{memory_debug}) {
# memory_debug needs GTop
eval { require GTop; };
croak("Could not load GTop. You must have GTop installed to use HTML::Template in memory_debug mode. The error was: $@")
if ($@);
$self->{gtop} = GTop->new();
$self->{proc_mem} = $self->{gtop}->proc_mem($$);
print STDERR "\n### HTML::Template Memory Debug ### START ", $self->{proc_mem}->size(), "\n";
}
if ($options->{file_cache}) {
# make sure we have a file_cache_dir option
croak("You must specify the file_cache_dir option if you want to use file_cache.")
unless defined $options->{file_cache_dir} and
length $options->{file_cache_dir};
# file_cache needs some extra modules loaded
eval { require Storable; };
croak("Could not load Storable. You must have Storable installed to use HTML::Template in file_cache mode. The error was: $@")
if ($@);
}
if ($options->{shared_cache}) {
# shared_cache needs some extra modules loaded
eval { require IPC::SharedCache; };
croak("Could not load IPC::SharedCache. You must have IPC::SharedCache installed to use HTML::Template in shared_cache mode. The error was: $@")
if ($@);
# initialize the shared cache
my %cache;
tie %cache, 'IPC::SharedCache',
ipc_key => $options->{ipc_key},
load_callback => [\&_load_shared_cache, $self],
validate_callback => [\&_validate_shared_cache, $self],
debug => $options->{shared_cache_debug},
ipc_mode => $options->{ipc_mode},
max_size => $options->{ipc_max_size},
ipc_segment_size => $options->{ipc_segment_size};
$self->{cache} = \%cache;
}
if ($options->{default_escape}) {
$options->{default_escape} = uc $options->{default_escape};
unless ($options->{default_escape} =~ /^(HTML|URL|JS)$/) {
croak("HTML::Template->new(): Invalid setting for default_escape - '$options->{default_escape}'. Valid values are HTML, URL or JS.");
}
}
print STDERR "### HTML::Template Memory Debug ### POST CACHE INIT ", $self->{proc_mem}->size(), "\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -