MACRO's are useful, but they cannot be passed to sort, map or grep, or to any 
other function.  The reason for this is because subroutines are evaluated 
before they are passed.  There at least possible solutions.  The first is to 
pass subroutines by reference and play them when accessed - this is 
problematic and would require rewriting TT.  A second option is to allow for
an operator that can create an anonymous MACRO that can be set in variables
(which would be equivalent of the MACRO directive) or used directly in calls 
to vmethods.

Further, if the macro has a way to return non-text values - then TT very 
nearly has full function support.

I'm proposing grabbing the "pointy-sub" syntax from Perl 6 for creating 
anonyous macros, and allowing for return values.  The syntax looks like this:

    [% MACRO foo BLOCK %]Hi[% END %]
    [% foo = ->{ "Hi" } %]    # same thing

    [% MACRO foo(max) FOREACH i IN [1..max] %][% i %][% END %]
    [% foo = ->(max){ FOREACH i IN [1..max]; i; END %]  # same thing

    [% a = [1, '', "b", "c"] %]
    [% a.grep(->{ this.length }).join %]   (1 b c)

    [% hash = ['a' .. 'c'].map(->{ {$this => 1}.return }) %]

Obviously, some of this power isn't needed, but it gives one more level of 
power to the Template designer.

All of this is available in the 1.012 release of Template::Alloy.  I'm hoping 
that it could find its way into standard TT as well.


The following is from the Template::Alloy::Operator perldoc for further 
examples of usage.

=item ->

Macro operator.  Works like the MACRO directive but can be used in
map, sort, and grep list operations.  Syntax is based on the Perl 6
pointy sub.  There are two diffences from the MACRO directive.  First
is that if no argument list is specified, a default argument list with
a single parameter named "this" will be used.  Second, the ->
operator parses its block as if it was already in a template tag.

    [% foo = ->{ "Hi" } %][% foo %] => Hi
    [% foo = ->{ this.repeat(2) } %][% foo("Hi") %] => HiHi
    [% foo = ->(n){ n.repeat(2) } %][% foo("Hi") %] => HiHi
    [% foo = ->(a,b){ a; "|"; b } %][% foo(2,3) %]  => 2|3

    [% [0..10].grep(->{ this % 2 }).join %] => 1 3 5 7 9
    [% ['a'..'c'].map(->{ this.upper }).join %] => A B C

    [% [1,2,3].sort(->(a,b){ b <=> a }).join %] prints 3 2 1

    [% c = [{k => "wow"}, {k => "wee"}, {k => "a"}] %]
    [% c.sort(->(a,b){ a.k cmp b.k }).map(->{this.k}).join %] => a wee wow

Note: Care should be used when attempting to sort large lists.
The mini-language of Template::Alloy is a interpreted language running
in Perl which is an interpreted language.  There are likely to be
performance issues when trying to do low level functions such as sort
on large lists.

The RETURN directive and return item, list, and hash vmethods can be
used to return more interesting values from a MACRO.

  [% a = ->(n){ [1..n].return } %]
  [% a(3).join %]    => 1 2 3
  [% a(10).join %]   => 1 2 3 4 5 6 7 8 9 10

The Schwartzian transform is now possible in Template::Alloy (somebody
somewhere is rolling over in their grave).

  [%- qw(Z a b D y M)
        .map(->{ [this.lc, this].return })
        .sort(->(a,b){a.0 cmp b.0})
        .map(->{this.1})
        .join %]          => a b D M y Z

_______________________________________________
templates mailing list
[email protected]
http://mail.template-toolkit.org/mailman/listinfo/templates

Reply via email to