File Coverage

blib/lib/Circle/Ruleable.pm
Criterion Covered Total %
statement 36 119 30.2
branch 0 26 0.0
condition 0 16 0.0
subroutine 12 23 52.1
pod 0 10 0.0
total 48 194 24.7


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