File Coverage

blib/lib/WWW/Noss/FeedConfig.pm
Criterion Covered Total %
statement 184 198 92.9
branch 39 54 72.2
condition 10 20 50.0
subroutine 26 27 96.3
pod 17 18 94.4
total 276 317 87.0


line stmt bran cond sub pod time code
1             package WWW::Noss::FeedConfig;
2 6     6   431209 use 5.016;
  6         42  
3 6     6   39 use strict;
  6         28  
  6         168  
4 6     6   41 use warnings;
  6         10  
  6         483  
5             our $VERSION = '2.02';
6              
7 6     6   1283 use parent 'WWW::Noss::BaseConfig';
  6         883  
  6         40  
8              
9 6     6   374 use List::Util qw(any min);
  6         11  
  6         15612  
10              
11             sub new {
12              
13 17     17 1 812991 my ($class, %param) = @_;
14              
15 17         48 my $self = bless {}, $class;
16              
17 17         83 $self->initialize(%param);
18              
19 17         124 return $self;
20              
21             }
22              
23             sub initialize {
24              
25 17     17 0 60 my ($self, %param) = @_;
26              
27 17         99 $self->SUPER::initialize;
28 17         85 $self->set_name($param{ name });
29 17         65 $self->set_feed($param{ feed });
30 17         68 $self->set_path($param{ path });
31 17         64 $self->set_etag($param{ etag });
32 17         68 $self->set_retry_cache($param{ retry_cache });
33              
34 17         50 my $default = $param{ default };
35              
36             # Apply default parameters
37 17 100       40 if (defined $default) {
38 1         5 $self->set_limit($default->limit);
39 1         4 $self->set_respect_skip($default->respect_skip);
40 1         5 $self->set_include_title($default->include_title);
41 1         4 $self->set_exclude_title($default->exclude_title);
42 1         4 $self->set_include_content($default->include_content);
43 1         3 $self->set_exclude_content($default->exclude_content);
44 1         4 $self->set_include_tags($default->include_tags);
45 1         4 $self->set_exclude_tags($default->exclude_tags);
46 1         3 $self->set_autoread($default->autoread);
47 1         3 $self->set_default_update($default->default_update);
48 1         3 $self->set_hidden($default->hidden);
49             }
50              
51 17   100     89 $self->set_groups($param{ groups } // []);
52              
53 17 100       24 if (@{ $self->groups }) {
  17         71  
54              
55             # Set lowest limit defined by groups if present
56 1         2 my $limit = min grep { defined } map { $_->limit } @{ $self->groups };
  3         11  
  3         9  
  1         4  
57 1 50       8 $self->set_limit($limit) if defined $limit;
58              
59             # If any group respects skip, we respect skip
60 1     1   7 my $rs = any { $_->respect_skip } @{ $self->groups };
  1         4  
  1         3  
61 1         7 $self->set_respect_skip($rs);
62              
63             # Overlay group filters
64 1         7 push @{ $self->include_title },
65 3   50     5 map { @{ $_->include_title // [] } }
  3         7  
66 1         2 @{ $self->groups };
  1         4  
67 1         6 push @{ $self->exclude_title },
68 3   50     6 map { @{ $_->exclude_title // [] } }
  3         7  
69 1         3 @{ $self->groups };
  1         4  
70 1         7 push @{ $self->include_content },
71 3   50     5 map { @{ $_->include_content // [] } }
  3         7  
72 1         2 @{ $self->groups };
  1         3  
73 1         6 push @{ $self->exclude_content },
74 3   50     5 map { @{ $_->exclude_content // [] } }
  3         8  
75 1         2 @{ $self->groups };
  1         3  
76 1         8 push @{ $self->include_tags },
77 3   50     7 map { @{ $_->include_tags // [] } }
  3         7  
78 1         2 @{ $self->groups };
  1         3  
79 1         12 push @{ $self->exclude_tags },
80 3   50     4 map { @{ $_->exclude_tags // [] } }
  3         8  
81 1         2 @{ $self->groups };
  1         3  
82              
83             # If any group wants autoread, we'll take autoread
84 1     1   6 my $ar = any { $_->autoread } @{ $self->groups };
  1         3  
  1         3  
85 1         8 $self->set_autoread($ar);
86              
87             # If any group does not want default_updates, we'll take no default
88             # updates
89 1     2   4 my $ndu = any { !$_->default_update } @{ $self->groups };
  2         6  
  1         4  
90 1         6 $self->set_default_update(!$ndu);
91              
92             # If any groups wants hidden, take hidden
93 1     1   3 my $hid = any { $_->hidden } @{ $self->groups };
  1         4  
  1         3  
94 1         6 $self->set_hidden($hid);
95              
96             }
97              
98 17 100       128 if (defined $param{ limit }) {
99 2         10 $self->set_limit($param{ limit });
100             }
101 17 50       47 if (defined $param{ respect_skip }) {
102 0         0 $self->set_respect_skip($param{ respect_skip });
103             }
104 17 100       38 if (defined $param{ include_title }) {
105 3         4 push @{ $self->include_title }, @{ $param{ include_title } };
  3         10  
  3         14  
106             }
107 17 100       39 if (defined $param{ exclude_title }) {
108 3         4 push @{ $self->exclude_title }, @{ $param{ exclude_title } };
  3         9  
  3         7  
109             }
110 17 100       36 if (defined $param{ include_content }) {
111 3         4 push @{ $self->include_content }, @{ $param{ include_content } };
  3         8  
  3         8  
112             }
113 17 100       45 if (defined $param{ exclude_content }) {
114 3         5 push @{ $self->exclude_content }, @{ $param{ exclude_content } };
  3         6  
  3         6  
115             }
116 17 100       48 if (defined $param{ include_tags }) {
117 3         5 push @{ $self->include_tags }, @{ $param{ include_tags } };
  3         7  
  3         31  
118             }
119 17 100       54 if (defined $param{ exclude_tags }) {
120 3         5 push @{ $self->exclude_tags }, @{ $param{ exclude_tags } };
  3         7  
  3         6  
121             }
122 17 100       44 if (defined $param{ autoread }) {
123 1         4 $self->set_autoread($param{ autoread });
124             }
125 17 100       36 if (defined $param{ default_update }) {
126 1         4 $self->set_default_update($param{ default_update });
127             }
128 17 100       41 if (defined $param{ hidden }) {
129 1         3 $self->set_hidden($param{ hidden });
130             }
131              
132 17         40 return 1;
133              
134             }
135              
136             sub name {
137              
138 19     19 1 748 my ($self) = @_;
139              
140 19         106 return $self->{ Name };
141              
142             }
143              
144             sub set_name {
145              
146 17     17 1 39 my ($self, $name) = @_;
147              
148 17 50       41 unless (defined $name) {
149 0         0 die "name cannot be undefined";
150             }
151              
152             # ':' feeds are reserved for internal use
153 17 50       110 unless ($name =~ /^\:?\w+$/) {
154 0         0 die "name can only contain alphanumeric and underscore characters";
155             }
156              
157 17         43 $self->{ Name } = $name;
158              
159             }
160              
161             sub feed {
162              
163 17     17 1 33 my ($self) = @_;
164              
165 17         221 return $self->{ Feed };
166              
167             }
168              
169             sub set_feed {
170              
171 17     17 1 37 my ($self, $feed) = @_;
172              
173 17 50       67 unless (defined $feed) {
174 0         0 die "feed cannot be undefined";
175             }
176              
177 17         41 $self->{ Feed } = $feed;
178              
179             }
180              
181             sub groups {
182              
183 32     32 1 59 my ($self) = @_;
184              
185 32         108 return $self->{ Groups };
186              
187             }
188              
189             sub set_groups {
190              
191 17     17 1 46 my ($self, $new) = @_;
192              
193 17 50       39 unless (ref $new eq 'ARRAY') {
194 0         0 die "groups must be an array ref";
195             }
196              
197 17         59 for my $i (0 .. $#$new) {
198 3 50       8 unless (eval { $new->[$i]->isa('WWW::Noss::GroupConfig') }) {
  3         16  
199 0         0 die "group[$i] is not a WWW::Noss::GroupConfig object";
200             }
201             }
202              
203 17         40 $self->{ Groups } = $new;
204              
205             }
206              
207             sub has_group {
208              
209 3     3 1 1111 my ($self, $grp) = @_;
210              
211 3         6 return !! grep { $_->name eq $grp } @{ $self->groups };
  9         25  
  3         20  
212              
213             }
214              
215             sub path {
216              
217 17     17 1 577 my ($self) = @_;
218              
219 17         106 return $self->{ Path };
220              
221             }
222              
223             sub set_path {
224              
225 17     17 1 39 my ($self, $path) = @_;
226              
227 17 50       38 unless (defined $path) {
228 0         0 die "path cannot be undefined";
229             }
230              
231 17         37 $self->{ Path } = $path;
232              
233             }
234              
235             sub etag {
236              
237 1     1 1 4 my ($self) = @_;
238              
239 1         5 return $self->{ Etag };
240              
241             }
242              
243             sub set_etag {
244              
245 17     17 1 46 my ($self, $etag) = @_;
246              
247 17         33 $self->{ Etag } = $etag;
248              
249             }
250              
251             sub retry_cache {
252              
253 0     0 1 0 my ($self) = @_;
254              
255 0         0 return $self->{ RetryCache };
256              
257             }
258              
259             sub set_retry_cache {
260              
261 17     17 1 37 my ($self, $cache) = @_;
262              
263 17         33 $self->{ RetryCache } = $cache;
264              
265             }
266              
267             sub retry {
268              
269 2     2 1 6 my ($self) = @_;
270              
271 2 50 33     69 if (not defined $self->{ RetryCache } or not -f $self->{ RetryCache }) {
272 0         0 return undef;
273             }
274              
275             open my $fh, '<', $self->{ RetryCache }
276 2 50       114 or die "Failed to open $self->{ RetryCache } for reading: $!";
277 2         6 my $retry = do { local $/; (readline $fh)[0] };
  2         12  
  2         130  
278 2         33 close $fh;
279 2         8 chomp $retry;
280              
281 2 50       19 if ($retry !~ /^\d+$/) {
282 0         0 die "$self->{ RetryCache }: corrupted retry cache";
283             }
284              
285 2         19 return int $retry;
286              
287             }
288              
289             sub set_retry {
290              
291 1     1 1 4 my ($self, $retry) = @_;
292              
293 1 50       12 if ($retry !~ /^\d+$/) {
294 0         0 die 'retry time must be an integar';
295             }
296              
297 1 50       4 if (not defined $self->{ RetryCache }) {
298 0         0 die 'retry_cache must be set before setting retry';
299             }
300              
301 1         2 $retry = int $retry;
302              
303             open my $fh, '>', $self->{ RetryCache }
304 1 50       152 or die "Failed to open $self->{ RetryCache } for writing: $!";
305 1         5 print { $fh } $retry, "\n";
  1         25  
306 1         213 close $fh;
307              
308 1         39 return $retry;
309              
310             }
311              
312             sub can_we_retry {
313              
314 1     1 1 4 my ($self, $time) = @_;
315 1   33     9 $time //= time;
316              
317 1         4 my $retry = $self->retry;
318 1 50       5 if (not defined $retry) {
319 0         0 return 1;
320             }
321              
322 1         7 return $time >= $retry;
323              
324             }
325              
326             1;
327              
328             =head1 NAME
329              
330             WWW::Noss::FeedConfig - Class for storing feed configurations
331              
332             =head1 USAGE
333              
334             use WWW::Noss::FeedConfig;
335              
336             my $feed = WWW::Noss::FeedConfig->new(
337             name => 'feed',
338             feed => 'https://feed.xml',
339             path => 'feed.xml',
340             );
341              
342             =head1 DESCRIPTION
343              
344             B is a module that provides a class for storing L
345             feed configurations. This is a private module, please consult the L
346             manual for user documentation.
347              
348             =head1 METHODS
349              
350             Not all methods are documented here, as this class is derived from the
351             L module. Consult its documentation for additional
352             methods.
353              
354             =over 4
355              
356             =item $feed = WWW::Noss::FeedConfig->new(%param)
357              
358             Returns a blessed B object based on the parameters
359             provided in the C<%param> hash.
360              
361             The following are valid fields for the C<%param> hash. The C, C,
362             and C fields are the only required fields.
363              
364             =over 4
365              
366             =item name
367              
368             The name of feed. Can only only contain alphanumeric and underscore
369             characters.
370              
371             =item feed
372              
373             The feed URL.
374              
375             =item path
376              
377             Path to the location to store the feed.
378              
379             =item etag
380              
381             Path to store the feed's etag.
382              
383             =item groups
384              
385             Array ref of L groups that the feed is a part of.
386              
387             =item default
388              
389             L object representing the default feed group.
390              
391             =back
392              
393             The following fields from L are also available:
394              
395             =over 4
396              
397             =item limit
398              
399             =item respect_skip
400              
401             =item include_title
402              
403             =item exclude_title
404              
405             =item include_content
406              
407             =item exclude_content
408              
409             =item include_tags
410              
411             =item exclude_tags
412              
413             =item autoread
414              
415             =item default_update
416              
417             =item hidden
418              
419             =back
420              
421             =item $name = $feed->name()
422              
423             =item $feed->set_name($name)
424              
425             Getter/setter for the feed's name attribute.
426              
427             =item $url = $feed->feed()
428              
429             =item $feed->set_feed($url)
430              
431             Getter/setter for the feed's feed attribute.
432              
433             =item \@groups = $feed->groups()
434              
435             =item $feed->set_groups(\@groups)
436              
437             Getter/setter for the feed's groups attribute. Do note that modifying the
438             groups attribute does not affect the feed's configuration like it does during
439             initialization.
440              
441             =item $ok = $feed->has_group($group)
442              
443             Returns true if C<$feed> is a part of the group C<$group>.
444              
445             =item $path = $feed->path()
446              
447             =item $feed->set_path($path)
448              
449             Getter/setter for the feed's path attribute.
450              
451             =item $etag = $feed->etag()
452              
453             =item $feed->set_etag($etag)
454              
455             Getter/setter for the feed's etag attribute.
456              
457             =item $file = $feed->retry_cache()
458              
459             =item $feed->set_retry_cache($file)
460              
461             Getter/setter for the feed's retry cache file.
462              
463             =item $retry = $feed->retry()
464              
465             =item $feed->set_retry($retry)
466              
467             =item $ok = $feed->can_we_retry([ $time ])
468              
469             Getter/setter for the feed's retry time.
470              
471             =back
472              
473             =head1 AUTHOR
474              
475             Written by Samuel Young, Esamyoung12788@gmail.comE.
476              
477             This project's source can be found on its
478             L. Comments and pull
479             requests are welcome!
480              
481             =head1 COPYRIGHT
482              
483             Copyright (C) 2025-2026 Samuel Young
484              
485             This program is free software: you can redistribute it and/or modify
486             it under the terms of the GNU General Public License as published by
487             the Free Software Foundation, either version 3 of the License, or
488             (at your option) any later version.
489              
490             =head1 SEE ALSO
491              
492             L, L, L
493              
494             =cut
495              
496             # vim: expandtab shiftwidth=4