Initial Commit
This commit is contained in:
694
database/perl/vendor/lib/Template/VMethods.pm
vendored
Normal file
694
database/perl/vendor/lib/Template/VMethods.pm
vendored
Normal file
@@ -0,0 +1,694 @@
|
||||
#============================================================= -*-Perl-*-
|
||||
#
|
||||
# Template::VMethods
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Module defining virtual methods for the Template Toolkit
|
||||
#
|
||||
# AUTHOR
|
||||
# Andy Wardley <abw@wardley.org>
|
||||
#
|
||||
# COPYRIGHT
|
||||
# Copyright (C) 1996-2015 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$
|
||||
#
|
||||
#============================================================================
|
||||
|
||||
package Template::VMethods;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Scalar::Util qw( blessed looks_like_number );
|
||||
use Template::Filters;
|
||||
require Template::Stash;
|
||||
|
||||
our $VERSION = '3.009';
|
||||
our $DEBUG = 0 unless defined $DEBUG;
|
||||
our $PRIVATE = $Template::Stash::PRIVATE;
|
||||
|
||||
our $ROOT_VMETHODS = {
|
||||
inc => \&root_inc,
|
||||
dec => \&root_dec,
|
||||
};
|
||||
|
||||
our $TEXT_VMETHODS = {
|
||||
item => \&text_item,
|
||||
list => \&text_list,
|
||||
hash => \&text_hash,
|
||||
length => \&text_length,
|
||||
size => \&text_size,
|
||||
empty => \&text_empty,
|
||||
defined => \&text_defined,
|
||||
upper => \&text_upper,
|
||||
lower => \&text_lower,
|
||||
ucfirst => \&text_ucfirst,
|
||||
lcfirst => \&text_lcfirst,
|
||||
match => \&text_match,
|
||||
search => \&text_search,
|
||||
repeat => \&text_repeat,
|
||||
replace => \&text_replace,
|
||||
remove => \&text_remove,
|
||||
split => \&text_split,
|
||||
chunk => \&text_chunk,
|
||||
substr => \&text_substr,
|
||||
trim => \&text_trim,
|
||||
collapse => \&text_collapse,
|
||||
squote => \&text_squote,
|
||||
dquote => \&text_dquote,
|
||||
html => \&Template::Filters::html_filter,
|
||||
xml => \&Template::Filters::xml_filter,
|
||||
};
|
||||
|
||||
our $HASH_VMETHODS = {
|
||||
item => \&hash_item,
|
||||
hash => \&hash_hash,
|
||||
size => \&hash_size,
|
||||
empty => \&hash_empty,
|
||||
each => \&hash_each,
|
||||
keys => \&hash_keys,
|
||||
values => \&hash_values,
|
||||
items => \&hash_items,
|
||||
pairs => \&hash_pairs,
|
||||
list => \&hash_list,
|
||||
exists => \&hash_exists,
|
||||
defined => \&hash_defined,
|
||||
delete => \&hash_delete,
|
||||
import => \&hash_import,
|
||||
sort => \&hash_sort,
|
||||
nsort => \&hash_nsort,
|
||||
};
|
||||
|
||||
our $LIST_VMETHODS = {
|
||||
item => \&list_item,
|
||||
list => \&list_list,
|
||||
hash => \&list_hash,
|
||||
push => \&list_push,
|
||||
pop => \&list_pop,
|
||||
unshift => \&list_unshift,
|
||||
shift => \&list_shift,
|
||||
max => \&list_max,
|
||||
size => \&list_size,
|
||||
empty => \&list_empty,
|
||||
defined => \&list_defined,
|
||||
first => \&list_first,
|
||||
last => \&list_last,
|
||||
reverse => \&list_reverse,
|
||||
grep => \&list_grep,
|
||||
join => \&list_join,
|
||||
sort => \&list_sort,
|
||||
nsort => \&list_nsort,
|
||||
unique => \&list_unique,
|
||||
import => \&list_import,
|
||||
merge => \&list_merge,
|
||||
slice => \&list_slice,
|
||||
splice => \&list_splice,
|
||||
};
|
||||
|
||||
|
||||
#========================================================================
|
||||
# root virtual methods
|
||||
#========================================================================
|
||||
|
||||
sub root_inc {
|
||||
no warnings;
|
||||
my $item = shift;
|
||||
++$item;
|
||||
}
|
||||
|
||||
sub root_dec {
|
||||
no warnings;
|
||||
my $item = shift;
|
||||
--$item;
|
||||
}
|
||||
|
||||
|
||||
#========================================================================
|
||||
# text virtual methods
|
||||
#========================================================================
|
||||
|
||||
sub text_item {
|
||||
$_[0];
|
||||
}
|
||||
|
||||
sub text_list {
|
||||
[ $_[0] ];
|
||||
}
|
||||
|
||||
sub text_hash {
|
||||
{ value => $_[0] };
|
||||
}
|
||||
|
||||
sub text_length {
|
||||
length $_[0];
|
||||
}
|
||||
|
||||
sub text_size {
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub text_empty {
|
||||
return 0 == text_length($_[0]) ? 1 : 0;
|
||||
}
|
||||
|
||||
sub text_defined {
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub text_upper {
|
||||
return uc $_[0];
|
||||
}
|
||||
|
||||
sub text_lower {
|
||||
return lc $_[0];
|
||||
}
|
||||
|
||||
sub text_ucfirst {
|
||||
return ucfirst $_[0];
|
||||
}
|
||||
|
||||
sub text_lcfirst {
|
||||
return lcfirst $_[0];
|
||||
}
|
||||
|
||||
sub text_trim {
|
||||
for ($_[0]) {
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
}
|
||||
return $_[0];
|
||||
}
|
||||
|
||||
sub text_collapse {
|
||||
for ($_[0]) {
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
s/\s+/ /g
|
||||
}
|
||||
return $_[0];
|
||||
}
|
||||
|
||||
sub text_match {
|
||||
my ($str, $search, $global) = @_;
|
||||
return $str unless defined $str and defined $search;
|
||||
my @matches = $global ? ($str =~ /$search/g)
|
||||
: ($str =~ /$search/);
|
||||
return @matches ? \@matches : '';
|
||||
}
|
||||
|
||||
sub text_search {
|
||||
my ($str, $pattern) = @_;
|
||||
return $str unless defined $str and defined $pattern;
|
||||
return $str =~ /$pattern/;
|
||||
}
|
||||
|
||||
sub text_repeat {
|
||||
my ($str, $count) = @_;
|
||||
$str = '' unless defined $str;
|
||||
return '' unless $count;
|
||||
$count ||= 1;
|
||||
return $str x $count;
|
||||
}
|
||||
|
||||
sub text_replace {
|
||||
my ($text, $pattern, $replace, $global) = @_;
|
||||
$text = '' unless defined $text;
|
||||
$pattern = '' unless defined $pattern;
|
||||
$replace = '' unless defined $replace;
|
||||
$global = 1 unless defined $global;
|
||||
|
||||
if ($replace =~ /\$\d+/) {
|
||||
# replacement string may contain backrefs
|
||||
my $expand = sub {
|
||||
my ($chunk, $start, $end) = @_;
|
||||
$chunk =~ s{ \\(\\|\$) | \$ (\d+) }{
|
||||
$1 ? $1
|
||||
: ($2 > $#$start || $2 == 0 || !defined $start->[$2]) ? ''
|
||||
: substr($text, $start->[$2], $end->[$2] - $start->[$2]);
|
||||
}exg;
|
||||
$chunk;
|
||||
};
|
||||
if ($global) {
|
||||
$text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }eg;
|
||||
}
|
||||
else {
|
||||
$text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($global) {
|
||||
$text =~ s/$pattern/$replace/g;
|
||||
}
|
||||
else {
|
||||
$text =~ s/$pattern/$replace/;
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub text_remove {
|
||||
my ($str, $search) = @_;
|
||||
return $str unless defined $str and defined $search;
|
||||
$str =~ s/$search//g;
|
||||
return $str;
|
||||
}
|
||||
|
||||
sub text_split {
|
||||
my ($str, $split, $limit) = @_;
|
||||
$str = '' unless defined $str;
|
||||
|
||||
# For versions of Perl prior to 5.18 we have to be very careful about
|
||||
# spelling out each possible combination of arguments because split()
|
||||
# is very sensitive to them, for example C<split(' ', ...)> behaves
|
||||
# differently to C<$space=' '; split($space, ...)>. Test 33 of
|
||||
# vmethods/text.t depends on this behaviour.
|
||||
|
||||
if ($] < 5.018) {
|
||||
if (defined $limit) {
|
||||
return [ defined $split
|
||||
? split($split, $str, $limit)
|
||||
: split(' ', $str, $limit) ];
|
||||
}
|
||||
else {
|
||||
return [ defined $split
|
||||
? split($split, $str)
|
||||
: split(' ', $str) ];
|
||||
}
|
||||
}
|
||||
|
||||
# split's behavior changed in Perl 5.18.0 making this:
|
||||
# C<$space=' '; split($space, ...)>
|
||||
# behave the same as this:
|
||||
# C<split(' ', ...)>
|
||||
# qr// behaves the same, so use that for user-defined split.
|
||||
|
||||
my $split_re;
|
||||
if (defined $split) {
|
||||
eval {
|
||||
$split_re = qr/$split/;
|
||||
};
|
||||
}
|
||||
$split_re = ' ' unless defined $split_re;
|
||||
$limit ||= 0;
|
||||
return [split($split_re, $str, $limit)];
|
||||
}
|
||||
|
||||
sub text_chunk {
|
||||
my ($string, $size) = @_;
|
||||
my @list;
|
||||
$size ||= 1;
|
||||
if ($size < 0) {
|
||||
# sexeger! It's faster to reverse the string, search
|
||||
# it from the front and then reverse the output than to
|
||||
# search it from the end, believe it nor not!
|
||||
$string = reverse $string;
|
||||
$size = -$size;
|
||||
unshift(@list, scalar reverse $1)
|
||||
while ($string =~ /((.{$size})|(.+))/g);
|
||||
}
|
||||
else {
|
||||
push(@list, $1) while ($string =~ /((.{$size})|(.+))/g);
|
||||
}
|
||||
return \@list;
|
||||
}
|
||||
|
||||
sub text_substr {
|
||||
my ($text, $offset, $length, $replacement) = @_;
|
||||
$offset ||= 0;
|
||||
|
||||
if(defined $length) {
|
||||
if (defined $replacement) {
|
||||
substr( $text, $offset, $length, $replacement );
|
||||
return $text;
|
||||
}
|
||||
else {
|
||||
return substr( $text, $offset, $length );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return substr( $text, $offset );
|
||||
}
|
||||
}
|
||||
|
||||
sub text_squote {
|
||||
my $text = shift;
|
||||
for ($text) {
|
||||
s/(['\\])/\\$1/g;
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub text_dquote {
|
||||
my $text = shift;
|
||||
for ($text) {
|
||||
s/(["\\])/\\$1/g;
|
||||
s/\n/\\n/g;
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
#========================================================================
|
||||
# hash virtual methods
|
||||
#========================================================================
|
||||
|
||||
|
||||
sub hash_item {
|
||||
my ($hash, $item) = @_;
|
||||
$item = '' unless defined $item;
|
||||
return if $PRIVATE && $item =~ /$PRIVATE/;
|
||||
$hash->{ $item };
|
||||
}
|
||||
|
||||
sub hash_hash {
|
||||
$_[0];
|
||||
}
|
||||
|
||||
sub hash_size {
|
||||
scalar keys %{$_[0]};
|
||||
}
|
||||
|
||||
sub hash_empty {
|
||||
return 0 == hash_size($_[0]) ? 1 : 0;
|
||||
}
|
||||
|
||||
sub hash_each {
|
||||
# this will be changed in TT3 to do what hash_pairs() does
|
||||
[ %{ $_[0] } ];
|
||||
}
|
||||
|
||||
sub hash_keys {
|
||||
[ keys %{ $_[0] } ];
|
||||
}
|
||||
|
||||
sub hash_values {
|
||||
[ values %{ $_[0] } ];
|
||||
}
|
||||
|
||||
sub hash_items {
|
||||
[ %{ $_[0] } ];
|
||||
}
|
||||
|
||||
sub hash_pairs {
|
||||
[ map {
|
||||
{ key => $_ , value => $_[0]->{ $_ } }
|
||||
}
|
||||
sort keys %{ $_[0] }
|
||||
];
|
||||
}
|
||||
|
||||
sub hash_list {
|
||||
my ($hash, $what) = @_;
|
||||
$what ||= '';
|
||||
return ($what eq 'keys') ? [ keys %$hash ]
|
||||
: ($what eq 'values') ? [ values %$hash ]
|
||||
: ($what eq 'each') ? [ %$hash ]
|
||||
: # for now we do what pairs does but this will be changed
|
||||
# in TT3 to return [ $hash ] by default
|
||||
[ map { { key => $_ , value => $hash->{ $_ } } }
|
||||
sort keys %$hash
|
||||
];
|
||||
}
|
||||
|
||||
sub hash_exists {
|
||||
exists $_[0]->{ $_[1] };
|
||||
}
|
||||
|
||||
sub hash_defined {
|
||||
# return the item requested, or 1 if no argument
|
||||
# to indicate that the hash itself is defined
|
||||
my $hash = shift;
|
||||
return @_ ? defined $hash->{ $_[0] } : 1;
|
||||
}
|
||||
|
||||
sub hash_delete {
|
||||
my $hash = shift;
|
||||
delete $hash->{ $_ } for @_;
|
||||
}
|
||||
|
||||
sub hash_import {
|
||||
my ($hash, $imp) = @_;
|
||||
$imp = {} unless ref $imp eq 'HASH';
|
||||
@$hash{ keys %$imp } = values %$imp;
|
||||
return '';
|
||||
}
|
||||
|
||||
sub hash_sort {
|
||||
my ($hash) = @_;
|
||||
[ sort { lc $hash->{$a} cmp lc $hash->{$b} } (keys %$hash) ];
|
||||
}
|
||||
|
||||
sub hash_nsort {
|
||||
my ($hash) = @_;
|
||||
[ sort { $hash->{$a} <=> $hash->{$b} } (keys %$hash) ];
|
||||
}
|
||||
|
||||
|
||||
#========================================================================
|
||||
# list virtual methods
|
||||
#========================================================================
|
||||
|
||||
|
||||
sub list_item {
|
||||
$_[0]->[ $_[1] || 0 ];
|
||||
}
|
||||
|
||||
sub list_list {
|
||||
$_[0];
|
||||
}
|
||||
|
||||
sub list_hash {
|
||||
my $list = shift;
|
||||
if (@_) {
|
||||
my $n = shift || 0;
|
||||
return { map { ($n++, $_) } @$list };
|
||||
}
|
||||
no warnings;
|
||||
return { @$list };
|
||||
}
|
||||
|
||||
sub list_push {
|
||||
my $list = shift;
|
||||
push(@$list, @_);
|
||||
return '';
|
||||
}
|
||||
|
||||
sub list_pop {
|
||||
my $list = shift;
|
||||
pop(@$list);
|
||||
}
|
||||
|
||||
sub list_unshift {
|
||||
my $list = shift;
|
||||
unshift(@$list, @_);
|
||||
return '';
|
||||
}
|
||||
|
||||
sub list_shift {
|
||||
my $list = shift;
|
||||
shift(@$list);
|
||||
}
|
||||
|
||||
sub list_max {
|
||||
no warnings;
|
||||
my $list = shift;
|
||||
$#$list;
|
||||
}
|
||||
|
||||
sub list_size {
|
||||
no warnings;
|
||||
my $list = shift;
|
||||
$#$list + 1;
|
||||
}
|
||||
|
||||
sub list_empty {
|
||||
return 0 == list_size($_[0]) ? 1 : 0;
|
||||
}
|
||||
|
||||
sub list_defined {
|
||||
# return the item requested, or 1 if no argument to
|
||||
# indicate that the hash itself is defined
|
||||
my $list = shift;
|
||||
return 1 unless @_; # list.defined is always true
|
||||
return unless looks_like_number $_[0]; # list.defined('bah') is always false
|
||||
return defined $list->[$_[0]]; # list.defined(n)
|
||||
}
|
||||
|
||||
sub list_first {
|
||||
my $list = shift;
|
||||
return $list->[0] unless @_;
|
||||
return [ @$list[0..$_[0]-1] ];
|
||||
}
|
||||
|
||||
sub list_last {
|
||||
my $list = shift;
|
||||
return $list->[-1] unless @_;
|
||||
return [ @$list[-$_[0]..-1] ];
|
||||
}
|
||||
|
||||
sub list_reverse {
|
||||
my $list = shift;
|
||||
[ reverse @$list ];
|
||||
}
|
||||
|
||||
sub list_grep {
|
||||
my ($list, $pattern) = @_;
|
||||
$pattern ||= '';
|
||||
return [ grep /$pattern/, @$list ];
|
||||
}
|
||||
|
||||
sub list_join {
|
||||
my ($list, $joint) = @_;
|
||||
join(defined $joint ? $joint : ' ',
|
||||
map { defined $_ ? $_ : '' } @$list);
|
||||
}
|
||||
|
||||
sub _list_sort_make_key {
|
||||
my ($item, $fields) = @_;
|
||||
my @keys;
|
||||
|
||||
if (ref($item) eq 'HASH') {
|
||||
@keys = map { $item->{ $_ } } @$fields;
|
||||
}
|
||||
elsif (blessed $item) {
|
||||
@keys = map { $item->can($_) ? $item->$_() : $item } @$fields;
|
||||
}
|
||||
else {
|
||||
@keys = $item;
|
||||
}
|
||||
|
||||
# ugly hack to generate a single string using a delimiter that is
|
||||
# unlikely (but not impossible) to be found in the wild.
|
||||
return lc join('/*^UNLIKELY^*/', map { defined $_ ? $_ : '' } @keys);
|
||||
}
|
||||
|
||||
sub list_sort {
|
||||
my ($list, @fields) = @_;
|
||||
return $list unless @$list > 1; # no need to sort 1 item lists
|
||||
return [
|
||||
@fields # Schwartzian Transform
|
||||
? map { $_->[0] } # for case insensitivity
|
||||
sort { $a->[1] cmp $b->[1] }
|
||||
map { [ $_, _list_sort_make_key($_, \@fields) ] }
|
||||
@$list
|
||||
: map { $_->[0] }
|
||||
sort { $a->[1] cmp $b->[1] }
|
||||
map { [ $_, lc $_ ] }
|
||||
@$list,
|
||||
];
|
||||
}
|
||||
|
||||
sub list_nsort {
|
||||
my ($list, @fields) = @_;
|
||||
return $list unless @$list > 1; # no need to sort 1 item lists
|
||||
|
||||
my $sort = sub {
|
||||
my $cmp;
|
||||
|
||||
if(@fields) {
|
||||
# compare each field individually
|
||||
for my $field (@fields) {
|
||||
my $A = _list_sort_make_key($a, [ $field ]);
|
||||
my $B = _list_sort_make_key($b, [ $field ]);
|
||||
($cmp = $A <=> $B) and last;
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $A = _list_sort_make_key($a);
|
||||
my $B = _list_sort_make_key($b);
|
||||
$cmp = $A <=> $B;
|
||||
}
|
||||
|
||||
$cmp;
|
||||
};
|
||||
|
||||
return [ sort $sort @{ $list } ];
|
||||
}
|
||||
|
||||
sub list_unique {
|
||||
my %u;
|
||||
[ grep { ++$u{$_} == 1 } @{$_[0]} ];
|
||||
}
|
||||
|
||||
sub list_import {
|
||||
my $list = shift;
|
||||
push(@$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_);
|
||||
return $list;
|
||||
}
|
||||
|
||||
sub list_merge {
|
||||
my $list = shift;
|
||||
return [ @$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_ ];
|
||||
}
|
||||
|
||||
sub list_slice {
|
||||
my ($list, $from, $to) = @_;
|
||||
$from ||= 0;
|
||||
$to = $#$list unless defined $to;
|
||||
$from += @$list if $from < 0;
|
||||
$to += @$list if $to < 0;
|
||||
return [ @$list[$from..$to] ];
|
||||
}
|
||||
|
||||
sub list_splice {
|
||||
my ($list, $offset, $length, @replace) = @_;
|
||||
if (@replace) {
|
||||
# @replace can contain a list of multiple replace items, or
|
||||
# be a single reference to a list
|
||||
@replace = @{ $replace[0] }
|
||||
if @replace == 1 && ref $replace[0] eq 'ARRAY';
|
||||
return [ splice @$list, $offset, $length, @replace ];
|
||||
}
|
||||
elsif (defined $length) {
|
||||
return [ splice @$list, $offset, $length ];
|
||||
}
|
||||
elsif (defined $offset) {
|
||||
return [ splice @$list, $offset ];
|
||||
}
|
||||
else {
|
||||
return [ splice(@$list) ];
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Template::VMethods - Virtual methods for variables
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The C<Template::VMethods> module implements the virtual methods
|
||||
that can be applied to variables.
|
||||
|
||||
Please see L<Template::Manual::VMethods> for further information.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 1996-2007 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::Stash>, L<Template::Manual::VMethods>
|
||||
|
||||
=cut
|
||||
|
||||
# Local Variables:
|
||||
# mode: perl
|
||||
# perl-indent-level: 4
|
||||
# indent-tabs-mode: nil
|
||||
# End:
|
||||
#
|
||||
# vim: expandtab shiftwidth=4:
|
||||
Reference in New Issue
Block a user