1 #============================================================= -*-Perl-*-
6 # Module defining virtual methods for the Template Toolkit
9 # Andy Wardley <abw@wardley.org>
12 # Copyright (C) 1996-2006 Andy Wardley. All Rights Reserved.
14 # This module is free software; you can redistribute it and/or
15 # modify it under the same terms as Perl itself.
18 # $Id: VMethods.pm 1245 2009-07-04 17:02:52Z abw $
20 #============================================================================
22 package Template::VMethods;
26 use Scalar::Util 'blessed';
27 require Template::Stash;
30 our $DEBUG = 0 unless defined $DEBUG;
31 our $PRIVATE = $Template::Stash::PRIVATE;
33 our $ROOT_VMETHODS = {
38 our $TEXT_VMETHODS = {
42 length => \&text_length,
44 defined => \&text_defined,
45 match => \&text_match,
46 search => \&text_search,
47 repeat => \&text_repeat,
48 replace => \&text_replace,
49 remove => \&text_remove,
50 split => \&text_split,
51 chunk => \&text_chunk,
52 substr => \&text_substr,
55 our $HASH_VMETHODS = {
61 values => \&hash_values,
62 items => \&hash_items,
63 pairs => \&hash_pairs,
65 exists => \&hash_exists,
66 defined => \&hash_defined,
67 delete => \&hash_delete,
68 import => \&hash_import,
70 nsort => \&hash_nsort,
73 our $LIST_VMETHODS = {
79 unshift => \&list_unshift,
80 shift => \&list_shift,
83 defined => \&list_defined,
84 first => \&list_first,
86 reverse => \&list_reverse,
90 nsort => \&list_nsort,
91 unique => \&list_unique,
92 import => \&list_import,
93 merge => \&list_merge,
94 slice => \&list_slice,
95 splice => \&list_splice,
99 #========================================================================
100 # root virtual methods
101 #========================================================================
116 #========================================================================
117 # text virtual methods
118 #========================================================================
145 my ($str, $search, $global) = @_;
146 return $str unless defined $str and defined $search;
147 my @matches = $global ? ($str =~ /$search/g)
148 : ($str =~ /$search/);
149 return @matches ? \@matches : '';
153 my ($str, $pattern) = @_;
154 return $str unless defined $str and defined $pattern;
155 return $str =~ /$pattern/;
159 my ($str, $count) = @_;
160 $str = '' unless defined $str;
161 return '' unless $count;
163 return $str x $count;
167 my ($text, $pattern, $replace, $global) = @_;
168 $text = '' unless defined $text;
169 $pattern = '' unless defined $pattern;
170 $replace = '' unless defined $replace;
171 $global = 1 unless defined $global;
173 if ($replace =~ /\$\d+/) {
174 # replacement string may contain backrefs
176 my ($chunk, $start, $end) = @_;
177 $chunk =~ s{ \\(\\|\$) | \$ (\d+) }{
179 : ($2 > $#$start || $2 == 0) ? ''
180 : substr($text, $start->[$2], $end->[$2] - $start->[$2]);
185 $text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }eg;
188 $text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }e;
193 $text =~ s/$pattern/$replace/g;
196 $text =~ s/$pattern/$replace/;
203 my ($str, $search) = @_;
204 return $str unless defined $str and defined $search;
205 $str =~ s/$search//g;
210 my ($str, $split, $limit) = @_;
211 $str = '' unless defined $str;
213 # we have to be very careful about spelling out each possible
214 # combination of arguments because split() is very sensitive
215 # to them, for example C<split(' ', ...)> behaves differently
216 # to C<$space=' '; split($space, ...)>
218 if (defined $limit) {
219 return [ defined $split
220 ? split($split, $str, $limit)
221 : split(' ', $str, $limit) ];
224 return [ defined $split
225 ? split($split, $str)
226 : split(' ', $str) ];
231 my ($string, $size) = @_;
235 # sexeger! It's faster to reverse the string, search
236 # it from the front and then reverse the output than to
237 # search it from the end, believe it nor not!
238 $string = reverse $string;
240 unshift(@list, scalar reverse $1)
241 while ($string =~ /((.{$size})|(.+))/g);
244 push(@list, $1) while ($string =~ /((.{$size})|(.+))/g);
250 my ($text, $offset, $length, $replacement) = @_;
253 if(defined $length) {
254 if (defined $replacement) {
255 substr( $text, $offset, $length, $replacement );
259 return substr( $text, $offset, $length );
263 return substr( $text, $offset );
268 #========================================================================
269 # hash virtual methods
270 #========================================================================
274 my ($hash, $item) = @_;
275 $item = '' unless defined $item;
276 return if $PRIVATE && $item =~ /$PRIVATE/;
285 scalar keys %{$_[0]};
289 # this will be changed in TT3 to do what hash_pairs() does
298 [ values %{ $_[0] } ];
307 { key => $_ , value => $_[0]->{ $_ } }
314 my ($hash, $what) = @_;
316 return ($what eq 'keys') ? [ keys %$hash ]
317 : ($what eq 'values') ? [ values %$hash ]
318 : ($what eq 'each') ? [ %$hash ]
319 : # for now we do what pairs does but this will be changed
320 # in TT3 to return [ $hash ] by default
321 [ map { { key => $_ , value => $hash->{ $_ } } }
327 exists $_[0]->{ $_[1] };
331 # return the item requested, or 1 if no argument
332 # to indicate that the hash itself is defined
334 return @_ ? defined $hash->{ $_[0] } : 1;
339 delete $hash->{ $_ } for @_;
343 my ($hash, $imp) = @_;
344 $imp = {} unless ref $imp eq 'HASH';
345 @$hash{ keys %$imp } = values %$imp;
351 [ sort { lc $hash->{$a} cmp lc $hash->{$b} } (keys %$hash) ];
356 [ sort { $hash->{$a} <=> $hash->{$b} } (keys %$hash) ];
360 #========================================================================
361 # list virtual methods
362 #========================================================================
366 $_[0]->[ $_[1] || 0 ];
377 return { map { ($n++, $_) } @$list };
418 # return the item requested, or 1 if no argument to
419 # indicate that the hash itself is defined
421 return @_ ? defined $list->[$_[0]] : 1;
426 return $list->[0] unless @_;
427 return [ @$list[0..$_[0]-1] ];
432 return $list->[-1] unless @_;
433 return [ @$list[-$_[0]..-1] ];
442 my ($list, $pattern) = @_;
444 return [ grep /$pattern/, @$list ];
448 my ($list, $joint) = @_;
449 join(defined $joint ? $joint : ' ',
450 map { defined $_ ? $_ : '' } @$list);
453 sub _list_sort_make_key {
454 my ($item, $fields) = @_;
457 if (ref($item) eq 'HASH') {
458 @keys = map { $item->{ $_ } } @$fields;
460 elsif (blessed $item) {
461 @keys = map { $item->can($_) ? $item->$_() : $item } @$fields;
467 # ugly hack to generate a single string using a delimiter that is
468 # unlikely (but not impossible) to be found in the wild.
469 return lc join('/*^UNLIKELY^*/', map { defined $_ ? $_ : '' } @keys);
473 my ($list, @fields) = @_;
474 return $list unless @$list > 1; # no need to sort 1 item lists
476 @fields # Schwartzian Transform
477 ? map { $_->[0] } # for case insensitivity
478 sort { $a->[1] cmp $b->[1] }
479 map { [ $_, _list_sort_make_key($_, \@fields) ] }
482 sort { $a->[1] cmp $b->[1] }
483 map { [ $_, lc $_ ] }
489 my ($list, @fields) = @_;
490 return $list unless @$list > 1; # no need to sort 1 item lists
492 @fields # Schwartzian Transform
493 ? map { $_->[0] } # for case insensitivity
494 sort { $a->[1] <=> $b->[1] }
495 map { [ $_, _list_sort_make_key($_, \@fields) ] }
498 sort { $a->[1] <=> $b->[1] }
499 map { [ $_, lc $_ ] }
506 [ grep { ++$u{$_} == 1 } @{$_[0]} ];
511 push(@$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_);
517 return [ @$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_ ];
521 my ($list, $from, $to) = @_;
523 $to = $#$list unless defined $to;
524 $from += @$list if $from < 0;
525 $to += @$list if $to < 0;
526 return [ @$list[$from..$to] ];
530 my ($list, $offset, $length, @replace) = @_;
532 # @replace can contain a list of multiple replace items, or
533 # be a single reference to a list
534 @replace = @{ $replace[0] }
535 if @replace == 1 && ref $replace[0] eq 'ARRAY';
536 return [ splice @$list, $offset, $length, @replace ];
538 elsif (defined $length) {
539 return [ splice @$list, $offset, $length ];
541 elsif (defined $offset) {
542 return [ splice @$list, $offset ];
545 return [ splice(@$list) ];
555 Template::VMethods - Virtual methods for variables
559 The C<Template::VMethods> module implements the virtual methods
560 that can be applied to variables.
562 Please see L<Template::Manual::VMethods> for further information.
566 Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
570 Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
572 This module is free software; you can redistribute it and/or
573 modify it under the same terms as Perl itself.
577 L<Template::Stash>, L<Template::Manual::VMethods>
583 # perl-indent-level: 4
584 # indent-tabs-mode: nil
587 # vim: expandtab shiftwidth=4: