Initial Commit
This commit is contained in:
346
database/perl/vendor/lib/Template/Tiny.pm
vendored
Normal file
346
database/perl/vendor/lib/Template/Tiny.pm
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
package Template::Tiny;
|
||||
|
||||
# Load overhead: 40k
|
||||
|
||||
use 5.00503;
|
||||
use strict;
|
||||
|
||||
$Template::Tiny::VERSION = '1.12';
|
||||
|
||||
# Evaluatable expression
|
||||
my $EXPR = qr/ [a-z_][\w.]* /xs;
|
||||
|
||||
# Opening [% tag including whitespace chomping rules
|
||||
my $LEFT = qr/
|
||||
(?:
|
||||
(?: (?:^|\n) [ \t]* )? \[\%\-
|
||||
|
|
||||
\[\% \+?
|
||||
) \s*
|
||||
/xs;
|
||||
|
||||
# Closing %] tag including whitespace chomping rules
|
||||
my $RIGHT = qr/
|
||||
\s* (?:
|
||||
\+? \%\]
|
||||
|
|
||||
\-\%\] (?: [ \t]* \n )?
|
||||
)
|
||||
/xs;
|
||||
|
||||
# Preparsing run for nesting tags
|
||||
my $PREPARSE = qr/
|
||||
$LEFT ( IF | UNLESS | FOREACH ) \s+
|
||||
(
|
||||
(?: \S+ \s+ IN \s+ )?
|
||||
\S+ )
|
||||
$RIGHT
|
||||
(?!
|
||||
.*?
|
||||
$LEFT (?: IF | UNLESS | FOREACH ) \b
|
||||
)
|
||||
( .*? )
|
||||
(?:
|
||||
$LEFT ELSE $RIGHT
|
||||
(?!
|
||||
.*?
|
||||
$LEFT (?: IF | UNLESS | FOREACH ) \b
|
||||
)
|
||||
( .+? )
|
||||
)?
|
||||
$LEFT END $RIGHT
|
||||
/xs;
|
||||
|
||||
# Condition set
|
||||
my $CONDITION = qr/
|
||||
\[\%\s
|
||||
( ([IUF])\d+ ) \s+
|
||||
(?:
|
||||
([a-z]\w*) \s+ IN \s+
|
||||
)?
|
||||
( $EXPR )
|
||||
\s\%\]
|
||||
( .*? )
|
||||
(?:
|
||||
\[\%\s \1 \s\%\]
|
||||
( .+? )
|
||||
)?
|
||||
\[\%\s \1 \s\%\]
|
||||
/xs;
|
||||
|
||||
sub new {
|
||||
bless { @_[1..$#_] }, $_[0];
|
||||
}
|
||||
|
||||
# Copy and modify
|
||||
sub preprocess {
|
||||
my $self = shift;
|
||||
my $text = shift;
|
||||
$self->_preprocess(\$text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub process {
|
||||
my $self = shift;
|
||||
my $copy = ${shift()};
|
||||
my $stash = shift || {};
|
||||
|
||||
local $@ = '';
|
||||
local $^W = 0;
|
||||
|
||||
# Preprocess to establish unique matching tag sets
|
||||
$self->_preprocess( \$copy );
|
||||
|
||||
# Process down the nested tree of conditions
|
||||
my $result = $self->_process( $stash, $copy );
|
||||
if ( @_ ) {
|
||||
${$_[0]} = $result;
|
||||
} elsif ( defined wantarray ) {
|
||||
require Carp;
|
||||
Carp::carp('Returning of template results is deprecated in Template::Tiny 0.11');
|
||||
return $result;
|
||||
} else {
|
||||
print $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
######################################################################
|
||||
# Support Methods
|
||||
|
||||
# The only reason this is a standalone is so we can
|
||||
# do more in-depth testing.
|
||||
sub _preprocess {
|
||||
my $self = shift;
|
||||
my $copy = shift;
|
||||
|
||||
# Preprocess to establish unique matching tag sets
|
||||
my $id = 0;
|
||||
1 while $$copy =~ s/
|
||||
$PREPARSE
|
||||
/
|
||||
my $tag = substr($1, 0, 1) . ++$id;
|
||||
"\[\% $tag $2 \%\]$3\[\% $tag \%\]"
|
||||
. (defined($4) ? "$4\[\% $tag \%\]" : '');
|
||||
/sex;
|
||||
}
|
||||
|
||||
sub _process {
|
||||
my ($self, $stash, $text) = @_;
|
||||
|
||||
$text =~ s/
|
||||
$CONDITION
|
||||
/
|
||||
($2 eq 'F')
|
||||
? $self->_foreach($stash, $3, $4, $5)
|
||||
: eval {
|
||||
$2 eq 'U'
|
||||
xor
|
||||
!! # Force boolification
|
||||
$self->_expression($stash, $4)
|
||||
}
|
||||
? $self->_process($stash, $5)
|
||||
: $self->_process($stash, $6)
|
||||
/gsex;
|
||||
|
||||
# Resolve expressions
|
||||
$text =~ s/
|
||||
$LEFT ( $EXPR ) $RIGHT
|
||||
/
|
||||
eval {
|
||||
$self->_expression($stash, $1)
|
||||
. '' # Force stringification
|
||||
}
|
||||
/gsex;
|
||||
|
||||
# Trim the document
|
||||
$text =~ s/^\s*(.+?)\s*\z/$1/s if $self->{TRIM};
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
# Special handling for foreach
|
||||
sub _foreach {
|
||||
my ($self, $stash, $term, $expr, $text) = @_;
|
||||
|
||||
# Resolve the expression
|
||||
my $list = $self->_expression($stash, $expr);
|
||||
unless ( ref $list eq 'ARRAY' ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
# Iterate
|
||||
return join '', map {
|
||||
$self->_process( { %$stash, $term => $_ }, $text )
|
||||
} @$list;
|
||||
}
|
||||
|
||||
# Evaluates a stash expression
|
||||
sub _expression {
|
||||
my $cursor = $_[1];
|
||||
my @path = split /\./, $_[2];
|
||||
foreach ( @path ) {
|
||||
# Support for private keys
|
||||
return undef if substr($_, 0, 1) eq '_';
|
||||
|
||||
# Split by data type
|
||||
my $type = ref $cursor;
|
||||
if ( $type eq 'ARRAY' ) {
|
||||
return '' unless /^(?:0|[0-9]\d*)\z/;
|
||||
$cursor = $cursor->[$_];
|
||||
} elsif ( $type eq 'HASH' ) {
|
||||
$cursor = $cursor->{$_};
|
||||
} elsif ( $type ) {
|
||||
$cursor = $cursor->$_();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return $cursor;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Template::Tiny - Template Toolkit reimplemented in as little code as possible
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
my $template = Template::Tiny->new(
|
||||
TRIM => 1,
|
||||
);
|
||||
|
||||
# Print the template results to STDOUT
|
||||
$template->process( <<'END_TEMPLATE', { foo => 'World' } );
|
||||
Hello [% foo %]!
|
||||
END_TEMPLATE
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<Template::Tiny> is a reimplementation of a subset of the functionality from
|
||||
L<Template> Toolkit in as few lines of code as possible.
|
||||
|
||||
It is intended for use in light-usage, low-memory, or low-cpu templating
|
||||
situations, where you may need to upgrade to the full feature set in the
|
||||
future, or if you want the retain the familiarity of TT-style templates.
|
||||
|
||||
For the subset of functionality it implements, it has fully-compatible template
|
||||
and stash API. All templates used with B<Template::Tiny> should be able to be
|
||||
transparently upgraded to full Template Toolkit.
|
||||
|
||||
Unlike Template Toolkit, B<Template::Tiny> will process templates without a
|
||||
compile phase (but despite this is still quicker, owing to heavy use of
|
||||
the Perl regular expression engine.
|
||||
|
||||
=head2 SUPPORTED USAGE
|
||||
|
||||
Only the default C<[% %]> tag style is supported.
|
||||
|
||||
Both the C<[%+ +%]> style explicit whitespace and the C<[%- -%]> style
|
||||
explicit chomp B<are> support, although the C<[%+ +%]> version is unneeded
|
||||
in practice as B<Template::Tiny> does not support default-enabled C<PRE_CHOMP>
|
||||
or C<POST_CHOMP>.
|
||||
|
||||
Variable expressions in the form C<[% foo.bar.baz %]> B<are> supported.
|
||||
|
||||
Appropriate simple behaviours for C<ARRAY> references, C<HASH> references and
|
||||
objects are supported. "VMethods" such as [% array.length %] are B<not>
|
||||
supported at this time.
|
||||
|
||||
C<IF>, C<ELSE> and C<UNLESS> conditional blocks B<are> supported, but only with
|
||||
simple C<[% foo.bar.baz %]> conditions.
|
||||
|
||||
Support for looping (or rather iteration) is available in simple
|
||||
C<[% FOREACH item IN list %]> form B<is> supported. Other loop structures are
|
||||
B<not> supported. Because support for arbitrary or infinite looping is not
|
||||
available, B<Template::Tiny> templates are not turing complete. This is
|
||||
intentional.
|
||||
|
||||
All of the four supported control structures C<IF>/C<ELSE>/C<UNLESS>/C<FOREACH>
|
||||
can be nested to arbitrary depth.
|
||||
|
||||
The treatment of C<_private> hash and method keys is compatible with
|
||||
L<Template> Toolkit, returning null or false rather than the actual content
|
||||
of the hash key or method.
|
||||
|
||||
Anything beyond the above is currently out of scope.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 new
|
||||
|
||||
my $template = Template::Tiny->new(
|
||||
TRIM => 1,
|
||||
);
|
||||
|
||||
The C<new> constructor is provided for compatibility with Template Toolkit.
|
||||
|
||||
The only parameter it currently supports is C<TRIM> (which removes leading
|
||||
and trailing whitespace from processed templates).
|
||||
|
||||
Additional parameters can be provided without error, but will be ignored.
|
||||
|
||||
=head2 process
|
||||
|
||||
# DEPRECATED: Return template results (emits a warning)
|
||||
my $text = $template->process( \$input, $vars );
|
||||
|
||||
# Print template results to STDOUT
|
||||
$template->process( \$input, $vars );
|
||||
|
||||
# Generate template results into a variable
|
||||
my $output = '';
|
||||
$template->process( \$input, $vars, \$output );
|
||||
|
||||
The C<process> method is called to process a template.
|
||||
|
||||
The first parameter is a reference to a text string containing the template
|
||||
text. A reference to a hash may be passed as the second parameter containing
|
||||
definitions of template variables.
|
||||
|
||||
If a third parameter is provided, it must be a scalar reference to be
|
||||
populated with the output of the template.
|
||||
|
||||
For a limited amount of time, the old deprecated interface will continue to
|
||||
be supported. If C<process> is called without a third parameter, and in
|
||||
scalar or list contest, the template results will be returned to the caller.
|
||||
|
||||
If C<process> is called without a third parameter, and in void context, the
|
||||
template results will be C<print()>ed to the currently selected file handle
|
||||
(probably C<STDOUT>) for compatibility with L<Template>.
|
||||
|
||||
=head1 SUPPORT
|
||||
|
||||
Bugs should be reported via the CPAN bug tracker at
|
||||
|
||||
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Template-Tiny>
|
||||
|
||||
For other issues, or commercial enhancement or support, contact the author.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Config::Tiny>, L<CSS::Tiny>, L<YAML::Tiny>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2009 - 2011 Adam Kennedy.
|
||||
|
||||
This program is free software; you can redistribute
|
||||
it and/or modify it under the same terms as Perl itself.
|
||||
|
||||
The full text of the license can be found in the
|
||||
LICENSE file included with this module.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user