File Coverage

blib/lib/App/Rssfilter/Group.pm
Criterion Covered Total %
statement 107 107 100.0
branch 21 32 65.6
condition 7 12 58.3
subroutine 27 27 100.0
pod n/a
total 162 178 91.0


line stmt bran cond sub pod time code
1             # ABSTRACT: associate one or more rules with more than one feed
2              
3 6     6   1173029 use strict;
  6         17  
  6         162  
4 6     6   28 use warnings;
  6         13  
  6         290  
5              
6              
7             package App::Rssfilter::Group;
8             $App::Rssfilter::Group::VERSION = '0.08'; # TRIAL
9 6     6   2297 use Moo;
  6         41044  
  6         39  
10             with 'App::Rssfilter::Logger';
11             with 'App::Rssfilter::FromHash';
12             with 'App::Rssfilter::FromYaml';
13 6     6   26187 use Method::Signatures;
  6         242412  
  6         51  
14              
15 6     6   540860 method BUILDARGS( @options ) {
  12     12   763688  
  12         61  
16 12 100       58 if( 1 == @options ) {
17 5         12 unshift @options, 'name';
18             }
19 12         235 return { @options };
20             }
21              
22              
23 6 50 33 6   55718 method update( ArrayRef :$rules = [], :$storage = $self->storage ) {
  3 50   3   173  
  3 100       19  
  3 50       17  
  3 50       48  
  3         15397  
  3         23  
  3         8  
  3         14  
  3         15  
24 3         48 my $child_storage = $storage->path_push( $self->name );
25 3         222 my @rules = map { @{ $_ } } $rules, $self->rules;
  6         10  
  6         16  
26 3         18 $self->logger->debugf( 'filtering feeds in %s', $self->name );
27 3         14533 $_->update( rules => \@rules, storage => $child_storage ) for @{ $self->groups };
  3         46  
28 3         214 $_->update( rules => \@rules, storage => $child_storage ) for @{ $self->feeds };
  3         31  
29             }
30              
31              
32              
33             has name => (
34             is => 'ro',
35             default => sub { '.' },
36             );
37              
38              
39             has storage => (
40             is => 'ro',
41             default => method { App::Rssfilter::Feed::Storage->new },
42             );
43              
44              
45             has groups => (
46             is => 'ro',
47             default => sub { [] },
48             );
49 6 50   6   24207  
  8     8   155107  
  8         37  
  8         19  
  8         27  
50 6     6   565  
  6         13  
  6         722  
51 8 100 66     87 method add_group( $app_rssfilter_group, @group_options ) {
52 2         5 use Scalar::Util qw< blessed >;
53 2         47 if ( ! blessed( $app_rssfilter_group ) or ! $app_rssfilter_group->isa( 'App::Rssfilter::Group' ) ) {
54             unshift @group_options, $app_rssfilter_group; # restore original @_
55             $app_rssfilter_group = App::Rssfilter::Group->new( @group_options );
56 8         168 }
  8         38  
57 8         29  
58             push @{ $self->groups }, $app_rssfilter_group;
59             return $self;
60             }
61 6 50   6   13107  
  2 50   2   63  
  2         6  
  2         5  
  2         6  
62 6     6   511  
  6         14  
  6         647  
63 2     5   9 method group( $name ) {
  5         19  
  2         12  
64             use List::Util qw< first >;
65             first { $_->name eq $name } reverse @{ $self->groups };
66             }
67              
68              
69             has rules => (
70             is => 'ro',
71             default => sub { [] },
72             );
73 6 50   6   17596  
  4     4   2083  
  4         16  
  4         7  
  4         20  
74 6     6   551  
  6         14  
  6         509  
