File Coverage

blib/lib/App/Rssfilter/FromHash.pm
Criterion Covered Total %
statement 63 65 96.9
branch 2 4 50.0
condition n/a
subroutine 13 13 100.0
pod n/a
total 78 82 95.1


line stmt bran cond sub pod time code
1             # ABSTRACT: a role for creating App::Rssfilter objects from a configuration hash
2              
3              
4 6     6   4795 use strict;
  6         15  
  6         178  
5 6     6   31 use warnings;
  6         14  
  6         328  
6              
7             package App::Rssfilter::FromHash;
8             $App::Rssfilter::FromHash::VERSION = '0.08'; # TRIAL
9 6     6   31 use Moo::Role; # test harness uses Test::Routine, which wants a Moose-y role, son no Role::Tiny
  6         12  
  6         45  
10 6     6   16321 use Method::Signatures;
  6         11  
  6         52  
11 6     6   3235 use Scalar::Util qw< blessed >;
  6         13  
  6         433  
12              
13             requires 'add_feed';
14             requires 'add_rule';
15             requires 'add_group';
16              
17              
18 6 50   6   18757 method from_hash( $config_ref, @config ) {
  2     2   15878  
  2         9  
  2         3  
  2         10  
19 2 50       6 if ( 'HASH' ne ref $config_ref ) {
20 2         6 unshift @config, $config_ref;
21 2         4 $config_ref = {};
22             }
23 2         3 $self->_from_hash( %{ $config_ref }, @config );
  2         14  
24             }
25              
26 6     6   14662 method _from_hash( %config ) {
  3     3   6  
  3         14  
27 3         17 my $group = $self->new( name => $config{name} );
28              
29 3         2964 map { $group->add_feed( @{ $_ } ) } $self->split_for_ctor( @{ $config{feeds} } );
  2         3  
  2         13  
  3         18  
30 3         8 map { $group->add_rule( @{ $_ } ) } $self->split_for_ctor( @{ $config{rules} } );
  2         4  
  2         21  
  3         11  
31              
32 3         5 for my $subgroup ( @{ $config{groups} } ) {
  3         9  
33 1         2 $group->add_group( $self->_from_hash( %{ $subgroup } ) );
  1         9  
34             }
35              
36 3         25 return $group;
37             }
38              
39              
40 6     6   14614 method split_for_ctor( @list ) {
  7     7   11931  
  7         24  
41 7         10 my @results;
42 7         20 while( @list ) {
43 6     6   514 use experimental 'smartmatch';
  6         14  
  6         54  
44 6     6   416 use feature 'switch';
  6         13  
  6         1493  
45 7         14 given( shift @list ) {
46 7         15 when( 'HASH' eq ref $_ ) { push @results, [ %{ $_ } ] }
  1         2  
  1         6  
47 6         10 when( 'ARRAY' eq ref $_ ) { push @results, [ @{ $_ } ] }
  0         0  
  0         0  
48             # squash 'Argument "foo" isn't numeric in smart match'
49 6         14 when( '' ne ref $_ ) { push @results, [ $_ ] }
  5         24  
50 1         2 default { push @results, [ $_ => shift @list ] };
  1         5  
51             };
52             }
53 7         22 return @results;
54             }
55              
56             1;
57              
58             __END__
59              
60             =pod
61              
62             =encoding UTF-8
63              
64             =head1 NAME
65              
66             App::Rssfilter::FromHash - a role for creating App::Rssfilter objects from a configuration hash
67              
68             =head1 VERSION
69              
70             version 0.08
71              
72             =head1 SYNOPSIS
73              
74             {
75             package Cool::Name;
76             use Role::Tiny::With;
77             with 'App::Rssfilter::FromHash';
78              
79             sub new { ... }
80             sub add_group { ... }
81             sub add_feed { ... }
82             sub add_rule { ... }
83             };
84              
85              
86             my $cool_name = Cool::Name->from_hash(
87             name => 'some group',
88             rules => [
89             # add_rule will be called with ...
90             keyvalue_pair => 'some value',
91             # then ...
92             {
93             this_hashref => 'of options',
94             with_multiple => 'keys and values',
95             },
96             # and then ...
97             $already_constructed_object,
98             ],
99             feeds => [
100             # same as rules above
101             # mix elements as you please
102             keyword_pair_for_first_feed => 'and value',
103             keyword_pair_for_second_feed => 'with different value',
104             {
105             feed_option1 => 'more key-value pairs',
106             feed_option2 => 'which will be passed as arguments',
107             feed_option3 => 'for the third call to add_feed',
108             },
109             ],
110             groups => [
111             {
112             name => 'a subgroup',
113             # subgroups can have their own feeds, rules, and subgroups
114             feeds => [ ... ],
115             rules => [ ... ],
116             groups => [ ... ],
117             },
118             {
119             name => 'another subgroup',
120             feeds => [ ... ],
121             rules => [ ... ],
122             groups => [ ... ],
123             },
124             ],
125             );
126              
127             =head1 DESCRIPTION
128              
129             This role will extend its receiving class with a L</from_hash> method. It requires that the receiver has C<add_group>, C<add_feed>, and C<add_rule> methods, and accepts a C<name> attribute to its constructor.
130              
131             =head1 METHODS
132              
133             =head2 from_hash
134              
135             my $receiver_instance = Receiver::Class->from_hash( %config );
136              
137             Create a new instance of the receiving class (using C<$config{name}> as its name), then walk the hash to create subgroups and add feeds or rules to it (or its subgroups).
138              
139             The hash may have four elements:
140              
141             =over 4
142              
143             =item *
144              
145             C<name> - name of this group
146              
147             =item *
148              
149             C<groups> - arrayref of hashrefs for subgroups, same schema as the original hash
150              
151             =item *
152              
153             C<feeds> - arrayref of feeds to fetch
154              
155             =item *
156              
157             C<rules> - arrayref of rules to apply
158              
159             =back
160              
161             Bare scalars in C<feeds> will be collected into key-value pairs; everything else will be mapped onto the receiver's C<add_feed>. Likewise for C<rules>.
162              
163             =head2 split_for_ctor
164              
165             B<INTERNAL>
166              
167             my @arguments_for_ctor_in_arrayrefs = $receiving_instance->split_for_ctor( @args );
168              
169             Returns the elements of C<@args> partitioned into arrayrefs, whose contents are suitable arguments for a L<Moose>-y constructor. Collects bare scalars in C<@args> with their following element into key-value pairs; arrayrefs & hashrefs are dereferenced; everthing else is taken as-is.
170              
171             =head1 AUTHOR
172              
173             Daniel Holz <dgholz@gmail.com>
174              
175             =head1 COPYRIGHT AND LICENSE
176              
177             This software is copyright (c) 2015 by Daniel Holz.
178              
179             This is free software; you can redistribute it and/or modify it under
180             the same terms as the Perl 5 programming language system itself.
181              
182             =cut