Skip to content

Commit

Permalink
Apply auto-filtering to individual directives instead of an entire tag
Browse files Browse the repository at this point in the history
Tags may contain multiple directives separated by ';', such as:

    [% IF foo; bar; ELSE; baz; END %]

Previously 'bar' and 'baz' were not auto-filtered by this module because
the directives IF and END appeared in the tag.  This made is easy for
variables to slip through unfiltered in compound tags.  The auto-filter
now translates the above examples into:

    [% IF foo; bar | html; ELSE; baz | html; END %]

Resolves [rt.cpan.org #90643].
  • Loading branch information
wchristian committed Nov 1, 2014
1 parent de6d644 commit 37aa275
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 7 deletions.
2 changes: 2 additions & 0 deletions Changes
@@ -1,6 +1,8 @@
Revision history for Perl module {{$dist->name}}

{{$NEXT}}
- apply auto-filtering to individual directives instead of an entire tag,
i.e. [% IF foo; bar; ELSE; baz; END %]

0.140770 2014-03-18 10:49:54-07:00 America/Los_Angeles
- removed 'use lib' which breaks some people ( thanks to Aran Deltac <aran@ziprecruiter.com> )
Expand Down
33 changes: 27 additions & 6 deletions lib/Template/AutoFilter/Parser.pm
Expand Up @@ -58,6 +58,7 @@ Prebuilds a hash of directives to be skipped while applying auto filters.
=cut

use base 'Template::Parser';
use List::MoreUtils qw< part >;

sub new {
my ( $class, $params ) = @_;
Expand All @@ -77,13 +78,33 @@ sub split_text {
next if !ref $token;
next if !ref $token->[2]; # Skip ITEXT (<foo>$bar</foo>)

my %fields = grep { !ref } @{$token->[2]}; # filter out nested fields, they don't matter for our decision of whether there is a filter already
next if $self->has_skip_field( \%fields );
next if ! %fields;

push @{$token->[2]}, qw( FILTER | IDENT ), $self->{AUTO_FILTER};
# Split a compound statement into individual directives
my ($part, $is_directive) = (0, 1);
my @directives = part {
# Skip over interpolated fields; they are unpaired
unless (ref) {
$part++ if $is_directive and $_ eq ';';
$is_directive = !$is_directive;
}
$part;
} @{$token->[2]};

for my $directive (@directives) {
# Filter out interpolated values in strings; they don't matter for
# our decision of whether to autofilter or not (e.g. an existing
# filter). Note, this is not the same as ITEXT. Also ignore
# semi-colon tokens, as they may make an empty directive look
# non-empty. They are also inconsequential to our decision to
# autofilter or not.
my %fields = grep { !ref and $_ ne ';' } @$directive;
next if $self->has_skip_field( \%fields );
next if ! %fields;

push @$directive, qw( FILTER | IDENT ), $self->{AUTO_FILTER};
}

$token->[2] = [ map { @$_ } @directives ];
}

return $tokens;
}

Expand Down
17 changes: 16 additions & 1 deletion t/autofilter.t
Expand Up @@ -87,7 +87,22 @@ sub tests {(
params => {
INTERPOLATE => 1,
},
}
},
{
name => 'split apart compound statements',
tmpl => 'pre [% FOR foo IN ["<a>", "<b>", "&c"]; "<Element> $foo "; END %] post',
expect => 'pre &lt;Element&gt; &lt;a&gt; &lt;Element&gt; &lt;b&gt; &lt;Element&gt; &amp;c post',
},
{
name => 'split apart compound statements',
tmpl => 'pre [% FOR foo IN ["<a>", "<b>", "&c"]; "<Element> $foo " | none; END %] post',
expect => 'pre <Element> <a> <Element> <b> <Element> &c post',
},
{
name => 'tailing semi-colon parsed ok',
tmpl => '[% foo=test; %][% foo %]',
expect => '&lt;a&gt;',
},
)}

sub run_tests {
Expand Down

0 comments on commit 37aa275

Please sign in to comment.