????
Current Path : /usr/local/lib64/perl5/Template/Plugin/ |
Current File : //usr/local/lib64/perl5/Template/Plugin/Filter.pm |
#============================================================= -*-Perl-*- # # Template::Plugin::Filter # # DESCRIPTION # Template Toolkit module implementing a base class plugin # object which acts like a filter and can be used with the # FILTER directive. # # AUTHOR # Andy Wardley <abw@wardley.org> # # COPYRIGHT # Copyright (C) 2001-2022 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. # #============================================================================ package Template::Plugin::Filter; use strict; use warnings; use base 'Template::Plugin'; use Scalar::Util 'weaken', 'isweak'; our $VERSION = '3.100'; our $DYNAMIC = 0 unless defined $DYNAMIC; sub new { my ($class, $context, @args) = @_; my $config = @args && ref $args[-1] eq 'HASH' ? pop(@args) : { }; # look for $DYNAMIC my $dynamic; { no strict 'refs'; $dynamic = ${"$class\::DYNAMIC"}; } $dynamic = $DYNAMIC unless defined $dynamic; my $self = bless { _CONTEXT => $context, _DYNAMIC => $dynamic, _ARGS => \@args, _CONFIG => $config, }, $class; return $self->init($config) || $class->error($self->error()); } sub init { my ($self, $config) = @_; return $self; } sub factory { my $self = shift; my $this = $self; # avoid a memory leak weaken( $this->{_CONTEXT} ) if ref $this->{_CONTEXT} && !isweak $this->{_CONTEXT}; if ($self->{ _DYNAMIC }) { return [ sub { my ($context, @args) = @_; my $config = ref $args[-1] eq 'HASH' ? pop(@args) : { }; return sub { $this->filter(shift, \@args, $config); }; }, 1 ]; } else { return sub { $this->filter(shift); }; } } sub filter { my ($self, $text, $args, $config) = @_; return $text; } sub merge_config { my ($self, $newcfg) = @_; my $owncfg = $self->{ _CONFIG }; return $owncfg unless $newcfg; return { %$owncfg, %$newcfg }; } sub merge_args { my ($self, $newargs) = @_; my $ownargs = $self->{ _ARGS }; return $ownargs unless $newargs; return [ @$ownargs, @$newargs ]; } sub install_filter { my ($self, $name) = @_; $self->{ _CONTEXT }->define_filter( $name => $self->factory ); return $self; } 1; __END__ =head1 NAME Template::Plugin::Filter - Base class for plugin filters =head1 SYNOPSIS package MyOrg::Template::Plugin::MyFilter; use Template::Plugin::Filter; use base qw( Template::Plugin::Filter ); sub filter { my ($self, $text) = @_; # ...mungify $text... return $text; } # now load it... [% USE MyFilter %] # ...and use the returned object as a filter [% FILTER $MyFilter %] ... [% END %] =head1 DESCRIPTION This module implements a base class for plugin filters. It hides the underlying complexity involved in creating and using filters that get defined and made available by loading a plugin. To use the module, simply create your own plugin module that is inherited from the C<Template::Plugin::Filter> class. package MyOrg::Template::Plugin::MyFilter; use Template::Plugin::Filter; use base qw( Template::Plugin::Filter ); Then simply define your C<filter()> method. When called, you get passed a reference to your plugin object (C<$self>) and the text to be filtered. sub filter { my ($self, $text) = @_; # ...mungify $text... return $text; } To use your custom plugin, you have to make sure that the Template Toolkit knows about your plugin namespace. my $tt2 = Template->new({ PLUGIN_BASE => 'MyOrg::Template::Plugin', }); Or for individual plugins you can do it like this: my $tt2 = Template->new({ PLUGINS => { MyFilter => 'MyOrg::Template::Plugin::MyFilter', }, }); Then you C<USE> your plugin in the normal way. [% USE MyFilter %] The object returned is stored in the variable of the same name, 'C<MyFilter>'. When you come to use it as a C<FILTER>, you should add a dollar prefix. This indicates that you want to use the filter stored in the variable 'C<MyFilter>' rather than the filter named 'C<MyFilter>', which is an entirely different thing (see later for information on defining filters by name). [% FILTER $MyFilter %] ...text to be filtered... [% END %] You can, of course, assign it to a different variable. [% USE blat = MyFilter %] [% FILTER $blat %] ...text to be filtered... [% END %] Any configuration parameters passed to the plugin constructor from the C<USE> directive are stored internally in the object for inspection by the C<filter()> method (or indeed any other method). Positional arguments are stored as a reference to a list in the C<_ARGS> item while named configuration parameters are stored as a reference to a hash array in the C<_CONFIG> item. For example, loading a plugin as shown here: [% USE blat = MyFilter 'foo' 'bar' baz = 'blam' %] would allow the C<filter()> method to do something like this: sub filter { my ($self, $text) = @_; my $args = $self->{ _ARGS }; # [ 'foo', 'bar' ] my $conf = $self->{ _CONFIG }; # { baz => 'blam' } # ...munge $text... return $text; } By default, plugins derived from this module will create static filters. A static filter is created once when the plugin gets loaded via the C<USE> directive and re-used for all subsequent C<FILTER> operations. That means that any argument specified with the C<FILTER> directive are ignored. Dynamic filters, on the other hand, are re-created each time they are used by a C<FILTER> directive. This allows them to act on any parameters passed from the C<FILTER> directive and modify their behaviour accordingly. There are two ways to create a dynamic filter. The first is to define a C<$DYNAMIC> class variable set to a true value. package MyOrg::Template::Plugin::MyFilter; use base 'Template::Plugin::Filter'; our $DYNAMIC = 1; The other way is to set the internal C<_DYNAMIC> value within the C<init()> method which gets called by the C<new()> constructor. sub init { my $self = shift; $self->{ _DYNAMIC } = 1; return $self; } When this is set to a true value, the plugin will automatically create a dynamic filter. The outcome is that the C<filter()> method will now also get passed a reference to an array of positional arguments and a reference to a hash array of named parameters. So, using a plugin filter like this: [% FILTER $blat 'foo' 'bar' baz = 'blam' %] would allow the C<filter()> method to work like this: sub filter { my ($self, $text, $args, $conf) = @_; # $args = [ 'foo', 'bar' ] # $conf = { baz => 'blam' } } In this case can pass parameters to both the USE and FILTER directives, so your filter() method should probably take that into account. [% USE MyFilter 'foo' wiz => 'waz' %] [% FILTER $MyFilter 'bar' biz => 'baz' %] ... [% END %] You can use the C<merge_args()> and C<merge_config()> methods to do a quick and easy job of merging the local (e.g. C<FILTER>) parameters with the internal (e.g. C<USE>) values and returning new sets of conglomerated data. sub filter { my ($self, $text, $args, $conf) = @_; $args = $self->merge_args($args); $conf = $self->merge_config($conf); # $args = [ 'foo', 'bar' ] # $conf = { wiz => 'waz', biz => 'baz' } ... } You can also have your plugin install itself as a named filter by calling the C<install_filter()> method from the C<init()> method. You should provide a name for the filter, something that you might like to make a configuration option. sub init { my $self = shift; my $name = $self->{ _CONFIG }->{ name } || 'myfilter'; $self->install_filter($name); return $self; } This allows the plugin filter to be used as follows: [% USE MyFilter %] [% FILTER myfilter %] ... [% END %] or [% USE MyFilter name = 'swipe' %] [% FILTER swipe %] ... [% END %] Alternately, you can allow a filter name to be specified as the first positional argument. sub init { my $self = shift; my $name = $self->{ _ARGS }->[0] || 'myfilter'; $self->install_filter($name); return $self; } [% USE MyFilter 'swipe' %] [% FILTER swipe %] ... [% END %] =head1 EXAMPLE Here's a complete example of a plugin filter module. package My::Template::Plugin::Change; use Template::Plugin::Filter; use base qw( Template::Plugin::Filter ); sub init { my $self = shift; $self->{ _DYNAMIC } = 1; # first arg can specify filter name $self->install_filter($self->{ _ARGS }->[0] || 'change'); return $self; } sub filter { my ($self, $text, $args, $config) = @_; $config = $self->merge_config($config); my $regex = join('|', keys %$config); $text =~ s/($regex)/$config->{ $1 }/ge; return $text; } 1; =head1 AUTHOR Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/> =head1 COPYRIGHT Copyright (C) 1996-2022 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::Plugin>, L<Template::Filters>, L<Template::Manual::Filters> =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: