File Coverage

blib/lib/Circle/Ruleable.pm
Criterion Covered Total %
statement 44 119 36.9
branch 1 26 3.8
condition 0 16 0.0
subroutine 14 23 60.8
pod 0 10 0.0
total 59 194 30.4


line stmt bran cond sub pod time code
1             # You may distribute under the terms of the GNU General Public License
2             #
3             # (C) Paul Evans, 2008-2014 -- leonerd@leonerd.org.uk
4              
5             package Circle::Ruleable;
6              
7 4     4   26 use strict;
  4         7  
  4         103  
8 4     4   16 use warnings;
  4         6  
  4         86  
9 4     4   15 use base qw( Circle::Commandable );
  4         7  
  4         985  
10              
11             our $VERSION = '0.173320';
12              
13             sub init_rulestore
14             {
15 2     2 0 5 my $self = shift;
16 2         16 my %args = @_;
17              
18 2         14 $self->{rulestore} = Circle::Rule::Store->new( %args );
19             }
20              
21             sub run_rulechain
22             {
23 4     4 0 8 my $self = shift;
24 4         27 my ( $chainname, $event ) = @_;
25              
26 4 50       9 return if eval { $self->{rulestore}->run( $chainname, $event ); 1 };
  4         48  
  4         83  
27              
28 0         0 my $err = $@; chomp $err;
  0         0  
29 0         0 $self->responderr( "Exception during processing of rulechain '$chainname': $err" );
30             }
31              
32             sub command_rules
33             : Command_description("Display or manipulate action rules")
34       0 0   {
35             # The body doesn't matter as it never gets run
36 4     4   24 }
  4         6  
  4         36  
37              
38             sub command_rules_list
39             : Command_description("List the action rules")
40             : Command_subof('rules')
41             : Command_default()
42             : Command_arg('chain?')
43             {
44 0     0 0 0 my $self = shift;
45 0         0 my ( $chain, $cinv ) = @_;
46              
47 0         0 my $rulestore = $self->{rulestore};
48              
49 0         0 my @chains = $rulestore->chains;
50              
51 0 0       0 if( defined $chain ) {
52 0 0       0 grep { $chain eq $_ } @chains or
  0         0  
53             return $cinv->responderr( "No such rule chain '$chain'" );
54             }
55              
56 0         0 foreach my $chain ( sort @chains ) {
57 0         0 $cinv->respond( "Chain '$chain':" );
58 0         0 my @rules = $rulestore->get_chain( $chain )->deparse_rules();
59 0         0 $cinv->respond( "$_: $rules[$_]" ) for 0 .. $#rules;
60             }
61              
62 0         0 return;
63 4     4   1116 }
  4         24  
  4         24  
64              
65             sub command_rules_add
66             : Command_description("Add a new rule")
67             : Command_subof('rules')
68             : Command_arg('chain')
69             : Command_arg('spec', eatall => 1)
70             {
71 0     0 0 0 my $self = shift;
72 0         0 my ( $chain, $spec, $cinv ) = @_;
73              
74 0         0 my $rulestore = $self->{rulestore};
75              
76 0         0 $rulestore->get_chain( $chain )->append_rule( $spec );
77              
78 0         0 $cinv->respond( "Added to chain $chain" );
79 4     4   778 }
  4         7  
  4         14  
80              
81             sub command_rules_insert
82             : Command_description("Insert a rule before another rule")
83             : Command_subof('rules')
84             : Command_arg('chain')
85             : Command_arg('index')
86             : Command_arg('spec', eatall => 1)
87             {
88 0     0 0 0 my $self = shift;
89 0         0 my ( $chain, $index, $spec, $cinv ) = @_;
90              
91 0 0       0 $index =~ m/^\d+$/ or
92             return $cinv->responderr( "Bad index: $index" );
93              
94 0         0 my $rulestore = $self->{rulestore};
95              
96 0         0 $rulestore->get_chain( $chain )->insert_rule( $index, $spec );
97              
98 0         0 $cinv->respond( "Inserted in $chain before rule $index" );
99 4     4   795 }
  4         7  
  4         14  
100              
101             sub command_rules_replace
102             : Command_description("Replace an existing rule with a new one")
103             : Command_subof('rules')
104             : Command_arg('chain')
105             : Command_arg('index')
106             : Command_arg('spec', eatall => 1)
107             {
108 0     0 0 0 my $self = shift;
109 0         0 my ( $chain, $index, $spec, $cinv ) = @_;
110              
111             # We'll do this by inserting our new rule before the one we want to
112             # replace. If it works, delete the old one, which will now be one further
113             # down.
114              
115 0         0 my $rulestore = $self->{rulestore};
116 0         0 my $rulechain = $rulestore->get_chain( $chain );
117              
118 0         0 $rulechain->insert_rule( $index, $spec );
119 0         0 $rulechain->delete_rule( $index + 1 );
120              
121 0         0 $cinv->respond( "Replaced $chain rule $index" );
122 4     4   690 }
  4         8  
  4         21  
