On Tue, 27 Aug 2002, Andy Wardley wrote:
> the answer
Yesterday I wrote a whole set of examples of how to do this. I was all
set to post them to the list and then my temperature skyrocketed to 104F so
I lay in bed moaning instead.
Anyway, here's the explanation, better late than never:
Though there's probably some way that you can easily count the number of
regexps that occur in a string from within the Template Toolkit, you
might want to consider if it's the right thing to do. There's no explicit
operator for this - do you really want to be shoehorning in something
designed to do something else into the task? I don't think that'll come
up with clean templates - we're not trying to re-implement perl here ;-).
I'd try and extend the Template Toolkit to do the right thing, to add an
explicit operator for the job.
The easiest way to do this is to add a subroutine to the stash that can do
the calling when you run the process method:
use Template;
my $template = Template->new();
$template->process( "template", { occurrence => \&occurrence } )
or die $template->error;
sub occurrence
{
my ($string, $regex) = @_;
return scalar(() = $string =~ m/$regex/g);
}
And then in the template:
[% occurrence("abaab","a") %]
The problem with doing this is that it requires you to know in advance
that you'll need to do occurrence counting. If this is part of the display
logic then the script shouldn't really have to do anything about it. What
you need to do is provide some system where by you can load dynamically
such routines as you need them.
The Template Toolkit uses a plugin architecture to achieve this. A simple
plugin might look something like this:
package Template::Plugin::Matcher;
use base qw(Template::Plugin);
use strict;
use warnings;
sub occurrence
{
my $self = shift;
my ($string, $regex) = @_;
return scalar(() = $string =~ m/$regex/g);
}
Then the plugin can be created as a object in TT like so:
[% USE Matcher %]
[% Matcher.occurrence("abaab","a") %]
Note how the plugin creates a Matcher class which methods, in this case a
static method that is used to do occurrence matching, can be called
against. This might seem a little counter intuitive to people who expect
to just have the functions made available to them...It's like the
difference between a exporter class and an object orientated class. We can
emulate the code we had above fully by having the *plugin* populate the
stash with the subroutine (rather than doing it manually in the process
method)
package Template::Plugin::Occurrences;
use base qw(Template::Plugin);
use strict;
use warnings;
sub new
{
my ($class, $context) = @_;
# place the occurrences subroutine in the stash
my $stash = $context->stash;
$stash->set("occurrence",\&occurrence);
# return a blessed object
return bless {}, $class;
}
sub occurrence
{
my ($string, $regex) = @_;
return scalar(() = $string =~ m/$regex/g);
}
Which leads us back to something more simple like this in our template:
[% USE Occurrences %]
[% occurrence("abaab","a") %]
Finally, the most complicated (but arguable easiest solution to use) is to
create vmethods. These are essentially methods that exist for all items in
the stash. You can call them on any object and they should do the right
thing.
package Template::Plugin::OccurrencesV;
use base qw(Template::Plugin);
use strict;
use warnings;
sub load
{
my ($class, $context) = @_;
# set the vmethod in the stash
$Template::Stash::SCALAR_OPS->{occurrence} = \&occurrence;
# and the same for a list op so that single element lists
# can be used as scalars
$Template::Stash::LIST_OPS->{occurrence} = \&occurrence_list;
# return the same class
return $class;
}
sub occurrence
{
my ($string, $regex) = @_;
return scalar(() = $string =~ m/$regex/g);
}
sub occurrence_list
{
my ($stringlist, $regex) = @_;
return occurrence($stringlist->[0], $regex)
}
This can then be used like this:
[% USE OccurrencesV %]
[% foo = "abaab" %]
[% bar = ["abaab"] %]
scalar: [% foo.occurrence("a") %]
list: [% bar.occurrence("a") %]
Note how we create two vmethods. One for scalar operations and one for
list operations. This is to fit in with the doing the right thing thing
that Template Toolkit does when it has single element lists - essentially
you should be able to treat them as scalars.
Mark.
--
s'' Mark Fowler London.pm Bath.pm
http://www.twoshortplanks.com/ [EMAIL PROTECTED]
';use Term'Cap;$t=Tgetent Term'Cap{};print$t->Tputs(cl);for$w(split/ +/
){for(0..30){$|=print$t->Tgoto(cm,$_,$y)." $w";select$k,$k,$k,.03}$y+=2}
_______________________________________________
templates mailing list
[EMAIL PROTECTED]
http://www.template-toolkit.org/mailman/listinfo/templates