line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ABSTRACT: match and filter RSS feeds |
2
|
|
|
|
|
|
|
|
3
|
17
|
|
|
17
|
|
164849
|
use strict; |
|
17
|
|
|
|
|
34
|
|
|
17
|
|
|
|
|
543
|
|
4
|
17
|
|
|
17
|
|
91
|
use warnings; |
|
17
|
|
|
|
|
33
|
|
|
17
|
|
|
|
|
938
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package App::Rssfilter::Rule; |
9
|
|
|
|
|
|
|
$App::Rssfilter::Rule::VERSION = '0.08'; # TRIAL |
10
|
17
|
|
|
17
|
|
1689
|
use Moo; |
|
17
|
|
|
|
|
29626
|
|
|
17
|
|
|
|
|
118
|
|
11
|
17
|
|
|
17
|
|
42165
|
use Method::Signatures; |
|
17
|
|
|
|
|
144614
|
|
|
17
|
|
|
|
|
129
|
|
12
|
17
|
|
|
17
|
|
9520
|
use Module::Runtime qw<>; |
|
17
|
|
|
|
|
37
|
|
|
17
|
|
|
|
|
298
|
|
13
|
17
|
|
|
17
|
|
13506
|
use Class::Inspector qw<>; |
|
17
|
|
|
|
|
55287
|
|
|
17
|
|
|
|
|
902
|
|
14
|
|
|
|
|
|
|
with 'App::Rssfilter::Logger'; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
has condition => ( |
19
|
|
|
|
|
|
|
is => 'ro', |
20
|
|
|
|
|
|
|
required => 1, |
21
|
|
|
|
|
|
|
); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
has _match => ( |
25
|
|
|
|
|
|
|
is => 'lazy', |
26
|
|
|
|
|
|
|
init_arg => undef, |
27
|
|
|
|
|
|
|
default => method { $self->coerce_attr( attr => $self->condition, type => 'match' ) }, |
28
|
17
|
50
|
|
17
|
|
354267
|
); |
|
15
|
50
|
|
15
|
|
24
|
|
|
15
|
|
|
|
|
43
|
|
|
15
|
|
|
|
|
21
|
|
|
15
|
|
|
|
|
39
|
|
29
|
15
|
|
|
|
|
350
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
method match( $item ) { |
32
|
|
|
|
|
|
|
return $self->_match->( $item ); |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
has condition_name => ( |
37
|
|
|
|
|
|
|
is => 'lazy', |
38
|
|
|
|
|
|
|
default => method { $self->nice_name_for( $self->condition, 'matcher' ) }, |
39
|
|
|
|
|
|
|
); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
has action => ( |
43
|
|
|
|
|
|
|
is => 'ro', |
44
|
|
|
|
|
|
|
required => 1, |
45
|
|
|
|
|
|
|
); |
46
|
|
|
|
|
|
|
|
47
|
17
|
50
|
|
17
|
|
56248
|
|
|
9
|
50
|
|
9
|
|
13
|
|
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
23
|
|
48
|
9
|
|
|
|
|
37
|
has _filter => ( |
49
|
|
|
|
|
|
|
is => 'lazy', |
50
|
|
|
|
|
|
|
init_arg => undef, |
51
|
|
|
|
|
|
|
default => method { $self->coerce_attr( attr => $self->action, type => 'filter' ) }, |
52
|
|
|
|
|
|
|
); |
53
|
|
|
|
|
|
|
|
54
|
9
|
|
|
|
|
5441
|
|
55
|
|
|
|
|
|
|
method filter( $item ) { |
56
|
|
|
|
|
|
|
$self->logger->debugf( |
57
|
|
|
|
|
|
|
'applying %s since %s matched %s', |
58
|
|
|
|
|
|
|
$self->action_name, |
59
|
|
|
|
|
|
|
$self->condition_name, |
60
|
|
|
|
|
|
|
$item->find('guid, link, title')->first->text |
61
|
|
|
|
|
|
|
); |
62
|
17
|
50
|
66
|
17
|
|
55900
|
return $self->_filter->( $item, $self->condition_name ); |
|
10
|
50
|
|
10
|
|
13353
|
|
|
10
|
50
|
|
|
|
32
|
|
|
10
|
|
|
|
|
18
|
|
|
10
|
|
|
|
|
79
|
|
|
10
|
|
|
|
|
500152
|
|
63
|
10
|
|
|
|
|
15
|
} |
64
|
10
|
|
|
15
|
|
45
|
|
|
15
|
|
|
|
|
6228
|
|
|
9
|
|
|
|
|
1834
|
|
|
9
|
|
|
|
|
4073
|
|
65
|
10
|
|
|
|
|
221
|
|
66
|
|
|
|
|
|
|
has action_name => ( |
67
|
|
|
|
|
|
|
is => 'lazy', |
68
|
|
|
|
|
|
|
default => method { $self->nice_name_for( $self->action, 'filter' ) }, |
69
|
|
|
|
|
|
|
); |
70
|
17
|
50
|
|
17
|
|
53317
|
|
|
16
|
50
|
|
16
|
|
28
|
|
|
16
|
50
|
|
|
|
38
|
|
|
16
|
|
|
|
|
28
|
|
|
16
|
|
|
|
|
34
|
|
|
16
|
|
|
|
|
23
|
|
|
16
|
|
|
|
|
33
|
|
71
|
17
|
|
|
17
|
|
1926
|
|
|
17
|
|
|
|
|
38
|
|
|
17
|
|
|
|
|
1713
|
|
72
|
17
|
|
|
17
|
|
14093
|
method constrain( Mojo::DOM $Mojo_DOM ) { |
|
17
|
|
|
|
|
64786
|
|
|
17
|
|
|
|
|
135
|
|
73
|
16
|
|
|
|
|
28
|
my $count = 0; |
74
|
16
|
|
|
|
|
31
|
$Mojo_DOM->find( 'item' )->grep( sub { $self->match( shift ) } )->each( sub { $self->filter( shift ); ++$count; } ); |
|
2
|
|
|
|
|
31
|
|
75
|
14
|
|
|
|
|
23
|
return $count; |
|
12
|
|
|
|
|
185
|
|
76
|
2
|
|
|
|
|
3
|
} |
|
2
|
|
|
|
|
30
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# internal helper methods |
79
|
|
|
|
|
|
|
|
80
|
17
|
|
|
17
|
|
42306
|
method nice_name_for( $attr, $type ) { |
|
16
|
|
|
16
|
|
29938
|
|
|
16
|
|
|
|
|
82
|
|
81
|
16
|
100
|
|
|
|
61
|
use feature 'switch'; |
82
|
6
|
|
|
|
|
25
|
use experimental 'smartmatch'; |
83
|
6
|
|
|
|
|
17
|
given( ref $attr ) { |
84
|
|
|
|
|
|
|
when( 'CODE' ) { return "unnamed RSS ${type}"; } |
85
|
16
|
|
|
|
|
342
|
when( q{} ) { return $attr } |
86
|
|
|
|
|
|
|
default { return $_ } |
87
|
|
|
|
|
|
|
} |
88
|
17
|
50
|
|
17
|
|
38899
|
} |
|
16
|
50
|
|
16
|
|
367
|
|
|
16
|
|
|
|
|
55
|
|
|
16
|
|
|
|
|
25
|
|
|
16
|
|
|
|
|
49
|
|
89
|
|
|
|
|
|
|
|
90
|
16
|
|
|
|
|
294
|
method BUILDARGS( %args ) { |
91
|
|
|
|
|
|
|
if ( 1 == keys %args ) { |
92
|
|
|
|
|
|
|
@args{'condition','action'} = each %args; |
93
|
17
|
50
|
|
17
|
|
61122
|
delete $args{ $args{ condition } }; |
|
29
|
50
|
|
29
|
|
43
|
|
|
29
|
|
|
|
|
137
|
|
|
29
|
|
|
|
|
57
|
|
|
29
|
|
|
|
|
52
|
|
|
29
|
|
|
|
|
49
|
|
|
29
|
|
|
|
|
41
|
|
|
29
|
|
|
|
|
71
|
|
|
29
|
|
|
|
|
67
|
|
94
|
29
|
50
|
|
|
|
110
|
} |
95
|
17
|
|
|
17
|
|
2598
|
return \%args; |
|
17
|
|
|
|
|
33
|
|
|
17
|
|
|
|
|
1373
|
|
96
|
17
|
|
|
17
|
|
89
|
} |
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
82
|
|
97
|
29
|
|
|
|
|
111
|
|
98
|
29
|
|
|
|
|
64
|
method BUILD( $args ) { |
99
|
9
|
|
|
|
|
168
|
# validate coercion of condition & action |
100
|
|
|
|
|
|
|
$self->$_ for qw< _filter _match >; |
101
|
20
|
|
|
|
|
33
|
} |
102
|
16
|
|
|
|
|
44
|
|
103
|
|
|
|
|
|
|
method coerce_attr( :$attr, :$type ) { |
104
|
4
|
|
|
|
|
7
|
die "can't use an undefined value to $type RSS items" if not defined $attr; |
105
|
4
|
100
|
|
|
|
20
|
use feature 'switch'; |
106
|
3
|
|
|
3
|
|
52
|
use experimental 'smartmatch'; |
107
|
2
|
|
|
|
|
52
|
given( ref $attr ) { |
108
|
|
|
|
|
|
|
when( 'CODE' ) { |
109
|
|
|
|
|
|
|
return $attr; |
110
|
2
|
|
|
|
|
25
|
} |
111
|
|
|
|
|
|
|
when( q{} ) { # not a ref |
112
|
|
|
|
|
|
|
return $self->coerce_module_name_to_sub( module_name => $attr, type => $type ); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
default { |
115
|
|
|
|
|
|
|
if( my $method = $attr->can( $type ) ) { |
116
|
17
|
50
|
|
17
|
|
64125
|
return sub { $attr->$type( @_ ); } |
|
16
|
50
|
|
16
|
|
27
|
|
|
16
|
|
|
|
|
56
|
|
|
16
|
|
|
|
|
29
|
|
|
16
|
|
|
|
|
28
|
|
|
16
|
|
|
|
|
25
|
|
|
16
|
|
|
|
|
25
|
|
|
16
|
|
|
|
|
38
|
|
|
16
|
|
|
|
|
33
|
|
117
|
16
|
|
|
|
|
100
|
} |
118
|
|
|
|
|
|
|
else |
119
|
|
|
|
|
|
|
{ |
120
|
|
|
|
|
|
|
die "${_}::$type does not exist"; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
method coerce_module_name_to_sub( :$module_name, :$type ) { |
127
|
|
|
|
|
|
|
my ($namespace, $additional_args) = |
128
|
16
|
|
100
|
|
|
97
|
$module_name =~ m/ |
129
|
16
|
100
|
|
|
|
54
|
\A |
130
|
4
|
|
|
|
|
16
|
( [^\[]+ ) # namespace |
131
|
|
|
|
|
|
|
(?: # followed by optional |
132
|
|
|
|
|
|
|
\[ |
133
|
16
|
|
|
|
|
26
|
( .* ) # additional arguments |
134
|
|
|
|
|
|
|
\] # in square brackets |
135
|
16
|
100
|
|
|
|
86
|
)? # optional, remember? |
136
|
2
|
|
|
|
|
138
|
\z |
137
|
|
|
|
|
|
|
/xms; |
138
|
|
|
|
|
|
|
my @additional_args = split q{,}, $additional_args // q{}; |
139
|
|
|
|
|
|
|
if( $namespace !~ /::/xms ) { |
140
|
16
|
|
|
|
|
578
|
$namespace = join q{::}, qw< App Rssfilter >, ucfirst( $type ), $namespace; |
141
|
16
|
100
|
|
|
|
160
|
} |
142
|
4
|
|
|
|
|
17
|
|
143
|
|
|
|
|
|
|
$namespace =~ s/\A :: //xms; # '::anything'->can() will die |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
if( not Class::Inspector->loaded( $namespace ) ) { |
146
|
16
|
100
|
|
|
|
2009
|
Module::Runtime::require_module $namespace; |
147
|
12
|
100
|
|
|
|
29
|
} |
148
|
|
|
|
|
|
|
|
149
|
13
|
|
|
13
|
|
288
|
# create an object if we got an OO package |
150
|
10
|
|
|
|
|
366
|
my $invocant = $namespace; |
151
|
|
|
|
|
|
|
if( $namespace->can( 'new' ) ) { |
152
|
|
|
|
|
|
|
$invocant = $namespace->new( @additional_args ); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
3
|
|
|
3
|
|
50
|
# return a wrapper |
156
|
2
|
|
|
|
|
62
|
if( my $method = $invocant->can( $type ) ) { |
157
|
|
|
|
|
|
|
if( $invocant eq $namespace ) { |
158
|
|
|
|
|
|
|
return sub { |
159
|
|
|
|
|
|
|
$method->( @_, @additional_args) ; |
160
|
|
|
|
|
|
|
}; |
161
|
4
|
|
|
|
|
75
|
} |
162
|
|
|
|
|
|
|
else |
163
|
|
|
|
|
|
|
{ |
164
|
|
|
|
|
|
|
return sub { |
165
|
|
|
|
|
|
|
$invocant->$method( @_ ); |
166
|
|
|
|
|
|
|
}; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
else |
170
|
|
|
|
|
|
|
{ |
171
|
|
|
|
|
|
|
die "${namespace}::$type does not exist"; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
1; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
__END__ |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=pod |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=encoding UTF-8 |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head1 NAME |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
App::Rssfilter::Rule - match and filter RSS feeds |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head1 VERSION |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
version 0.08 |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=head1 SYNOPSIS |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
use App::RssFilter::Rule; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
use Mojo::DOM; |
195
|
|
|
|
|
|
|
my $rss = Mojo::DOM->new( 'an RSS document' ); |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
my $delete_duplicates_rule = App::Rssfilter::Rule->new( Duplicate => 'DeleteItem' ); |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# shorthand for |
200
|
|
|
|
|
|
|
$delete_duplicates_rule = App::Rssfilter::Rule->new( |
201
|
|
|
|
|
|
|
condition => 'App::Rssfilter::Match::Duplicate', |
202
|
|
|
|
|
|
|
action => 'App::Rssfilter::Filter::DeleteItem', |
203
|
|
|
|
|
|
|
); |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# apply rule to RSS document |
206
|
|
|
|
|
|
|
$delete_duplicates_rule->constrain( $rss ); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# write modules with match and filter subs |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
package MyMatcher::LevelOfInterest; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub new { |
213
|
|
|
|
|
|
|
my ( $class, @bracketed_args) = @_; |
214
|
|
|
|
|
|
|
if ( grep { $_ eq 'BORING' } @bracketed_args ) { |
215
|
|
|
|
|
|
|
# turn on boredom detection circuits |
216
|
|
|
|
|
|
|
... |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
... |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub match { |
222
|
|
|
|
|
|
|
my ( $self, $mojo_dom_rss_item ) = @_; |
223
|
|
|
|
|
|
|
... |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
package MyFilter::MakeMoreInteresting; |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub filter { |
229
|
|
|
|
|
|
|
my ( $reason_for_match, |
230
|
|
|
|
|
|
|
$matched_mojo_dom_rss_item, |
231
|
|
|
|
|
|
|
@bracketed_args ) = @_; |
232
|
|
|
|
|
|
|
... |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
package main; |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
my $boring_made_interesting_rule = App::Rssfilter::Rule->new( |
238
|
|
|
|
|
|
|
'MyMatcher::LevelOfInterest[BORING]' |
239
|
|
|
|
|
|
|
=> 'MyFilter::MakeMoreInteresting[glitter,lasers]' |
240
|
|
|
|
|
|
|
); |
241
|
|
|
|
|
|
|
$boring_made_interesting_rule->constrain( $rss ); |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
my $interesting_with_decoration_rule = App::Rssfilter::Rule->new( |
244
|
|
|
|
|
|
|
condition => MyMatcher::LevelOfInterest->new('OUT_OF_SIGHT'), |
245
|
|
|
|
|
|
|
condition_name => 'ReallyInteresting', # instead of plain 'MyMatcher::LevelOfInterest' |
246
|
|
|
|
|
|
|
action => 'MyFilter::MakeMoreInteresting[ascii_art]', |
247
|
|
|
|
|
|
|
); |
248
|
|
|
|
|
|
|
$interesting_with_decoration_rule->constrain( $rss ); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# or use anonymous subs |
251
|
|
|
|
|
|
|
my $space_the_final_frontier_rule = App::Rssfilter:Rule->new( |
252
|
|
|
|
|
|
|
condition => sub { |
253
|
|
|
|
|
|
|
my ( $item_to_match ) = @_; |
254
|
|
|
|
|
|
|
return $item_to_match->at('title')->text =~ / \b space \b /ixms; |
255
|
|
|
|
|
|
|
}, |
256
|
|
|
|
|
|
|
action => sub { |
257
|
|
|
|
|
|
|
my ( $reason_for_match, $matched_item ) = @_; |
258
|
|
|
|
|
|
|
my @to_check = ( $matched_item->tree ); |
259
|
|
|
|
|
|
|
my %seen; |
260
|
|
|
|
|
|
|
while( my $elem = pop @to_check ) { |
261
|
|
|
|
|
|
|
next if 'ARRAY' ne ref $elem or $seen{ $elem }++; |
262
|
|
|
|
|
|
|
if( $elem->[0] eq 'text' ) { |
263
|
|
|
|
|
|
|
$elem->[1] =~ s/ \b space \b /\& (the final frontier)/xmsig; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
else |
266
|
|
|
|
|
|
|
{ |
267
|
|
|
|
|
|
|
push @to_check, @{ $elem }; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
}, |
271
|
|
|
|
|
|
|
); |
272
|
|
|
|
|
|
|
$space_the_final_frontier_rule->constrain( $rss ); |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
### or with an App::Rssfilter feed or group |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
use App::RssFilter::Feed; |
277
|
|
|
|
|
|
|
my $feed = App::RssFilter::Feed->new( 'examples' => 'http://example.org/e.g.rss' ); |
278
|
|
|
|
|
|
|
$feed->add_rule( 'My::Matcher' => 'My::Filter' ); |
279
|
|
|
|
|
|
|
# same as |
280
|
|
|
|
|
|
|
$feed->add_rule( App::Rssfilter::Rule->new( 'My::Matcher' => 'My::Filter' ) ); |
281
|
|
|
|
|
|
|
$feed->update; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=head1 DESCRIPTION |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
This module will test all C<item> elements in a L<Mojo::DOM> object against a condition, and apply an action on items where the condition is true. |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
It consumes the L<App::Rssfilter::Logger> role. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=head2 logger |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
This is a object used for logging; it defaults to a L<Log::Any> object. It is provided by the L<App::Rssfilter::Logger> role. |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head2 condition |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
This is the module, object, or coderef to use to match C<item> elements for filtering. Modules are passed as strings, and must contain a C<match> sub. Object must have a C<match> method. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head2 _match |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
This is a coderef created from this rule's condition which will be used by L</match> to check RSS items. It is automatically coerced from the C<condition> attribute and cannot be passed to the constructor. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
If this rule's condition is an object, C<_match> will store a wrapper which calls the C<match> method of the object. |
304
|
|
|
|
|
|
|
If this rule's condition is a subref, C<_match> will store the same subref. |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
If this rule's condition is a string, it is treated as a namespace. If the string is not a fully-specified namespace, it will be changed to C<App::Rssfilter::Match::I<<string>>>; if you really want to use C<&TopLevelNamespace::match>, specify C<condition> as C<'::TopLevelNamespace'> (or directly as C<\&TopLevelNameSpace::match>). Additional arguments can be passed to the matcher by appending then to the string, separated by commas, surrounded by square brackets. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
C<_match> will then be set to a wrapper: |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=over 4 |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=item * |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
If C<I<< <namespace> >>::new> exists, C<_match> will be set as if C<condition> had originally been the object returned from calling C<I<< <namespace> >>::new( @additional_arguments )>. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=item * |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Otherwise, C<_match> will store a wrapper which calls C<I<< <namespace> >>::match( $rss_item, @additional_arguments )>. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=back |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head2 condition_name |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
This is a nice name for the condition, which will be used as the reason for the match given to the action. Defaults to the class of the condition, or its value if it is a simple scalar, or C<unnamed RSS matcher> otherwise. |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=head2 action |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
This is the module, object, or coderef to use to filter C<item> elements matched by this rule's condition. Modules are passed as strings, and must contain a C<filter> sub. Object must have a C<filter> method. |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=head2 _filter |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
This is a coderef created from this rule's action which will be used by L</filter> to check RSS items. It is automatically coerced from the C<action> attribute and cannot be passed to the constructor. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
If this rule's action is an object, C<_filter> will store a wrapper which calls the C<filter> method of the object. |
335
|
|
|
|
|
|
|
If this rule's action is a subref, C<_filter> will store the same subref. |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
If the rule's action is a string, it is treated as a namespace. If the string is not a fully-specified namespace, it will be changed to C<App::Rssfilter::filter::I<<string>>>; if you really want to use C<&TopLevelNamespace::filter>, specify C<action> as C<'::TopLevelNamespace'> (or directly as C<\&TopLevelNameSpace::filter>). Additional arguments can be passed to the filter by appending then to the string, separated by commas, surrounded by square brackets. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
The filter will then be set to a wrapper: |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=over 4 |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=item * |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
If C<I<< <namespace> >>::new> exists, C<_filter> will be set as if C<action> had originally been the object returned from calling C<I<< <namespace> >>::new( @additional_arguments )>. |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=item * |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Otherwise, C<_filter> will store a wrapper which calls C<I<< <namespace> >>::filter( $rss_item, @additional_arguments )>. |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=back |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=head2 action_name |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
This is a nice name for the action. Defaults to the class of the action, or its value if it is a simple scalar, or C<unnamed RSS filter> otherwise. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=head1 METHODS |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=head2 match |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
my $did_match = $self->match( $item_element_from_Mojo_DOM ); |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
Returns the result of testing this rule's condition against C<$item>. |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=head2 filter |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
$self->filter( $item_element_from_Mojo_DOM ); |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
Applies this rule's action to C<$item>. |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=head2 constrain |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
my $count_of_filtered_items = $rule->constrain( $Mojo_DOM ); |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
Gathers all child item elements of C<$Mojo_DOM> for which the condition is true, and applies the action to each. Returns the number of items that were matched (and filtered). |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head1 SEE ALSO |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=over 4 |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=item * |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
L<App::Rssfilter::Match::AbcPreviews> |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=item * |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
L<App::Rssfilter::Match::BbcSports> |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=item * |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
L<App::Rssfilter::Match::Category> |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=item * |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
L<App::Rssfilter::Match::Duplicates> |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=item * |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
L<App::Rssfilter::Filter::MarkTitle> |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=item * |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
L<App::Rssfilter::Filter::DeleteItem> |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=item * |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
L<App::RssFilter::Group> |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=item * |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
L<App::RssFilter::Feed> |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=item * |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
L<App::RssFilter> |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=back |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head1 AUTHOR |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
Daniel Holz <dgholz@gmail.com> |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
This software is copyright (c) 2015 by Daniel Holz. |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
428
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=cut |