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