1package Template::Alloy::VMethod;
2
3=head1 NAME
4
5Template::Alloy::VMethod - VMethod role.
6
7=cut
8
9use strict;
10use warnings;
11use Template::Alloy;
12use base qw(Exporter);
13our @EXPORT_OK = qw(define_vmethod
14                    $ITEM_OPS   $ITEM_METHODS
15                    $SCALAR_OPS
16                    $LIST_OPS   $LIST_METHODS
17                    $HASH_OPS
18                    $FILTER_OPS
19                    $VOBJS);
20
21sub new { die "This class is a role for use by packages such as Template::Alloy" }
22
23###----------------------------------------------------------------###
24
25our ($JSON, $JSONP);
26sub json  { $JSON  ||= do { require JSON; JSON->new->utf8->allow_nonref->allow_unknown->allow_blessed->convert_blessed->canonical } }
27sub jsonp { $JSONP ||= do { require JSON; JSON->new->utf8->allow_nonref->allow_unknown->allow_blessed->convert_blessed->canonical->pretty } }
28
29our $SCALAR_OPS = our $ITEM_OPS = {
30    '0'      => sub { $_[0] },
31    abs      => sub { no warnings; abs shift },
32    atan2    => sub { no warnings; atan2($_[0], $_[1]) },
33    chunk    => \&vmethod_chunk,
34    collapse => sub { local $_ = $_[0]; s/^\s+//; s/\s+$//; s/\s+/ /g; $_ },
35    cos      => sub { no warnings; cos $_[0] },
36    defined  => sub { defined $_[0] ? 1 : '' },
37    dquote   => sub { local $_ = $_[0]; return if ! $_; s/([\"\\])/\\$1/g; s/\n/\\n/g; $_ },
38    exp      => sub { no warnings; exp $_[0] },
39    fmt      => \&vmethod_fmt_scalar,
40    'format' => \&vmethod_format,
41    hash     => sub { {value => $_[0]} },
42    hex      => sub { no warnings; hex $_[0] },
43    html     => sub { local $_ = $_[0]; return $_ if ! $_; s/&/&amp;/g; s/</&lt;/g; s/>/&gt;/g; s/\"/&quot;/g; $_ },
44    indent   => \&vmethod_indent,
45    int      => sub { no warnings; int $_[0] },
46    item     => sub { $_[0] },
47    js       => sub { local $_ = $_[0]; return if ! $_; s/\n/\\n/g; s/\r/\\r/g; s/(?<!\\)([\"\'])/\\$1/g; $_ },
48    json     => sub { return json()->encode($_[0]) if ! $_[1]; my $j = jsonp()->encode($_[0]); chomp $j; $j },
49    lc       => sub { lc $_[0] },
50    lcfirst  => sub { lcfirst $_[0] },
51    length   => sub { defined($_[0]) ? length($_[0]) : 0 },
52    list     => sub { [$_[0]] },
53    log      => sub { no warnings; log $_[0] },
54    lower    => sub { lc $_[0] },
55    match    => \&vmethod_match,
56    new      => sub { defined $_[0] ? $_[0] : '' },
57    none     => sub { $_[0] },
58    null     => sub { '' },
59    oct      => sub { no warnings; oct $_[0] },
60    print    => sub { no warnings; "@_" },
61    rand     => sub { no warnings; rand shift },
62    remove   => sub { vmethod_replace(shift, shift, '', 1) },
63    repeat   => \&vmethod_repeat,
64    replace  => \&vmethod_replace,
65    'return' => \&vmethod_return,
66    search   => sub { my ($str, $pat) = @_; return $str if ! defined $str || ! defined $pat; return $str =~ /$pat/ },
67    sin      => sub { no warnings; sin $_[0] },
68    size     => sub { 1 },
69    split    => \&vmethod_split,
70    sprintf  => sub { no warnings; my $pat = shift; sprintf($pat, @_) },
71    sqrt     => sub { no warnings; sqrt $_[0] },
72    squote   => sub { local $_ = $_[0]; return if ! $_; s/([\'\\])/\\$1/g; $_ },
73    srand    => sub { no warnings; srand $_[0]; '' },
74    stderr   => sub { print STDERR $_[0]; '' },
75    substr   => \&vmethod_substr,
76    trim     => sub { local $_ = $_[0]; s/^\s+//; s/\s+$//; $_ },
77    uc       => sub { uc $_[0] },
78    ucfirst  => sub { ucfirst $_[0] },
79    upper    => sub { uc $_[0] },
80    uri      => \&vmethod_uri,
81    url      => \&vmethod_url,
82    xml      => sub { local $_ = $_[0]; s/&/&amp;/g; s/</&lt;/g; s/>/&gt;/g; s/\"/&quot;/g; s/\'/&apos;/g; $_ },
83};
84
85our $ITEM_METHODS = {
86    eval     => \&Template::Alloy::item_method_eval,
87    evaltt   => \&Template::Alloy::item_method_eval,
88    file     => \&item_method_redirect,
89    redirect => \&item_method_redirect,
90    block_exists => sub { defined($_[1]) && UNIVERSAL::isa($_[0], 'HASH') && $_[0]->{'BLOCKS'} && exists($_[0]->{'BLOCKS'}->{$_[1]}) || 0 },
91};
92
93our $FILTER_OPS = {}; # generally - non-dynamic filters belong in scalar ops
94
95our $LIST_OPS = {
96    defined  => sub { return 1 if @_ == 1; defined $_[0]->[ defined($_[1]) ? $_[1] : 0 ] },
97    first    => sub { my ($ref, $i) = @_; return $ref->[0] if ! $i; return [@{$ref}[0 .. $i - 1]]},
98    fmt      => \&vmethod_fmt_list,
99    grep     => sub { no warnings; my ($ref, $pat) = @_; UNIVERSAL::isa($pat, 'CODE') ? [grep {$pat->($_)} @$ref] : [grep {/$pat/} @$ref] },
100    hash     => sub { no warnings; my $list = shift; return {@$list} if ! @_; my $i = shift || 0; return {map {$i++ => $_} @$list} },
101    import   => sub { my $ref = shift; push @$ref, grep {defined} map {ref eq 'ARRAY' ? @$_ : undef} @_; '' },
102    item     => sub { $_[0]->[ $_[1] || 0 ] },
103    join     => sub { my ($ref, $join) = @_; $join = ' ' if ! defined $join; no warnings; return join $join, @$ref },
104    json     => sub { return json()->encode($_[0]) if ! $_[1]; my $j = jsonp()->encode($_[0]); chomp $j; $j },
105    last     => sub { my ($ref, $i) = @_; return $ref->[-1] if ! $i; return [@{$ref}[-$i .. -1]]},
106    list     => sub { $_[0] },
107    map      => sub { no warnings; my ($ref, $code) = @_; UNIVERSAL::isa($code, 'CODE') ? [map {$code->($_)} @$ref] : [map {$code} @$ref] },
108    max      => sub { no warnings; $#{ $_[0] } },
109    merge    => sub { my $ref = shift; return [ @$ref, grep {defined} map {ref eq 'ARRAY' ? @$_ : undef} @_ ] },
110    new      => sub { no warnings; return [@_] },
111    null     => sub { '' },
112    nsort    => \&vmethod_nsort,
113    pick     => \&vmethod_pick,
114    pop      => sub { pop @{ $_[0] } },
115    push     => sub { my $ref = shift; push @$ref, @_; return '' },
116    'return' => \&vmethod_return,
117    reverse  => sub { [ reverse @{ $_[0] } ] },
118    shift    => sub { shift  @{ $_[0] } },
119    size     => sub { no warnings; scalar @{ $_[0] } },
120    slice    => sub { my ($ref, $a, $b) = @_; $a ||= 0; $b = $#$ref if ! defined $b; return [@{$ref}[$a .. $b]] },
121    sort     => \&vmethod_sort,
122    splice   => \&vmethod_splice,
123    unique   => sub { my %u; return [ grep { ! $u{$_}++ } @{ $_[0] } ] },
124    unshift  => sub { my $ref = shift; unshift @$ref, @_; return '' },
125};
126
127our $LIST_METHODS = {
128};
129
130our $HASH_OPS = {
131    defined  => sub { return 1 if @_ == 1; defined $_[0]->{ defined($_[1]) ? $_[1] : '' } },
132    delete   => sub { my $h = shift; delete @{ $h }{map {defined($_) ? $_ : ''} @_}; '' },
133    each     => sub { [%{ $_[0] }] },
134    exists   => sub { exists $_[0]->{ defined($_[1]) ? $_[1] : '' } },
135    fmt      => \&vmethod_fmt_hash,
136    hash     => sub { $_[0] },
137    import   => sub { my ($a, $b) = @_; @{$a}{keys %$b} = values %$b if ref($b) eq 'HASH'; '' },
138    item     => sub { my ($h, $k) = @_; $k = '' if ! defined $k; $Template::Alloy::QR_PRIVATE && $k =~ $Template::Alloy::QR_PRIVATE ? undef : $h->{$k} },
139    items    => sub { [ %{ $_[0] } ] },
140    json     => sub { return json()->encode($_[0]) if ! $_[1]; my $j = jsonp()->encode($_[0]); chomp $j; $j },
141    keys     => sub { [keys %{ $_[0] }] },
142    list     => \&vmethod_list_hash,
143    new      => sub { no warnings; return (@_ == 1 && ref $_[-1] eq 'HASH') ? $_[-1] : {@_} },
144    null     => sub { '' },
145    nsort    => sub { my $ref = shift; [sort {   $ref->{$a} <=>    $ref->{$b}} keys %$ref] },
146    pairs    => sub { [map { {key => $_, value => $_[0]->{$_}} } sort keys %{ $_[0] } ] },
147    'return' => \&vmethod_return,
148    size     => sub { scalar keys %{ $_[0] } },
149    sort     => sub { my $ref = shift; [sort {lc $ref->{$a} cmp lc $ref->{$b}} keys %$ref] },
150    values   => sub { [values %{ $_[0] }] },
151};
152
153our $VOBJS = {
154    Text => $SCALAR_OPS,
155    List => $LIST_OPS,
156    Hash => $HASH_OPS,
157};
158foreach (values %$VOBJS) {
159    $_->{'Text'} = $_->{'fmt'};
160    $_->{'Hash'} = $_->{'hash'};
161    $_->{'List'} = $_->{'list'};
162}
163
164###----------------------------------------------------------------###
165### long virtual methods or filters
166### many of these vmethods have used code from Template/Stash.pm to
167### assure conformance with the TT spec.
168
169sub define_vmethod {
170    my ($self, $type, $name, $sub) = @_;
171    if (   $type =~ /scalar|item|text/i) { $SCALAR_OPS->{$name} = $sub }
172    elsif ($type =~ /array|list/i ) { $LIST_OPS->{  $name} = $sub }
173    elsif ($type =~ /hash/i       ) { $HASH_OPS->{  $name} = $sub }
174    elsif ($type =~ /filter/i     ) { $FILTER_OPS->{$name} = $sub }
175    else { die "Invalid type vmethod type $type" }
176    return 1;
177}
178
179sub vmethod_fmt_scalar {
180    my $str = shift; $str = ''   if ! defined $str;
181    my $pat = shift; $pat = '%s' if ! defined $pat;
182    no warnings;
183    return @_ ? sprintf($pat, $_[0], $str)
184              : sprintf($pat, $str);
185}
186
187sub vmethod_fmt_list {
188    my $ref = shift || return '';
189    my $pat = shift; $pat = '%s' if ! defined $pat;
190    my $sep = shift; $sep = ' '  if ! defined $sep;
191    no warnings;
192    return @_ ? join($sep, map {sprintf $pat, $_[0], $_} @$ref)
193              : join($sep, map {sprintf $pat, $_} @$ref);
194}
195
196sub vmethod_fmt_hash {
197    my $ref = shift || return '';
198    my $pat = shift; $pat = "%s\t%s" if ! defined $pat;
199    my $sep = shift; $sep = "\n"     if ! defined $sep;
200    no warnings;
201    return ! @_    ? join($sep, map {sprintf $pat, $_, $ref->{$_}} sort keys %$ref)
202         : @_ == 1 ? join($sep, map {sprintf $pat, $_[0], $_, $ref->{$_}} sort keys %$ref) # don't get to pick - it applies to the key
203         :           join($sep, map {sprintf $pat, $_[0], $_, $_[1], $ref->{$_}} sort keys %$ref);
204}
205
206sub vmethod_chunk {
207    my $str  = shift;
208    my $size = shift || 1;
209    my @list;
210    if ($size < 0) { # chunk from the opposite end
211        $str = reverse $str;
212        $size = -$size;
213        unshift(@list, scalar reverse $1) while $str =~ /( .{$size} | .+ )/xg;
214    } else {
215        push(@list, $1)                   while $str =~ /( .{$size} | .+ )/xg;
216    }
217    return \@list;
218}
219
220sub vmethod_indent {
221    my $str = shift; $str = '' if ! defined $str;
222    my $pre = shift; $pre = 4  if ! defined $pre;
223    $pre = ' ' x $pre if $pre =~ /^\d+$/;
224    $str =~ s/^/$pre/mg;
225    return $str;
226}
227
228sub vmethod_format {
229    my $str = shift; $str = ''   if ! defined $str;
230    my $pat = shift; $pat = '%s' if ! defined $pat;
231    if (@_) {
232        return join "\n", map{ sprintf $pat, $_[0], $_ } split(/\n/, $str);
233    } else {
234        return join "\n", map{ sprintf $pat, $_ } split(/\n/, $str);
235    }
236}
237
238sub vmethod_list_hash {
239    my ($hash, $what) = @_;
240    $what = 'pairs' if ! $what || $what !~ /^(keys|values|each|pairs)$/;
241    return $HASH_OPS->{$what}->($hash);
242}
243
244
245sub vmethod_match {
246    my ($str, $pat, $global) = @_;
247    return [] if ! defined $str || ! defined $pat;
248    my @res = $global ? ($str =~ /$pat/g) : ($str =~ /$pat/);
249    return @res ? \@res : '';
250}
251
252sub vmethod_nsort {
253    my ($list, $field) = @_;
254    return defined($field)
255        ? [map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, (ref $_ eq 'HASH' ? $_->{$field}
256                                                               : UNIVERSAL::can($_, $field) ? $_->$field()
257                                                               : $_)]} @$list ]
258        : [sort {$a <=> $b} @$list];
259}
260
261sub vmethod_pick {
262    my $ref = shift;
263    no warnings;
264    my $n   = int(shift);
265    $n = 1 if $n < 1;
266    my @ind = map { $ref->[ rand @$ref ] } 1 .. $n;
267    return $n == 1 ? $ind[0] : \@ind;
268}
269
270sub vmethod_repeat {
271    my ($str, $n, $join) = @_;
272    return '' if ! defined $str || ! length $str;
273    $n = 1 if ! defined($n) || ! length $n;
274    $join = '' if ! defined $join;
275    return join $join, ($str) x $n;
276}
277
278### This method is a combination of my submissions along
279### with work from Andy Wardley, Sergey Martynoff, Nik Clayton, and Josh Rosenbaum
280sub vmethod_replace {
281    my ($text, $pattern, $replace, $global) = @_;
282    $text      = '' unless defined $text;
283    $pattern   = '' unless defined $pattern;
284    $replace   = '' unless defined $replace;
285    $global    = 1  unless defined $global;
286    my $expand = sub {
287        my ($chunk, $start, $end) = @_;
288        $chunk =~ s{ \\(\\|\$) | \$ (\d+) }{
289            $1 ? $1
290                : ($2 > $#$start || $2 == 0) ? ''
291                : substr($text, $start->[$2], $end->[$2] - $start->[$2]);
292        }exg;
293        $chunk;
294    };
295    if ($global) {
296        $text =~ s{$pattern}{ $expand->($replace, [@-], [@+]) }eg;
297    } else {
298        $text =~ s{$pattern}{ $expand->($replace, [@-], [@+]) }e;
299    }
300    return $text;
301}
302
303sub vmethod_return {
304    my $obj = shift;
305    Template::Alloy->throw('return', {return_val => $obj});
306}
307
308sub vmethod_sort {
309    my ($list, $field) = @_;
310    if (! defined $field) {
311        return [map {$_->[0]} sort {$a->[1] cmp $b->[1]} map {[$_, lc $_]} @$list ]; # case insensitive
312    } elsif (UNIVERSAL::isa($field, 'CODE')) {
313        return [sort {int($field->($a, $b))} @$list];
314    } else {
315        return [map {$_->[0]} sort {$a->[1] cmp $b->[1]} map {[$_, lc(ref $_ eq 'HASH' ? $_->{$field}
316                                                                      : UNIVERSAL::can($_, $field) ? $_->$field()
317                                                                      : $_)]} @$list ];
318    }
319}
320
321sub vmethod_splice {
322    my ($ref, $i, $len, @replace) = @_;
323    @replace = @{ $replace[0] } if @replace == 1 && ref $replace[0] eq 'ARRAY';
324    if (defined $len) {
325        return [splice @$ref, $i || 0, $len, @replace];
326    } elsif (defined $i) {
327        return [splice @$ref, $i];
328    } else {
329        return [splice @$ref];
330    }
331}
332
333sub vmethod_split {
334    my ($str, $pat, $lim) = @_;
335    $str = '' if ! defined $str;
336    if (defined $lim) { return defined $pat ? [split $pat, $str, $lim] : [split ' ', $str, $lim] }
337    else              { return defined $pat ? [split $pat, $str      ] : [split ' ', $str      ] }
338}
339
340sub vmethod_substr {
341    my ($str, $i, $len, $replace) = @_;
342    $i ||= 0;
343    return '' if ! defined $str;
344    return substr($str, $i)       if ! defined $len;
345    return substr($str, $i, $len) if ! defined $replace;
346    substr($str, $i, $len, $replace);
347    return $str;
348}
349
350sub vmethod_uri {
351    my $str = shift;
352    return '' if ! defined $str;
353    utf8::upgrade($str) if defined &utf8::upgrade;
354    $str =~ s/([^A-Za-z0-9\-_.!~*\'()])/sprintf('%%%02X', ord($1))/eg;
355    return $str;
356}
357
358sub vmethod_url {
359    my $str = shift;
360    return '' if ! defined $str;
361    utf8::upgrade($str) if defined &utf8::upgrade;
362    $str =~ s/([^;\/?:@&=+\$,A-Za-z0-9\-_.!~*\'()])/sprintf('%%%02X', ord($1))/eg;
363    return $str;
364}
365
366sub item_method_redirect {
367    my ($t, $text, $file, $options) = @_;
368    my $path = $t->{'OUTPUT_PATH'} || $t->throw('redirect', 'OUTPUT_PATH is not set');
369    $t->throw('redirect', 'Invalid filename - cannot include "/../"')
370        if $file =~ m{(^|/)\.\./};
371
372    if (! -d $path) {
373        require File::Path;
374        File::Path::mkpath($path) || $t->throw('redirect', "Couldn't mkpath \"$path\": $!");
375    }
376    open (my $fh, '>', "$path/$file") || $t->throw('redirect', "Couldn't open \"$file\": $!");
377    if (my $bm = (! $options) ? 0 : ref($options) ? $options->{'binmode'} : $options) {
378        if (+$bm == 1) { binmode $fh }
379        else { binmode $fh, $bm}
380    }
381    print $fh $text;
382    return '';
383}
384
385###----------------------------------------------------------------###
386
3871;
388
389__END__
390
391=head1 DESCRIPTION
392
393The Template::Alloy::VMethod role provides all of the extra vmethods,
394filters, and virtual objects that add to the base feature set of
395Template::Alloy.  Most of the vmethods listed here are similar to
396those provided by Template::Toolkit.  We will try to keep
397Template::Alloy's in sync.  Template::Alloy also provides several
398extra methods that are needed for HTML::Template::Expr support.
399
400=head1 ROLE METHODS
401
402=over 4
403
404=item define_vmethod
405
406Defines a vmethod.  See L<Template::Alloy> for more details.
407
408=item C<vmethod_*>
409
410Methods by these names implement virtual methods that are more complex
411than oneliners.  These methods are not exposed via the role.
412
413=item C<filter_*>
414
415Methods by these names implement filters that are more complex than
416one liners.  These methods are not exposed via the role.
417
418=back
419
420=head1 VIRTUAL METHOD LIST
421
422The following is the list of builtin virtual methods and filters that
423can be called on each type of data.
424
425In Template::Alloy, the "|" operator can be used to call virtual
426methods just the same way that the "." operator can.  The main
427difference between the two is that on access to hashrefs or objects,
428the "|" means to always call the virtual method or filter rather than
429looking in the hashref for a key by that name, or trying to call that
430method on the object.  This is similar to how TT3 will function.
431
432Virtual methods are also made available via Virtual Objects which
433are discussed in a later section.
434
435=head2 SCALAR VIRTUAL METHODS AND FILTERS
436
437The following is the list of builtin virtual methods and filters that
438can be called on scalar data types.  In Alloy and TT3, filters and
439virtual methods are more closely related than in TT2.  In general
440anywhere a virtual method can be used a filter can be used also - and
441likewise all scalar virtual methods can be used as filters.
442
443In addition to the filters listed below, Alloy will automatically load
444Template::Filters and use them if Template::Toolkit is installed.
445
446In addition to the scalar virtual methods, any scalar will be
447automatically converted to a single item list if a list virtual method
448is called on it.
449
450Scalar virtual methods are also available through the "Text" virtual
451object (except for true filters such as eval and redirect).
452
453All scalar virtual methods are available as top level functions as well.
454This is not true of TT2.  In Template::Alloy the following are equivalent:
455
456    [% "abc".length %]
457    [% length("abc") %]
458
459You may set VMETHOD_FUNCTIONS to 0 to disable this behavior.
460
461=over 4
462
463=item '0'
464
465    [% item = 'foo' %][% item.0 %] Returns foo.
466
467Allows for scalars to mask as arrays (scalars already will, but this
468allows for more direct access).
469
470Not available in TT.
471
472=item abs
473
474    [% -1.abs %] Returns the absolute value
475
476=item atan2
477
478    [% pi = 4 * 1.atan2(1) %]
479
480Returns the arctangent.  The item itself represents Y, the passed argument represents X.
481
482Not available in TT - available in HTML::Template::Expr.
483
484=item chunk
485
486    [% item.chunk(60).join("\n") %] Split string up into a list of chunks of text 60 chars wide.
487
488=item collapse
489
490    [% item.collapse %] Strip leading and trailing whitespace and collapse all other space to one space.
491
492=item cos
493
494    [% item.cos %] Returns the cosine of the item.
495
496Not available in TT - available in HTML::Template::Expr.
497
498=item defined
499
500    [% item.defined %] Always true - because the undef sub translates all undefs to ''.
501
502=item eval
503
504    [% item.eval %]
505
506Process the string as though it was a template.  This will start the
507parsing engine and will use the same configuration as the current
508process.  Alloy is several times faster at doing this than TT is and
509is considered acceptable.
510
511This is a filter and is not available via the Text virtual object.
512
513Template::Alloy has attempted to make the compile process painless and
514fast.  By default an MD5 sum of evaled is taken and used to cache the
515AST.  This behavior can be disabled using the CACHE_STR_REFS
516configuration item.
517
518Template::Alloy also allows for named parameters to be passed to the
519eval filter.
520
521    [% '[% 1 + 2 %]'.eval %]
522
523    [% '${ 1 + 2 }'.eval(interpolate => 1) %]
524
525    [% "#get( 1 + 2)"|eval(syntax => 'velocity') %]
526
527    [% '<TMPL_VAR EXPR="1 + 2">'.eval(syntax => 'hte') %]
528
529    [% '<TMPL_VAR EXPR="1 + 2">'.eval(syntax => 'hte') %]
530
531=item evaltt
532
533    Same as the eval filter.
534
535=item exp
536
537    [% 1.exp %] Something like 2.71828182845905
538
539Returns "e" to the power of the item.
540
541=item file
542
543    Same as the redirect filter.
544
545=item fmt
546
547    [% item.fmt('%d') %]
548    [% item.fmt('%6s') %]
549    [% item.fmt('%*s', 6) %]
550
551Similar to format.  Returns a string formatted with the passed
552pattern.  Default pattern is %s.  Opposite from of the sprintf
553vmethod.
554
555=item format
556
557    [% item.format('%d') %]
558    [% item.format('%6s') %]
559    [% item.format('%*s', 6) %]
560
561Print the string out in the specified format.  It is similar to the
562"fmt" virtual method, except that the item is split on newline and
563each line is processed separately.
564
565=item hash
566
567    [% item.hash %] Returns a one item hash with a key of "value" and a value of the item.
568
569
570=item hex
571
572    [% "FF".hex %]
573
574Returns the decimal value of the passed hex numbers.  Note that you
575may also just use [% 0xFF %].
576
577Not available in TT - available in HTML::Template::Expr.
578
579=item html
580
581    [% item.html %] Performs a very basic html encoding (swaps out &, <, > and " with the corresponding html entities)
582    Previously it also encoded the ' but this behavior did not match TT2's behavior.  Use .xml to obtain that behavior.
583
584=item indent
585
586    [% item.indent(3) %] Indent by that number of spaces if an integer is passed (default is 4).
587
588    [% item.indent("Foo: ") %] Add the string "Foo: " to the beginning of every line.
589
590=item int
591
592    [% item.int %] Return the integer portion of the value (0 if none).
593
594=item json
595
596    [% item.json    %] Returns a JSON encoded representation.
597    [% item.json(1) %] Returns a pretty JSON encoded representation.
598
599=item lc
600
601Same as the lower vmethod.  Returns the lowercased version of the item.
602
603=item lcfirst
604
605    [% item.lcfirst %] Lowercase the leading letter.
606
607=item length
608
609    [% item.length %] Return the length of the string.
610
611=item list
612
613    [% item.list %] Returns a list (arrayref) with a single value of the item.
614
615=item log
616
617    [% 8.exp.log %] Equal to 8.
618
619Returns the natural log base "e" of the item.
620
621Not available in TT - available in HTML::Template::Expr.
622
623=item lower
624
625    [% item.lower %] Return the string lowercased.
626
627=item match
628
629    [% item.match("(\w+) (\w+)") %] Return a list of items matching the pattern.
630
631    [% item.match("(\w+) (\w+)", 1) %] Same as before - but match globally.
632
633In Template::Alloy and TT3 you can use regular expressions notation as well.
634
635    [% item.match( /(\w+) (\w+)/ ) %] Same as before.
636
637    [% item.match( m{(\w+) (\w+)} ) %] Same as before.
638
639Note that you can't use the 'g' regex modifier - you must pass the second
640argument to turn on global match.
641
642=item none
643
644Returns the item without modification.  This was added as a compliment case
645when the AUTO_FILTER configuration is specified.  Note that it must be
646called as a filter to bypass the application of the AUTO_FILTER.
647
648    [% item | none %] Returns the item without modification.
649
650=item null
651
652    [% item.null %] Return nothing.
653
654If the item contains a coderef it will still be executed, but the result would
655be ignored.
656
657=item oct
658
659    [% "377".oct %]
660
661Returns the decimal value of the octal string.  On recent versions of perl you
662may also pass numbers starting with 0x which will be interpreted as hexadecimal,
663and starting with 0b which will be interpreted as binary.
664
665Not available in TT - available in HTML::Template::Expr.
666
667=item rand
668
669    [% item = 10; item.rand %] Returns a number greater or equal to 0 but less than 10.
670    [% 1.rand %]
671
672Note: This filter is not available as of TT2.15.
673
674=item remove
675
676    [% item.remove("\s+") %] Same as replace - but is global and replaces with nothing.
677
678=item redirect
679
680    [% item.redirect("output_file.html") %]
681
682Writes the contents out to the specified file.  The filename must be
683relative to the OUTPUT_PATH configuration variable and the OUTPUT_PATH
684variable must be set.
685
686This is a filter and is not available via the Text virtual object.
687
688=item repeat
689
690    [% item.repeat(3) %] Repeat the item 3 times
691
692    [% item.repeat(3, ' | ') %] Repeat the item 3 times separated with ' | '
693
694=item replace
695
696    [% item.replace("\s+", "&nbsp;") %] Globally replace all space with &nbsp;
697
698    [% item.replace("foo", "bar", 0) %] Replace only the first instance of foo with bar.
699
700    [% item.replace("(\w+)", "($1)") %] Surround all words with parenthesis.
701
702In Template::Alloy and TT3 you may also use normal regular expression notation.
703
704    [% item.replace(/(\w+)/, "($1)") %] Same as before.
705
706Note that you can't use the 'g' regex modifier - global match is on by default.
707You must pass the third argument of false to turn off global match.
708
709=item return
710
711Returns the item from the inner most block, macro, or file.  Similar to the
712RETURN directive.
713
714    [% item.return %]
715    [% RETURN item %]
716
717=item search
718
719    [% item.search("(\w+)") %] Tests if the given pattern is in the string.
720
721In Template::Alloy and TT3 you may also use normal regular expression notation.
722
723    [% item.search(/(\w+)/) %] Same as before.
724
725=item sin
726
727    [% item.sin %] Returns the sine of the item.
728
729=item size
730
731    [% item.size %] Always returns 1.
732
733=item split
734
735    [% item.split %] Returns an arrayref from the item split on " "
736
737    [% item.split("\s+") %] Returns an arrayref from the item split on /\s+/
738
739    [% item.split("\s+", 3) %] Returns an arrayref from the item split on /\s+/ splitting until 3 elements are found.
740
741In Template::Alloy and TT3 you may also use normal regular expression notation.
742
743    [% item.split( /\s+/, 3 ) %] Same as before.
744
745=item sprintf
746
747    [% item = "%d %d" %]
748    [% item.sprintf(7, 8) %]
749
750Uses the pattern stored in self, and passes it to sprintf with the passed arguments.
751Opposite from the fmt vmethod.
752
753=item sqrt
754
755    [% item.sqrt %]
756
757Returns the square root of the number.
758
759=item srand
760
761Calls the perl srand function to set the internal random seed.  This
762will affect future calls to the rand vmethod.
763
764=item stderr
765
766    [% item.stderr %] Print the item to the current STDERR handle.
767
768=item substr
769
770    [% item.substr(i) %] Returns a substring of item starting at i and going to the end of the string.
771
772    [% item.substr(i, n) %] Returns a substring of item starting at i and going n characters.
773
774=item trim
775
776    [% item.trim %] Strips leading and trailing whitespace.
777
778=item uc
779
780Same as the upper command.  Returns uppercased string.
781
782=item ucfirst
783
784    [% item.ucfirst %] Uppercase the leading letter.
785
786=item upper
787
788    [% item.upper %] Return the string uppercased.
789
790=item uri
791
792    [% item.uri %] Perform a very basic URI encoding.
793
794=item url
795
796    [% item.url %] Perform a URI encoding - but some characters such
797                   as : and / are left intact.
798
799=item xml
800
801    [% item.xml %] Performs a very basic xml encoding (swaps out &, <, >, ' and " with the corresponding xml entities)
802
803=back
804
805=head2 LIST VIRTUAL METHODS
806
807The following methods can be called on an arrayref type data
808structures (scalar types will automatically promote to a single
809element list and call these methods if needed):
810
811Additionally, list virtual methods can be accessed via the List
812Virtual Object.
813
814=over 4
815
816=item fmt
817
818    [% mylist.fmt('%s', ', ') %]
819    [% mylist.fmt('%6s', ', ') %]
820    [% mylist.fmt('%*s', ', ', 6) %]
821
822Passed a pattern and an string to join on.  Returns a string of the
823values of the list formatted with the passed pattern and joined with
824the passed string.  Default pattern is %s and the default join string
825is a space.
826
827=item first
828
829    [% mylist.first(3) %]  Returns a list of the first 3 items in the list.
830
831=item grep
832
833    [% mylist.grep("^\w+\.\w+$") %] Returns a list of all items matching the pattern.
834
835In Template::Alloy and TT3 you may also use normal regular expression notation.
836
837    [% mylist.grep(/^\w+\.\w+$/) %] Same as before.
838
839    [% mylist.grep(->(a){ a.foo.bar }
840
841=item hash
842
843    [% mylist.hash %] Returns a hashref with the array indexes as keys and the values as values.
844
845=item join
846
847    [% mylist.join %] Joins on space.
848    [% mylist.join(", ") Joins on the passed argument.
849
850=item json
851
852    [% mylist.json    %] Returns a JSON encoded representation.
853    [% mylist.json(1) %] Returns a pretty JSON encoded representation.
854
855=item last
856
857    [% mylist.last(3) %]  Returns a list of the last 3 items in the list.
858
859=item list
860
861    [% mylist.list %] Returns a reference to the list.
862
863=item map (Not in TT2)
864
865    [% mylist.map(->{ this.upper }) %] Returns a list with the macro played on each item.
866    [% mylist.map(->(a){ a.upper }) %] Same thing
867
868The RETURN directive or return list, item, and hash vmethods allow for
869returning more interesting items.
870
871    [% [1..3].map(->(a){ [1..a].return }) %]
872
873=item max
874
875    [% mylist.max %] Returns the last item in the array.
876
877=item merge
878
879    [% mylist.merge(list2) %] Returns a new list with all defined items from list2 added.
880
881=item nsort
882
883    [% mylist.nsort %] Returns the numerically sorted items of the list.  If the items are
884    hashrefs, a key containing the field to sort on can be passed.
885
886=item pop
887
888    [% mylist.pop %] Removes and returns the last element from the arrayref (the stash is modified).
889
890=item push
891
892    [% mylist.push(23) %] Adds an element to the end of the arrayref (the stash is modified).
893
894=item pick
895
896    [% mylist.pick %] Returns a random item from the list.
897    [% ['a' .. 'z'].pick %]
898
899An additional numeric argument is how many items to return.
900
901    [% ['a' .. 'z'].pick(8).join('') %]
902
903Note: This filter is not available as of TT2.15.
904
905=item return
906
907Returns the list from the inner most block, macro, or file.  Similar to the
908RETURN directive.
909
910    [% mylist.return %]
911    [% RETURN mylist %]
912
913=item reverse
914
915    [% mylist.reverse %] Returns the list in reverse order.
916
917=item shift
918
919    [% mylist.shift %] Removes and returns the first element of the arrayref (the stash is modified).
920
921=item size
922
923    [% mylist.size %] Returns the number of elements in the array.
924
925=item slice
926
927    [% mylist.slice(i, n) %] Returns a list from the arrayref beginning at index i and continuing for n items.
928
929=item sort
930
931    [% mylist.sort %] Returns the alphabetically sorted items of the list.  If the items are
932    hashrefs, a key containing the field to sort on can be passed.
933
934=item splice
935
936    [% mylist.splice(i, n) %] Removes items from array beginning at i and continuing for n items.
937
938    [% mylist.splice(i, n, list2) %] Same as before, but replaces removed items with the items
939    from list2.
940
941=item unique
942
943    [% mylist.unique %] Return a list of the unique items in the array.
944
945=item unshift
946
947    [% mylist.unshift(23) %] Adds an item to the beginning of the arrayref.
948
949=back
950
951=head2 HASH VIRTUAL METHODS
952
953The following methods can be called on hash type data structures:
954
955Additionally, list virtual methods can be accessed via the Hash
956Virtual Object.
957
958=over 4
959
960=item fmt
961
962    [% myhash.fmt('%s => %s', "\n") %]
963    [% myhash.fmt('%4s => %5s', "\n") %]
964    [% myhash.fmt('%*s => %*s', "\n", 4, 5) %]
965
966Passed a pattern and an string to join on.  Returns a string of the
967key/value pairs of the hash formatted with the passed pattern and
968joined with the passed string.  Default pattern is "%s\t%s" and the
969default join string is a newline.
970
971=item defined
972
973    [% myhash.defined('a') %]  Checks if a is defined in the hash.
974
975=item delete
976
977    [% myhash.delete('a') %]  Deletes the item from the hash.
978
979Unlink Perl the value is not returned.  Multiple values may be passed
980and represent the keys to be deleted.
981
982=item each
983
984    [% myhash.each.join(", ") %]  Turns the contents of the hash into a list - subject
985    to change as TT is changing the operations of each and list.
986
987=item exists
988
989    [% myhash.exists('a') %]  Checks if a is in the hash.
990
991=item hash
992
993    [% myhash.hash %]  Returns a reference to the hash.
994
995=item import
996
997    [% myhash.import(hash2) %]  Overlays the keys of hash2 over the keys of myhash.
998
999=item item
1000
1001    [% myhash.item(key) %] Returns the hashes value for that key.
1002
1003=item items
1004
1005    [% myhash.items %] Returns a list of the key and values (flattened hash)
1006
1007=item json
1008
1009    [% myhash.json    %] Returns a JSON encoded representation.
1010    [% myhash.json(1) %] Returns a pretty JSON encoded representation.
1011
1012=item keys
1013
1014    [% myhash.keys.join(', ') %] Returns an arrayref of the keys of the hash.
1015
1016=item list
1017
1018    [% myhash.list %] Returns an arrayref with the hash as a single value (subject to change).
1019
1020=item pairs
1021
1022    [% myhash.pairs %] Returns an arrayref of hashrefs where each hash contains {key => $key, value => $value}
1023    for each value of the hash.
1024
1025=item nsort
1026
1027    [% myhash.nsort.join(", ") %] Returns a list of keys numerically sorted by the values.
1028
1029=item return
1030
1031Returns the hash from the inner most block, macro, or file.  Similar to the
1032RETURN directive.
1033
1034    [% myhash.return %]
1035    [% RETURN myhash %]
1036
1037=item size
1038
1039    [% myhash.size %] Returns the number of key/value pairs in the hash.
1040
1041=item sort
1042
1043    [% myhash.sort.join(", ") Returns a list of keys alphabetically sorted by the values.
1044
1045=item values
1046
1047    [% myhash.values.join(', ') %] Returns an arrayref of the values of the hash.
1048
1049=back
1050
1051=head1 VIRTUAL OBJECTS
1052
1053TT3 has a concept of Text, List, and Hash virtual objects which
1054provide direct access to the scalar, list, and hash virtual methods.
1055In the TT3 engine this will allow for more concise generated code.
1056Because Alloy does not generated perl code to be executed later, Alloy
1057provides for these virtual objects but does so as more of a namespace
1058(using the methods does not provide a speed optimization in your
1059template - just may help clarify things).
1060
1061    [% a = "foo"; a.length %] => 3
1062
1063    [% a = "foo"; Text.length(a) %] => 3
1064
1065    [% a = Text.new("foo"); a.length %] => 3
1066
1067
1068    [% a = [1 .. 30]; a.size %] => 30
1069
1070    [% a = [1 .. 30]; List.size(a) %] => 30
1071
1072    [% a = List.new(1 .. 30); a.size %] => 30
1073
1074
1075    [% a = {a => 1, b => 2}; a.size %] => 2
1076
1077    [% a = {a => 1, b => 2}; Hash.size(a) %] => 2
1078
1079    [% a = Hash.new({a => 1, b => 2}); a.size %] => 2
1080
1081    [% a = Hash.new(a => 1, b => 2); a.size %] => 2
1082
1083    [% a = Hash.new(a = 1, b = 2); a.size %] => 2
1084
1085    [% a = Hash.new('a', 1, 'b', 2); a.size %] => 2
1086
1087One limitation is that if you pass a key named "Text",
1088"List", or "Hash" in your variable stash - the corresponding
1089virtual object will be hidden.
1090
1091Additionally, you can use all of the Virtual object methods with
1092the pipe operator.
1093
1094    [% {a => 1, b => 2}
1095       | Hash.keys
1096       | List.join(", ") %] => a, b
1097
1098Again, there aren't any speed optimizations to using the virtual
1099objects in Alloy, but it can help clarify the intent in some cases.
1100
1101Note: these aren't really objects.  All of the "virtual objects" are
1102references to the $SCALAR_OPS, $LIST_OPS, and $HASH_OPS hashes
1103found in the $VOBJS hash of Template::Alloy.
1104
1105=head1 AUTHOR
1106
1107Paul Seamons <paul@seamons.com>
1108
1109=head1 LICENSE
1110
1111This module may be distributed under the same terms as Perl itself.
1112
1113=cut
1114