75 4 100 66     33 method add_rule( $app_rssfilter_rule, @rule_options ) {
76 1         3 use Scalar::Util qw< blessed >;
77 6     6   4707 if ( ! blessed( $app_rssfilter_rule ) or ! $app_rssfilter_rule->isa( 'App::Rssfilter::Rule' ) ) {
  6         21  
  6         445  
78 1         10 unshift @rule_options, $app_rssfilter_rule; # restore original @_
79             use App::Rssfilter::Rule;
80             $app_rssfilter_rule = App::Rssfilter::Rule->new( @rule_options );
81 4         66 }
  4         18  
82 4         15  
83             push @{ $self->rules }, $app_rssfilter_rule;
84             return $self;
85             }
86              
87              
88             has feeds => (
89             is => 'ro',
90             default => sub { [] },
91             );
92 6 50   6   22103  
  9     9   3810  
  9         37  
  9         16  
  9         31  
93 6     6   592  
  6         12  
  6         595  
94 9 100 66     82 method add_feed( $app_rssfilter_feed, @feed_options ) {
95 2         5 use Scalar::Util qw< blessed >;
96 6     6   4351 if ( ! blessed( $app_rssfilter_feed ) or ! $app_rssfilter_feed->isa( 'App::Rssfilter::Feed' ) ) {
  6         23  
  6         645  
97 2         31 unshift @feed_options, $app_rssfilter_feed; # restore original @_
98             use App::Rssfilter::Feed;
99             $app_rssfilter_feed = App::Rssfilter::Feed->new( @feed_options );
100 9         170 }
  9         53  
101 9         30  
102             push @{ $self->feeds }, $app_rssfilter_feed;
103             return $app_rssfilter_feed;
104             }
105 6 50   6   14610  
  2 50   2   64  
  2         8  
  2         4  
  2         6  
106 6     6   547  
  6         14  
  6         659  