123              
124             sub command_rules_delete
125             : Command_description("Delete a rule")
126             : Command_subof('rules')
127             : Command_arg('chain')
128             : Command_arg('index')
129             {
130 0     0 0 0 my $self = shift;
131 0         0 my ( $chain, $index, $cinv ) = @_;
132              
133 0 0       0 $index =~ m/^\d+$/ or
134             return $cinv->responderr( "Bad index: $index" );
135              
136 0         0 my $rulestore = $self->{rulestore};
137              
138 0         0 $rulestore->get_chain( $chain )->delete_rule( $index );
139              
140 0         0 $cinv->respond( "Deleted $chain rule $index" );
141 4     4   860 }
  4         8  
  4         31  
142              
143             sub command_rules_describe
144             : Command_description("Describe rule conditions or actions")
145             : Command_subof('rules')
146             : Command_arg('name?')
147             : Command_opt('conds=+', desc => "List conditions")
148             : Command_opt('actions=+', desc => "List actions")
149             {
150 0     0 0 0 my $self = shift;
151 0         0 my ( $name, $opts, $cinv ) = @_;
152              
153 0         0 my $rulestore = $self->{rulestore};
154              
155 0         0 my @names;
156            
157 0 0       0 if( defined $name ) {
158 0         0 @names = ( $name );
159             }
160             else {
161             # List both if neither or both options specified
162 0 0 0     0 push @names, sort $rulestore->list_conds if !$opts->{actions} or $opts->{conds};
163 0 0 0     0 push @names, sort $rulestore->list_actions if !$opts->{conds} or $opts->{actions};
164             }
165              
166 0         0 for my $name ( @names ) {
167 0 0       0 if( my $attrs = eval { $rulestore->describe_cond( $name ) } ) {
  0 0       0  
168 0   0     0 my $description = $attrs->{desc} || "[has no description]";
169 0         0 $cinv->respond( "Condition '$name': $description" );
170 0 0       0 $cinv->respond( " $name($attrs->{format})" ) if defined $attrs->{format};
171             }
172 0         0 elsif( $attrs = eval { $rulestore->describe_action( $name ) } ) {
173 0   0     0 my $description = $attrs->{desc} || "[has no description]";
174 0         0 $cinv->respond( "Action '$name': $description" );
175 0 0       0 $cinv->respond( " $name($attrs->{format})" ) if defined $attrs->{format};
176             }
177             else {
178 0         0 $cinv->responderr( "No such condition or action '$name'" );
179             }
180             }
181              
182 0         0 return;
183 4     4   1336 }
  4         8  
  4         24  
184              
185 4     4   389 use Class::Method::Modifiers qw( install_modifier );
  4         9  
  4         1024  
186             sub APPLY_Ruleable
187             {
188 8     8 0 26 my $caller = caller;
189              
190             install_modifier $caller, after => load_configuration => sub {
191 0     0   0 my $self = shift;
192 0         0 my ( $ynode ) = @_;
193              
194 0 0       0 return unless my $rules_ynode = $ynode->{rules};
195 0         0 my $rulestore = $self->{rulestore};
196              
197 0         0 foreach my $chain ( keys %$rules_ynode ) {
198 0         0 my $chain_ynode = $rules_ynode->{$chain};
199 0         0 my $chain = $rulestore->new_chain( $chain ); # or fetch the existing one
200 0         0 $chain->clear;
201 0         0 $chain->append_rule( $_ ) for @$chain_ynode;
202             }
203 8         58 };
204              
205             install_modifier $caller, after => store_configuration => sub {
206 0     0     my $self = shift;
207 0           my ( $ynode ) = @_;
208              
209 0           my $rulestore = $self->{rulestore};
210 0   0       my $rules_ynode = $ynode->{rules} ||= YAML::Node->new({});
211              
212 0           foreach my $chain ( $rulestore->chains ) {
213 0           my $chain_ynode = $rules_ynode->{$chain} = [
214             $rulestore->get_chain( $chain )->deparse_rules(),
215             ];
216             }
217              
218             # Delete any of the old ones
219 0   0       $rulestore->get_chain( $_ ) or delete $rules_ynode->{$_} for keys %$rules_ynode;
220 8         1037 };
221             }
222              
223             0x55AA;