1 #============================================================= -*-Perl-*-
6 # Defines filter plugins as used by the FILTER directive.
9 # Andy Wardley <abw@wardley.org>, with a number of filters contributed
10 # by Leslie Michael Orchard <deus_x@nijacode.com>
13 # Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
15 # This module is free software; you can redistribute it and/or
16 # modify it under the same terms as Perl itself.
18 #============================================================================
20 package Template::Filters;
25 use base 'Template::Base';
26 use Template::Constants;
27 use Scalar::Util 'blessed';
31 our $TRUNCATE_LENGTH = 32;
32 our $TRUNCATE_ADDON = '...';
35 #------------------------------------------------------------------------
36 # standard filters, defined in one of the following forms:
37 # name => \&static_filter
38 # name => [ \&subref, $is_dynamic ]
39 # If the $is_dynamic flag is set then the sub-routine reference
40 # is called to create a new filter each time it is requested; if
41 # not set, then it is a single, static sub-routine which is returned
42 # for every filter request for that name.
43 #------------------------------------------------------------------------
47 'html' => \&html_filter,
48 'html_para' => \&html_paragraph,
49 'html_break' => \&html_para_break,
50 'html_para_break' => \&html_para_break,
51 'html_line_break' => \&html_line_break,
52 'xml' => \&xml_filter,
53 'uri' => \&uri_filter,
54 'url' => \&url_filter,
55 'upper' => sub { uc $_[0] },
56 'lower' => sub { lc $_[0] },
57 'ucfirst' => sub { ucfirst $_[0] },
58 'lcfirst' => sub { lcfirst $_[0] },
59 'stderr' => sub { print STDERR @_; return '' },
60 'trim' => sub { for ($_[0]) { s/^\s+//; s/\s+$// }; $_[0] },
61 'null' => sub { return '' },
62 'collapse' => sub { for ($_[0]) { s/^\s+//; s/\s+$//; s/\s+/ /g };
66 'html_entity' => [ \&html_entity_filter_factory, 1 ],
67 'indent' => [ \&indent_filter_factory, 1 ],
68 'format' => [ \&format_filter_factory, 1 ],
69 'truncate' => [ \&truncate_filter_factory, 1 ],
70 'repeat' => [ \&repeat_filter_factory, 1 ],
71 'replace' => [ \&replace_filter_factory, 1 ],
72 'remove' => [ \&remove_filter_factory, 1 ],
73 'eval' => [ \&eval_filter_factory, 1 ],
74 'evaltt' => [ \&eval_filter_factory, 1 ], # alias
75 'perl' => [ \&perl_filter_factory, 1 ],
76 'evalperl' => [ \&perl_filter_factory, 1 ], # alias
77 'redirect' => [ \&redirect_filter_factory, 1 ],
78 'file' => [ \&redirect_filter_factory, 1 ], # alias
79 'stdout' => [ \&stdout_filter_factory, 1 ],
82 # name of module implementing plugin filters
83 our $PLUGIN_FILTER = 'Template::Plugin::Filter';
87 #========================================================================
88 # -- PUBLIC METHODS --
89 #========================================================================
91 #------------------------------------------------------------------------
92 # fetch($name, \@args, $context)
94 # Attempts to instantiate or return a reference to a filter sub-routine
95 # named by the first parameter, $name, with additional constructor
96 # arguments passed by reference to a list as the second parameter,
97 # $args. A reference to the calling Template::Context object is
98 # passed as the third paramter.
100 # Returns a reference to a filter sub-routine or a pair of values
101 # (undef, STATUS_DECLINED) or ($error, STATUS_ERROR) to decline to
102 # deliver the filter or to indicate an error.
103 #------------------------------------------------------------------------
106 my ($self, $name, $args, $context) = @_;
107 my ($factory, $is_dynamic, $filter, $error);
109 $self->debug("fetch($name, ",
110 defined $args ? ('[ ', join(', ', @$args), ' ]') : '<no args>', ', ',
111 defined $context ? $context : '<no context>',
112 ')') if $self->{ DEBUG };
114 # allow $name to be specified as a reference to
115 # a plugin filter object; any other ref is
116 # assumed to be a coderef and hence already a filter;
117 # non-refs are assumed to be regular name lookups
120 if (blessed($name) && $name->isa($PLUGIN_FILTER)) {
121 $factory = $name->factory()
122 || return $self->error($name->error());
129 return (undef, Template::Constants::STATUS_DECLINED)
130 unless ($factory = $self->{ FILTERS }->{ $name }
131 || $FILTERS->{ $name });
134 # factory can be an [ $code, $dynamic ] or just $code
135 if (ref $factory eq 'ARRAY') {
136 ($factory, $is_dynamic) = @$factory;
142 if (ref $factory eq 'CODE') {
144 # if the dynamic flag is set then the sub-routine is a
145 # factory which should be called to create the actual
148 ($filter, $error) = &$factory($context, $args ? @$args : ());
151 $error = "invalid FILTER for '$name' (not a CODE ref)"
152 unless $error || ref($filter) eq 'CODE';
155 # ...otherwise, it's a static filter sub-routine
160 $error = "invalid FILTER entry for '$name' (not a CODE ref)";
164 return $self->{ TOLERANT }
165 ? (undef, Template::Constants::STATUS_DECLINED)
166 : ($error, Template::Constants::STATUS_ERROR) ;
174 #------------------------------------------------------------------------
175 # store($name, \&filter)
177 # Stores a new filter in the internal FILTERS hash. The first parameter
178 # is the filter name, the second a reference to a subroutine or
179 # array, as per the standard $FILTERS entries.
180 #------------------------------------------------------------------------
183 my ($self, $name, $filter) = @_;
185 $self->debug("store($name, $filter)") if $self->{ DEBUG };
187 $self->{ FILTERS }->{ $name } = $filter;
192 #========================================================================
193 # -- PRIVATE METHODS --
194 #========================================================================
196 #------------------------------------------------------------------------
199 # Private initialisation method.
200 #------------------------------------------------------------------------
203 my ($self, $params) = @_;
205 $self->{ FILTERS } = $params->{ FILTERS } || { };
206 $self->{ TOLERANT } = $params->{ TOLERANT } || 0;
207 $self->{ DEBUG } = ( $params->{ DEBUG } || 0 )
208 & Template::Constants::DEBUG_FILTERS;
216 #------------------------------------------------------------------------
220 #------------------------------------------------------------------------
224 my $output = "[Template::Filters] {\n";
225 my $format = " %-16s => %s\n";
228 foreach $key (qw( TOLERANT )) {
229 my $val = $self->{ $key };
230 $val = '<undef>' unless defined $val;
231 $output .= sprintf($format, $key, $val);
234 my $filters = $self->{ FILTERS };
235 $filters = join('', map {
236 sprintf(" $format", $_, $filters->{ $_ });
238 $filters = "{\n$filters }";
240 $output .= sprintf($format, 'FILTERS (local)' => $filters);
243 $filters = join('', map {
244 my $f = $filters->{ $_ };
245 my ($ref, $dynamic) = ref $f eq 'ARRAY' ? @$f : ($f, 0);
246 sprintf(" $format", $_, $dynamic ? 'dynamic' : 'static');
247 } sort keys %$filters);
248 $filters = "{\n$filters }";
250 $output .= sprintf($format, 'FILTERS (global)' => $filters);
257 #========================================================================
258 # -- STATIC FILTER SUBS --
259 #========================================================================
261 #------------------------------------------------------------------------
262 # uri_filter() [% FILTER uri %]
264 # URI escape a string. This code is borrowed from Gisle Aas' URI::Escape
265 # module, copyright 1995-2004. See RFC2396 for details.
266 #-----------------------------------------------------------------------
268 # cache of escaped characters
275 map { ( chr($_), sprintf("%%%02X", $_) ) } (0..255),
278 if ($] >= 5.008 && utf8::is_utf8($text)) {
282 $text =~ s/([^A-Za-z0-9\-_.!~*'()])/$URI_ESCAPES->{$1}/eg;
286 #------------------------------------------------------------------------
287 # url_filter() [% FILTER uri %]
289 # NOTE: the difference: url vs uri.
290 # This implements the old-style, non-strict behaviour of the uri filter
291 # which allows any valid URL characters to pass through so that
292 # http://example.com/blah.html does not get the ':' and '/' characters
294 #-----------------------------------------------------------------------
300 map { ( chr($_), sprintf("%%%02X", $_) ) } (0..255),
303 if ($] >= 5.008 && utf8::is_utf8($text)) {
307 $text =~ s/([^;\/?:@&=+\$,A-Za-z0-9\-_.!~*'()])/$URI_ESCAPES->{$1}/eg;
312 #------------------------------------------------------------------------
313 # html_filter() [% FILTER html %]
315 # Convert any '<', '>' or '&' characters to the HTML equivalents, '<',
316 # '>' and '&', respectively.
317 #------------------------------------------------------------------------
331 #------------------------------------------------------------------------
332 # xml_filter() [% FILTER xml %]
334 # Same as the html filter, but adds the conversion of ' to ' which
336 #------------------------------------------------------------------------
351 #------------------------------------------------------------------------
352 # html_paragraph() [% FILTER html_para %]
354 # Wrap each paragraph of text (delimited by two or more newlines) in the
355 # <p>...</p> HTML tags.
356 #------------------------------------------------------------------------
361 . join("\n</p>\n\n<p>\n", split(/(?:\r?\n){2,}/, $text))
366 #------------------------------------------------------------------------
367 # html_para_break() [% FILTER html_para_break %]
369 # Join each paragraph of text (delimited by two or more newlines) with
370 # <br><br> HTML tags.
371 #------------------------------------------------------------------------
373 sub html_para_break {
375 $text =~ s|(\r?\n){2,}|$1<br />$1<br />$1|g;
379 #------------------------------------------------------------------------
380 # html_line_break() [% FILTER html_line_break %]
382 # replaces any newlines with <br> HTML tags.
383 #------------------------------------------------------------------------
385 sub html_line_break {
387 $text =~ s|(\r?\n)|<br />$1|g;
391 #========================================================================
392 # -- DYNAMIC FILTER FACTORIES --
393 #========================================================================
395 #------------------------------------------------------------------------
396 # html_entity_filter_factory(\%options) [% FILTER html %]
398 # Dynamic version of the static html filter which attempts to locate the
399 # Apache::Util or HTML::Entities modules to perform full entity encoding
400 # of the text passed. Returns an exception if one or other of the
401 # modules can't be located.
402 #------------------------------------------------------------------------
404 sub use_html_entities {
405 require HTML::Entities;
406 return ($AVAILABLE->{ HTML_ENTITY } = \&HTML::Entities::encode_entities);
409 sub use_apache_util {
410 require Apache::Util;
411 Apache::Util::escape_html(''); # TODO: explain this
412 return ($AVAILABLE->{ HTML_ENTITY } = \&Apache::Util::escape_html);
415 sub html_entity_filter_factory {
419 # if Apache::Util is installed then we use escape_html
420 $haz = $AVAILABLE->{ HTML_ENTITY }
421 || eval { use_apache_util() }
422 || eval { use_html_entities() }
423 || -1; # we use -1 for "not available" because it's a true value
425 return ref $haz eq 'CODE'
427 : (undef, Template::Exception->new(
428 html_entity => 'cannot locate Apache::Util or HTML::Entities' )
433 #------------------------------------------------------------------------
434 # indent_filter_factory($pad) [% FILTER indent(pad) %]
436 # Create a filter to indent text by a fixed pad string or when $pad is
437 # numerical, a number of space.
438 #------------------------------------------------------------------------
440 sub indent_filter_factory {
441 my ($context, $pad) = @_;
442 $pad = 4 unless defined $pad;
443 $pad = ' ' x $pad if $pad =~ /^\d+$/;
447 $text = '' unless defined $text;
448 $text =~ s/^/$pad/mg;
453 #------------------------------------------------------------------------
454 # format_filter_factory() [% FILTER format(format) %]
456 # Create a filter to format text according to a printf()-like format
458 #------------------------------------------------------------------------
460 sub format_filter_factory {
461 my ($context, $format) = @_;
462 $format = '%s' unless defined $format;
466 $text = '' unless defined $text;
467 return join("\n", map{ sprintf($format, $_) } split(/\n/, $text));
472 #------------------------------------------------------------------------
473 # repeat_filter_factory($n) [% FILTER repeat(n) %]
475 # Create a filter to repeat text n times.
476 #------------------------------------------------------------------------
478 sub repeat_filter_factory {
479 my ($context, $iter) = @_;
480 $iter = 1 unless defined $iter and length $iter;
484 $text = '' unless defined $text;
485 return join('\n', $text) x $iter;
490 #------------------------------------------------------------------------
491 # replace_filter_factory($s, $r) [% FILTER replace(search, replace) %]
493 # Create a filter to replace 'search' text with 'replace'
494 #------------------------------------------------------------------------
496 sub replace_filter_factory {
497 my ($context, $search, $replace) = @_;
498 $search = '' unless defined $search;
499 $replace = '' unless defined $replace;
503 $text = '' unless defined $text;
504 $text =~ s/$search/$replace/g;
510 #------------------------------------------------------------------------
511 # remove_filter_factory($text) [% FILTER remove(text) %]
513 # Create a filter to remove 'search' string from the input text.
514 #------------------------------------------------------------------------
516 sub remove_filter_factory {
517 my ($context, $search) = @_;
521 $text = '' unless defined $text;
522 $text =~ s/$search//g;
528 #------------------------------------------------------------------------
529 # truncate_filter_factory($n) [% FILTER truncate(n) %]
531 # Create a filter to truncate text after n characters.
532 #------------------------------------------------------------------------
534 sub truncate_filter_factory {
535 my ($context, $len, $char) = @_;
536 $len = $TRUNCATE_LENGTH unless defined $len;
537 $char = $TRUNCATE_ADDON unless defined $char;
539 # Length of char is the minimum length
540 my $lchar = length $char;
542 $char = substr($char, 0, $len);
548 return $text if length $text <= $len;
549 return substr($text, 0, $len - $lchar) . $char;
556 #------------------------------------------------------------------------
557 # eval_filter_factory [% FILTER eval %]
559 # Create a filter to evaluate template text.
560 #------------------------------------------------------------------------
562 sub eval_filter_factory {
567 $context->process(\$text);
572 #------------------------------------------------------------------------
573 # perl_filter_factory [% FILTER perl %]
575 # Create a filter to process Perl text iff the context EVAL_PERL flag
577 #------------------------------------------------------------------------
579 sub perl_filter_factory {
581 my $stash = $context->stash;
583 return (undef, Template::Exception->new('perl', 'EVAL_PERL is not set'))
584 unless $context->eval_perl();
588 local($Template::Perl::context) = $context;
589 local($Template::Perl::stash) = $stash;
590 my $out = eval <<EOF;
591 package Template::Perl;
592 \$stash = \$context->stash();
595 $context->throw($@) if $@;
601 #------------------------------------------------------------------------
602 # redirect_filter_factory($context, $file) [% FILTER redirect(file) %]
604 # Create a filter to redirect the block text to a file.
605 #------------------------------------------------------------------------
607 sub redirect_filter_factory {
608 my ($context, $file, $options) = @_;
609 my $outpath = $context->config->{ OUTPUT_PATH };
611 return (undef, Template::Exception->new('redirect',
612 'OUTPUT_PATH is not set'))
615 $context->throw('redirect', "relative filenames are not supported: $file")
616 if $file =~ m{(^|/)\.\./};
618 $options = { binmode => $options } unless ref $options;
622 my $outpath = $context->config->{ OUTPUT_PATH }
624 $outpath .= "/$file";
625 my $error = Template::_output($outpath, \$text, $options);
626 die Template::Exception->new('redirect', $error)
633 #------------------------------------------------------------------------
634 # stdout_filter_factory($context, $binmode) [% FILTER stdout(binmode) %]
636 # Create a filter to print a block to stdout, with an optional binmode.
637 #------------------------------------------------------------------------
639 sub stdout_filter_factory {
640 my ($context, $options) = @_;
642 $options = { binmode => $options } unless ref $options;
646 binmode(STDOUT) if $options->{ binmode };
659 Template::Filters - Post-processing filters for template blocks
663 use Template::Filters;
665 $filters = Template::Filters->new(\%config);
667 ($filter, $error) = $filters->fetch($name, \@args, $context);
670 print &$filter("some text");
673 print "Could not fetch $name filter: $error\n";
678 The C<Template::Filters> module implements a provider for creating subroutines
679 that implement the standard filters. Additional custom filters may be provided
680 via the L<FILTERS> configuration option.
686 Constructor method which instantiates and returns a reference to a
687 C<Template::Filters> object. A reference to a hash array of configuration
688 items may be passed as a parameter. These are described below.
690 my $filters = Template::Filters->new({
694 my $template = Template->new({
695 LOAD_FILTERS => [ $filters ],
698 A default C<Template::Filters> module is created by the L<Template> module
699 if the L<LOAD_FILTERS> option isn't specified. All configuration parameters
700 are forwarded to the constructor.
702 $template = Template->new({
706 =head2 fetch($name, \@args, $context)
708 Called to request that a filter of a given name be provided. The name
709 of the filter should be specified as the first parameter. This should
710 be one of the standard filters or one specified in the L<FILTERS>
711 configuration hash. The second argument should be a reference to an
712 array containing configuration parameters for the filter. This may be
713 specified as 0, or undef where no parameters are provided. The third
714 argument should be a reference to the current L<Template::Context>
717 The method returns a reference to a filter sub-routine on success. It
718 may also return C<(undef, STATUS_DECLINE)> to decline the request, to allow
719 delegation onto other filter providers in the L<LOAD_FILTERS> chain of
720 responsibility. On error, C<($error, STATUS_ERROR)> is returned where $error
721 is an error message or L<Template::Exception> object indicating the error
724 When the C<TOLERANT> option is set, errors are automatically downgraded to
725 a C<STATUS_DECLINE> response.
727 =head2 use_html_entities()
729 This class method can be called to configure the C<html_entity> filter to use
730 the L<HTML::Entities> module. An error will be raised if it is not installed
733 use Template::Filters;
734 Template::Filters->use_html_entities();
736 =head2 use_apache_util()
738 This class method can be called to configure the C<html_entity> filter to use
739 the L<Apache::Util> module. An error will be raised if it is not installed on
742 use Template::Filters;
743 Template::Filters->use_apache_util();
745 =head1 CONFIGURATION OPTIONS
747 The following list summarises the configuration options that can be provided
748 to the C<Template::Filters> L<new()> constructor. Please see
749 L<Template::Manual::Config> for further information about each option.
753 The L<FILTERS|Template::Manual::Config#FILTERS> option can be used to specify
754 custom filters which can then be used with the
755 L<FILTER|Template::Manual::Directives#FILTER> directive like any other. These
756 are added to the standard filters which are available by default.
758 $filters = Template::Filters->new({
760 'sfilt1' => \&static_filter,
761 'dfilt1' => [ \&dyanamic_filter_factory, 1 ],
767 The L<TOLERANT|Template::Manual::Config#TOLERANT> flag can be set to indicate
768 that the C<Template::Filters> module should ignore any errors and instead
769 return C<STATUS_DECLINED>.
773 The L<DEBUG|Template::Manual::Config#DEBUG> option can be used to enable
774 debugging messages for the Template::Filters module by setting it to include
775 the C<DEBUG_FILTERS> value.
777 use Template::Constants qw( :debug );
779 my $template = Template->new({
780 DEBUG => DEBUG_FILTERS | DEBUG_PLUGINS,
783 =head1 STANDARD FILTERS
785 Please see L<Template::Manual::Filters> for a list of the filters provided
786 with the Template Toolkit, complete with examples of use.
790 Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
794 Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
796 This module is free software; you can redistribute it and/or
797 modify it under the same terms as Perl itself.
801 L<Template::Manual::Filters>, L<Template>, L<Template::Context>
807 # perl-indent-level: 4
808 # indent-tabs-mode: nil
811 # vim: expandtab shiftwidth=4: