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