107 2     5   8 method feed( $name ) {
  5         17  
  2         9  
108             use List::Util qw< first >;
109             first { $_->name eq $name } reverse @{ $self->feeds };
110             }
111              
112              
113              
114             1;
115              
116             __END__
117              
118             =pod
119              
120             =encoding UTF-8
121              
122             =head1 NAME
123              
124             App::Rssfilter::Group - associate one or more rules with more than one feed
125              
126             =head1 VERSION
127              
128             version 0.08
129              
130             =head1 SYNOPSIS
131              
132             use App::RssFilter::Group;
133              
134             my $news_group = App::Rssfilter::Group->new( 'news' );
135             # shorthand for
136             $news_group = App::Rssfilter::Group( name => 'news' );
137              
138             $news_group->add_group( 'USA' );
139             # shorthand for
140             $news_group->add_group(
141             App::Rssfilter::Group->new(
142             name => 'USA',
143             )
144             );
145             my $uk_news_group = $news_group->add_group( name => 'UK' );
146              
147             $uk_news_group->add_rule( 'Category[Politics]' => 'MarkTitle' );
148             # shorthand for
149             $uk_news_group->add_rule(
150             App::Rssfilter::Rule->new(
151             condition => 'Category[Politics]',
152             action => 'MarkTitle',
153             )
154             );
155              
156             my $dupe_rule = $news_group->group( 'USA' )->add_rule( condition => 'Duplicate', action => 'DeleteItem' );
157             $uk_news_group->add_rule( $dupe_rule );
158              
159             $news_group->group( 'USA' )->add_feed( WashPost => 'http://feeds.washingtonpost.com/rss/national' );
160             # shorthand for
161             $news_group->group( 'USA' )->add_feed(
162             App::Rssfilter::Feed->new(
163             name => 'WashPost',
164             url => 'http://feeds.washingtonpost.com/rss/national',
165             )
166             );
167             $news_group->group( 'USA' )->add_feed( name => 'NYTimes', url => 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml' );
168              
169             $uk_news_group->add_feed( $news_group->group( 'USA' )->feed( 'WashPost' ) );
170              
171             $news_group->update;
172              
173             =head1 DESCRIPTION
174              
175             This module groups together feeds so that the same rules will be used to constrain them.
176              
177             It consumes the L<App::Rssfilter::Logger> role.
178              
179             Use a group to:
180              
181             =over 4
182              
183             =item *
184              
185             allow rules which retain state (e.g. L<Duplicates|App::Rssfilter::Match::Duplicates>) to constrain over multiple feeds
186              
187             =item *
188              
189             apply the same rules configuration to multiple feeds
190              
191             =back
192              
193             =head1 ATTRIBUTES
194              
195             =head2 logger
196              
197             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.
198              
199             =head2 name
200              
201             This is the name of the group. Group names are used when storing a feed so that feeds from the same group are kept together. The default value is '.' (a single period).
202              
203             =head2 storage
204              
205             This is a feed storage object for feeds to use when they are updated. The default value is a fresh instance of L<App::Rssfilter::Feed::Storage>. See L</update> for details on when the default value is used.
206              
207             =head2 groups
208              
209             This is an arrayref of subgroups attatched to this group.
210              
211             =head2 rules
212              
213             This is an arrayref of rules to apply to the feeds in this group (and subgroups).
214              
215             =head2 feeds
216              
217             This is an arrayref of feeds.
218              
219             =head1 METHODS
220              
221             =head2 update
222              
223             $group->update( rules => $rules, storage => $storage );
224              
225             Recursively calls C<update> on the feeds and subgroups of this group.
226              
227             C<$rules> is an arrayref of additional rules to constrain the feed and groups, in addition to the group's current list of rules.
228              
229             C<$storage> is the feed storage object that feeds and subgroups will use to store their updated contents. If not specified, groups will use their default C<storage>. The group's C<name> is appended to the current path of C<$storage> before being passed to feeds and subgroups.
230              
231             =head2 add_group
232              
233             $group = $group->add_group( $app_rssfilter_group | %group_options );
234              
235             Adds C<$app_rssfilter_group> (or creates a new App::RssFilter::Group instance from the C<%group_options>) to the list of subgroups for this group. Returns this group (for chaining).
236              
237             =head2 group
238              
239             my $subgroup = $group->group( $name );
240              
241             Returns the last subgroup added to this group whose name is C<$name>, or C<undef> if no matching group.
242              
243             =head2 add_rule
244              
245             $group = $group->add_rule( $app_rssfilter_rule | %rule_options )
246              
247             Adds C<$app_rssfilter_rule> (or creates a new App::RssFilter::Rule instance from the C<%rule_options>) to the list of rules for this group. Returns this group (for chaining).
248              
249             =head2 add_feed
250              
251             $group = $group->add_feed( $app_rssfilter_feed | %feed_options );
252              
253             Adds C<$app_rssfilter_feed> (or creates a new App::RssFilter::Feed instance from the C<%feed_options>) to the list of feeds for this group. Returns this group (for chaining).
254              
255             =head2 feed
256              
257             my $feed = $group->feed( $name );
258              
259             Returns the last feed added to this group whose name is C<$name>, or C<undef> if no matching feed.
260              
261             =head2 from_hash
262              
263             my $group = App::Rssfilter::Group::from_hash( %config );
264              
265             Returns a new instance of this class with the feeds, rules, and subgroups specifed in C<%config>. This method is provided by L<App::Rssfilter::FromHash/from_hash>, which has additional documentation & examples.
266              
267             =head2 from_yaml
268              
269             my $group = App::Rssfilter::Group::from_yaml( $yaml_config );
270              
271             Returns a new instance of this class with the feeds, rules, and subgroups specifed in C<$yaml_config>. This method is provided by L<App::Rssfilter::FromYaml/from_yaml>, which has additional documentation & examples.
272              
273             =head1 SEE ALSO
274              
275             =over 4
276              
277             =item *
278              
279             L<App::RssFilter::Rule>
280              
281             =item *
282              
283             L<App::RssFilter::Feed>
284              
285             =item *
286              
287             L<App::RssFilter>
288              
289             =back
290              
291             =head1 AUTHOR
292              
293             Daniel Holz <dgholz@gmail.com>
294              
295             =head1 COPYRIGHT AND LICENSE
296              
297             This software is copyright (c) 2015 by Daniel Holz.
298              
299             This is free software; you can redistribute it and/or modify it under
300             the same terms as the Perl 5 programming language system itself.
301              
302             =cut