File Coverage

blib/lib/LUGS/Events/Parser/Filter.pm
Criterion Covered Total %
statement 163 163 100.0
branch 35 40 87.5
condition 7 9 77.7
subroutine 23 23 100.0
pod n/a
total 228 235 97.0


line stmt bran cond sub pod time code
1             package LUGS::Events::Parser::Filter;
2              
3 5     5   37 use strict;
  5         8  
  5         117  
4 5     5   20 use warnings;
  5         8  
  5         118  
5 5     5   856 use boolean qw(true);
  5         5872  
  5         27  
6              
7 5     5   1539 use Encode qw(decode encode);
  5         20831  
  5         270  
8 5     5   2294 use HTML::Entities qw(decode_entities);
  5         25124  
  5         314  
9 5     5   37 use HTML::Parser ();
  5         9  
  5         9194  
10              
11             our $VERSION = '0.07';
12              
13             my (@tags, @stack);
14              
15             sub _init_parser
16             {
17 5     5   12 my $self = shift;
18              
19 5         49 my $parser = HTML::Parser->new(
20             api_version => 3,
21             start_h => [ \&_start_tag, 'tagname,attr,attrseq' ],
22             text_h => [ \&_text_tag, 'text' ],
23             end_h => [ \&_end_tag, 'tagname' ],
24             );
25              
26 5         355 $parser->attr_encoded(true);
27              
28 5         45 return $parser;
29             }
30              
31             sub _parse_html
32             {
33 104     104   132 my $self = shift;
34 104         158 my ($chunk, $html) = @_;
35              
36 104         373 $self->{parser}->parse($chunk);
37              
38 104         136 undef @stack;
39              
40 104 100       221 return unless @tags;
41              
42 31         51 @$html = @tags;
43 31         63 undef @tags;
44             }
45              
46             sub _eof_parser
47             {
48 5     5   10 my $self = shift;
49              
50 5         26 $self->{parser}->eof;
51             }
52              
53             sub _start_tag
54             {
55 49     49   95 my ($tagname, $attr, $attrseq) = @_;
56              
57 49         199 push @stack, { name => $tagname, attr => $attr, attrseq => $attrseq };
58             }
59              
60             sub _text_tag
61             {
62 116     116   183 my ($text) = @_;
63              
64 116 100       354 return unless @stack;
65              
66 44         126 $stack[-1]->{text} = $text;
67             }
68              
69             sub _end_tag
70             {
71 41     41   67 my ($tagname) = @_;
72              
73 41 100       73 return unless @stack;
74              
75 38 50       83 if ($stack[-1]->{name} eq $tagname) {
76             push @tags, {
77             $tagname => {
78 38         65 map { $_ => $stack[-1]->{$_} }
  114         245  
79             qw(text attr attrseq),
80             },
81             };
82 38         125 pop @stack;
83             }
84             }
85              
86             sub _rewrite_tags
87             {
88 13     13   22 my $self = shift;
89 13         26 my ($fields) = @_;
90              
91             my $preserve_brackets = sub
92             {
93 33     33   69 my ($field, $subst) = @_;
94 33         42 my %purge_tags = map { $_ => true } @{$self->{Purge_tags}};
  10         34  
  33         63  
95 33 100       109 return unless $purge_tags{$field};
96 10         65 my $pkg = __PACKAGE__;
97 10         59 $$subst =~ s/<(.+?)>/\[$pkg\]$1\[\/$pkg\]/g;
98 13         59 };
99              
100 13         21 foreach my $field (keys %{$fields->{_html}}) {
  13         62  
101 27         56 my %rewritten;
102 27         38 foreach my $html (@{$fields->{_html}->{$field}}) {
  27         67  
103 38         77 foreach my $tag (keys %$html) {
104 38         51 my @tagnames;
105 38 100       46 if (%{$html->{$tag}->{attr}}) {
  38         76  
106 37         59 foreach my $attr (keys %{$html->{$tag}->{attr}}) {
  37         77  
107 37 50       103 if (exists $self->{Tag_handlers}->{"$tag $attr"}) {
108 37         86 push @tagnames, "$tag $attr";
109             }
110             }
111             }
112             else {
113 1 50       4 if (exists $self->{Tag_handlers}->{$tag}) {
114 1         3 push @tagnames, $tag;
115             }
116             }
117 38         59 foreach my $tagname (@tagnames) {
118 38         63 foreach my $handler (@{$self->{Tag_handlers}->{$tagname}}) {
  38         65  
119 57 100       118 if ($self->_field_rewrite($field, $handler)) {
120 32 100       377 unless (exists $rewritten{$tagname}) {
121 23         43 $rewritten{$tagname} = true;
122             }
123 32         89 my $subst = $handler->{rewrite};
124 32         82 foreach my $subst_item ($self->_subst_data($html, $tag)) {
125 63 100       141 next unless defined $subst_item->[1];
126 62         153 my ($identifier, $replacement) = @$subst_item;
127 62         84 my $place_holder = uc $identifier;
128 62         627 $subst =~ s/\$$place_holder/$replacement/;
129             }
130 32         103 my $re = $self->_subst_pattern($html, $tag);
131 32 100       78 if (defined $html->{$tag}->{text}) {
132 31         75 $preserve_brackets->($field, \$subst);
133 31         319 $fields->{$field} =~ s{$re}{$subst};
134             }
135             else {
136 1         11 $fields->{$field} =~ s{$re}{$1};
137             }
138             }
139             }
140             }
141             }
142             }
143 27         48 foreach my $tagname (grep !$rewritten{$_}, keys %{$self->{Tag_handlers}}) {
  27         104  
144 54         182 foreach my $handler (@{$self->{Tag_handlers}->{$tagname}}) {
  54         95  
145 54 100       86 if ($self->_field_rewrite($field, $handler)) {
146 47 100 100     650 if ($tagname !~ /\b\s+?\b/
      66        
147             && $fields->{$field} =~ m{<$tagname>}
148             && $fields->{$field} !~ m{</$tagname>}
149             ) {
150 2         5 my $subst = $handler->{rewrite};
151 2         7 $preserve_brackets->($field, \$subst);
152 2         24 $fields->{$field} =~ s{<$tagname>}{$subst}g;
153             }
154             }
155             }
156             }
157             }
158             }
159              
160             sub _purge_tags
161             {
162 13     13   22 my $self = shift;
163 13         25 my ($fields) = @_;
164              
165 13         19 my $pkg = __PACKAGE__;
166              
167 13         50 my %subst = (
168             "[$pkg]" => '<',
169             "[/$pkg]" => '>',
170             );
171              
172 13 50       18 foreach my $field (grep { !/^\_/ && exists $fields->{$_} } @{$self->{Purge_tags}}) {
  3         16  
  13         41  
173 3         6 $fields->{$field} = do {
174 3         7 local $_ = $fields->{$field};
175 3         32 s/<\/?\w+?>//g;
176 3         7 s/^\s+//;
177 3         21 s/\s+$//;
178 3         10 $_
179             };
180 3         44 $fields->{$field} =~ s/(\[\/?$pkg\])/$subst{$1}/g;
181             }
182             }
183              
184             sub _strip_html
185             {
186 31     31   41 my $self = shift;
187 31         47 my ($html) = @_;
188              
189 31         63 foreach my $html (@$html) {
190 38         93 foreach my $tag (keys %$html) {
191 38         51 foreach my $item (@{$self->{Strip_text}}) {
  38         69  
192 46 100       94 if (defined $html->{$tag}->{text}) {
193 45         201 $html->{$tag}->{text} =~ s/\Q$item\E//gi;
194             }
195 46         66 foreach my $attr (keys %{$html->{$tag}->{attr}}) {
  46         94  
196 45 50       83 if (defined $html->{$tag}->{attr}->{$attr}) {
197 45         243 $html->{$tag}->{attr}->{$attr} =~ s/\Q$item\E//gi;
198             }
199             }
200             }
201             }
202             }
203             }
204              
205             sub _strip_text
206             {
207 13     13   20 my $self = shift;
208 13         23 my ($fields) = @_;
209              
210 13         80 foreach my $field (grep !/^\_/, keys %$fields) {
211 92         123 foreach my $item (@{$self->{Strip_text}}) {
  92         192  
212 127         1383 while ($fields->{$field} =~ /<.+?"[^"]*?(?=\Q$item\E[^"]*?".*?>)/gi) {
213 11         99 $fields->{$field} =~ s/\G\Q$item\E//i;
214             }
215 127         2097 while ($fields->{$field} =~ /(?:^|>)[^<>]*?(?=\Q$item\E[^<>]*?(?:<|$))/gi) {
216 3         49 $fields->{$field} =~ s/\G\Q$item\E//i;
217             }
218             }
219             }
220             }
221              
222             sub _decode_entities
223             {
224 13     13   20 my $self = shift;
225 13         21 my ($fields) = @_;
226              
227 13         73 foreach my $field (grep !/^\_/, keys %$fields) {
228 92         229 decode_entities($fields->{$field});
229             }
230             }
231              
232             sub _encode_safe
233             {
234 13     13   22 my $self = shift;
235 13         21 my ($fields) = @_;
236              
237             my $encode = sub
238             {
239 43     43   49 my $f;
240 43 100       58 $f = eval { decode('UTF-8', $_[0], Encode::FB_CROAK) } or $f = $_[0];
  43         93  
241 43         2046 return encode('UTF-8', $f);
242 13         51 };
243              
244 13         50 foreach my $field (grep exists $fields->{$_}, qw(title location responsible more)) {
245 43         1161 $fields->{$field} = $encode->($fields->{$field});
246             }
247             }
248              
249             sub _field_rewrite
250             {
251 111     111   141 my $self = shift;
252 111         167 my ($field, $handler) = @_;
253              
254 111         133 my %rewrite = map { $_ => true } @{$handler->{fields}};
  130         240  
  111         183  
255              
256 111   66     663 return ($rewrite{$field} || $rewrite{'*'});
257             }
258              
259             sub _subst_data
260             {
261 32     32   43 my $self = shift;
262 32         48 my ($html, $tag) = @_;
263              
264             return (map {
265 31         89 [ $_ => $html->{$tag}->{attr}->{$_} ]
266 32         73 } keys %{$html->{$tag}->{attr}}),
267             (map {
268 32         109 [ $_ => $html->{$tag}->{$_} ]
269 32         38 } grep /^(?:text)$/, keys %{$html->{$tag}});
  32         136  
270             }
271              
272             sub _subst_pattern
273             {
274 32     32   43 my $self = shift;
275 32         65 my ($html, $tag) = @_;
276              
277 32 100       42 if (@{$html->{$tag}->{attrseq}}) {
  32         72  
278             my $attr = join ' ',
279             map "${_}=\"$html->{$tag}->{attr}->{$_}\"",
280 31         44 @{$html->{$tag}->{attrseq}};
  31         122  
281 31         58 my $text = $html->{$tag}->{text};
282 31 100       430 return defined $text
283             ? qr{<$tag\s+?\Q$attr\E>$text</$tag>}
284             : qr{<$tag\s+?\Q$attr\E>(.*?)</$tag>};
285             }
286             else {
287 1         14 return qr{<$tag>(.*?)</$tag>};
288             }
289             }
290              
291             1;