File Coverage

blib/lib/IO/Iron/PolicyBase.pm
Criterion Covered Total %
statement 169 194 87.1
branch 21 32 65.6
condition 10 15 66.6
subroutine 24 25 96.0
pod 5 5 100.0
total 229 271 84.5


line stmt bran cond sub pod time code
1             package IO::Iron::PolicyBase;
2              
3             ## no critic (Documentation::RequirePodAtEnd)
4             ## no critic (Documentation::RequirePodSections)
5             ## no critic (Subroutines::RequireArgUnpacking)
6              
7 6     6   3080 use 5.010_000;
  6         36  
8 6     6   33 use strict;
  6         16  
  6         144  
9 6     6   29 use warnings;
  6         14  
  6         175  
10              
11             # Global creator
12       6     BEGIN {
13             # Inherit nothing
14             }
15              
16             # Global destructor
17       6     END {
18             }
19              
20              
21             # ABSTRACT: Base package (inherited) for IO::Iron::IronMQ/Cache/Worker::Policy packages.
22              
23             our $VERSION = '0.12_01'; # TRIAL VERSION: generated by DZP::OurPkgVersion
24              
25              
26 6     6   46 use Log::Any qw{$log};
  6         11  
  6         44  
27 6     6   1573 use Hash::Util 0.06 qw{lock_keys unlock_keys};
  6         164  
  6         40  
28 6     6   474 use Carp::Assert;
  6         14  
  6         46  
29 6     6   842 use Carp::Assert::More;
  6         17  
  6         1003  
30 6     6   66 use English '-no_match_vars';
  6         15  
  6         45  
31 6     6   2219 use File::Spec ();
  6         13  
  6         181  
32 6     6   2280 use Params::Validate qw(:all);
  6         36583  
  6         1217  
33             use Exception::Class (
34 6         66 'IronPolicyException' => {
35             fields => ['policy', 'candidate'],
36             },
37             'NoIronPolicyException' => {
38             fields => [],
39             },
40             'CharacterGroupNotDefinedIronPolicyException' => {
41             fields => [],
42             }
43 6     6   3062 );
  6         52077  
44              
45 6     6   7046 use IO::Iron::Common ();
  6         18  
  6         127  
46 6     6   2821 use IO::Iron::PolicyBase::CharacterGroup ();
  6         18  
  6         13932  
47              
48              
49             # INTERNAL METHODS
50             # For use in the inheriting subclass
51              
52              
53             # TODO policy character set, list possible alternatives:
54             sub IRON_CLIENT_DEFAULT_POLICIES {
55 2     2 1 43 my %default_policies =
56             (
57             'definition' => {
58             'character_set' => 'ascii', # The only supported character set!
59             'character_group' => {
60             },
61             'no_limitation' => 1, # There is an unlimited number of alternatives.
62             },
63             'queue' => { 'name' => [ '[:word:]{1,}' ], },
64             'cache' => { 'name' => [ '[:word:]{1,}' ], 'item_key' => [ '[:word:]{1,}' ]},
65             'worker' => { 'name' => [ '[:word:]{1,}' ], },
66             );
67 2         15 return %default_policies;
68             }
69              
70             sub _do_alt {
71 618     618   973 my $self = shift;
72 618         8789 my %params = validate(
73             @_, {
74             'str' => { type => SCALAR, }, # name/key name.
75             }
76             );
77 618         2418 my $str = $params{'str'};
78 618         1919 $log->tracef('Entering _do_alt(%s)', $str);
79 618         45065 assert(length $str > 0, 'String length > 0.');
80 618         2676 my @processed_alts;
81 618 100 100     5710 if( $str =~ /^([[:graph:]]*)(\[:[[:graph:]]+:\]\{[[:digit:]]+\,[[:digit:]]+\})([[:graph:]]*)$/sx
      100        
82             || ($str =~ /^([[:graph:]]*)(\[:[[:graph:]]+:\]\{([[:digit:]]+)\})([[:graph:]]*)$/sx && $3 > 1)
83             ) {
84 12         61 $log->tracef('We need to do recursion.', $str);
85 12         854 my $preceeding_part = $1;
86 12         41 my $group_part = $2;
87 12 100       47 my $succeeding_part = defined $4 ? $4 : $3;
88 12         44 $log->tracef('$preceeding_part=%s;$group_part=%s;$succeeding_part=%s;',
89             $preceeding_part, $group_part, $succeeding_part);
90 12         996 my @alternatives = _make_ones($preceeding_part, $group_part, $succeeding_part);
91 12         53 foreach (@alternatives) {
92 13         48 push @processed_alts, $self->_do_alt('str' => $_);
93             }
94             }
95             else {
96 606         1831 $log->tracef('We need to create the alternatives.', $str);
97 606 100       42755 if( $str =~ /^([[:graph:]]*)(\[:[[:graph:]]+:\]\{1\})([[:graph:]]*)$/sx ) {
98 238         385 my @alts;
99 238         554 my $preceeding_part = $1;
100 238         486 my $group_part = $2;
101 238         411 my $succeeding_part = $3;
102 238         689 $log->tracef('$preceeding_part=%s;$group_part=%s;$succeeding_part=%s;',
103             $preceeding_part, $group_part, $succeeding_part);
104 238 50       19266 if($group_part =~ /^(\[:[[:graph:]]+:\])\{([[:digit:]]+)\}$/sx) {
105 238         507 my $group = $1;
106 238         433 my $lowest_amount = $2;
107 238         438 my $highest_amount = $3;
108 238         673 $log->tracef('$group=%s;$lowest_amount=%s;$highest_amount=%s;',
109             $group, $lowest_amount, $highest_amount);
110 238         17824 foreach ($self->_get_character_group_alternatives('character_group' => $group)) {
111 602         2040 push @alts, $preceeding_part . $_ . $succeeding_part;
112             }
113             }
114 238         799 $log->tracef('@alts=%s;', \@alts);
115 238         58515 foreach (@alts) {
116 602         1714 push @processed_alts, $self->_do_alt('str' => $_);
117             }
118             }
119             else {
120 368         726 push @processed_alts, $str;
121             }
122             }
123 618         1762 $log->tracef('Exiting _do_alt():%s', \@processed_alts);
124 618         148248 return @processed_alts;
125             }
126              
127             sub _make_ones {
128 12     12   26 my $preceeding_part = $_[0];
129 12         22 my $group_part = $_[1];
130 12         25 my $succeeding_part = $_[2];
131 12         45 $log->tracef('_make_ones():$preceeding_part=%s;$group_part=%s;$succeeding_part=%s;',
132             $preceeding_part, $group_part, $succeeding_part);
133 12         907 $log->tracef('$group_part=%s;', $group_part);
134 12         788 my @alternatives;
135 12 100       120 if($group_part =~ /^(\[:[[:graph:]]+:\])\{([[:digit:]]+)\,([[:digit:]]+)\}$/msx) {
    50          
136 1         3 my $group = $1;
137 1         5 my $lowest_amount = $2;
138 1         3 my $highest_amount = $3;
139 1         5 $log->tracef('$group=%s;$lowest_amount=%s;$highest_amount=%s;',
140             $group, $lowest_amount, $highest_amount);
141 1         81 for($lowest_amount..$highest_amount) {
142 2         5 my $group_str = $group . '{1}';
143 2         9 push @alternatives, $preceeding_part . $group_str x $_ . $succeeding_part;
144             }
145             }
146             elsif($group_part =~ /^(\[:[[:graph:]]+:\])\{([[:digit:]]+)\}$/msx) {
147 11         32 my $group = $1;
148 11         29 my $lowest_amount = $2;
149 11         23 my $highest_amount = $2;
150 11         41 $log->tracef('$group=%s;$lowest_amount=%s;$highest_amount=%s;',
151             $group, $lowest_amount, $highest_amount);
152 11         888 for(my $i = $lowest_amount; $i < $highest_amount + 1; $i++) {
153 11         24 my $group_str = $group . '{1}';
154 11         74 push @alternatives, $preceeding_part . $group_str x $i . $succeeding_part;
155             }
156             }
157             else {
158 0         0 $log->fatalf('Illegal string \'%s\'.', $group_part);
159             }
160 12         49 $log->tracef('@alternatives=%s;', \@alternatives);
161 12         2810 return @alternatives;
162             }
163              
164             sub _get_character_group_alternatives {
165 254     254   397 my $self = shift;
166 254         4480 my %params = validate(
167             @_, {
168             'character_group' => { type => SCALAR, regex => qr/^[[:graph:]]+$/msx, }, # name/key name.
169             'keep_posix_group' => { type => BOOLEAN, optional => 1, }, # Keep POSIX (subset) group name and return it.
170             },
171             );
172 254         4616 my $chars;
173              
174             # Predefined groups (subset of POSIX) first!
175             $chars = IO::Iron::PolicyBase::CharacterGroup::group(
176 254         871 'character_group' => $params{'character_group'});
177 254 100 100     669 if($chars && $params{'keep_posix_group'}) {
178 16         33 $chars = $params{'character_group'}; # Put the group name back.
179             }
180 254 100       522 if(!$chars) {
181             $chars = $self->{'policy'}->{'definition'}->{'character_group'}
182 237         738 ->{$params{'character_group'}};
183             }
184 254 50       516 if($chars) {
185 254         639 $log->tracef('$chars=%s;', $chars);
186             }
187             else {
188 0         0 $log->fatalf('Character group \'%s\' not defined.', $params{'character_group'});
189             CharacterGroupNotDefinedIronPolicyException->throw(
190 0         0 error => 'CharacterGroupNotDefinedIronPolicyException: Character group \'' . $params{'character_group'} . '\' not defined!',
191             );
192             }
193 254         18066 return split //msx, $chars;
194             }
195              
196              
197             sub alternatives {
198 3     3 1 8 my $self = shift;
199 3         56 my %params = validate(
200             @_, {
201             'required_policy' => { type => SCALAR, }, # name/key name.
202             }
203             );
204 3         30 assert_hashref( $self->{'policy'}, 'self->{required_policy} is a reference to a list.');
205 3         87 $log->tracef('Entering alternatives(%s)', \%params);
206              
207 3 50 33     733 if(defined $self->{'policy'}->{'definition'}->{'no_limitation'} &&
208             $self->{'policy'}->{'definition'}->{'no_limitation'} == 1) {
209 0         0 NoIronPolicyException->throw(
210             error => 'NoIronPolicyException: Cannot list alternatives, unlimited number!',
211             );
212             }
213 3         14 my $templates = $self->{'policy'}->{$params{'required_policy'}};
214 3         14 assert_listref($templates, 'templates is a reference to a list');
215 3         62 my @template_alternatives;
216 3         8 foreach (@{$templates}) {
  3         10  
217 3         48 $log->tracef('alternatives(): Template:\"%s\".)', $_);
218 3         241 push @template_alternatives, $self->_do_alt('str' => $_);
219             }
220 3         17 $log->tracef('Exiting alternatives():%s', \@template_alternatives);
221 3         1296 return @template_alternatives;
222             }
223              
224             sub _get_chars_or_remain_posix_group {
225 16     16   34 my $self = shift;
226 16         50 $log->tracef('Entering _get_chars_or_remain_posix_group(%s)', \@_);
227 16         3652 my $group = $_[0];
228 16         55 $log->tracef('_get_chars_or_remain_posix_group(): Ask for Group alternatives for :%s', $group);
229 16         1088 my @chars = $self->_get_character_group_alternatives('character_group' => $group, 'keep_posix_group' => 1);
230 16         52 $log->tracef('_get_chars_or_remain_posix_group(): Group alternatives:%s', \@chars);
231 16         4018 my $group_chars = join q{}, @chars;
232 16         56 $log->tracef('Exiting _get_chars_or_remain_posix_group():%s', ('[' . $group_chars . ']') );
233 16         1111 return '[' . $group_chars . ']';
234             }
235              
236             sub _convert_policy_to_normal_regexp {
237 22     22   34 my $self = shift;
238 22         76 $log->tracef('Entering _convert_policy_to_normal_regexp(%s)', \@_);
239 22         5040 my $policy_regexp = $_[0];
240 22         137 $policy_regexp =~ s/(\[:[[:graph:]]+?:\])/$self->_get_chars_or_remain_posix_group($1)/egsx;
  16         56  
241 22         73 $log->tracef('Exiting _convert_policy_to_normal_regexp():%s', $policy_regexp);
242 22         1516 return $policy_regexp;
243             }
244              
245              
246             sub is_valid_policy {
247 0     0 1 0 my $self = shift;
248 0         0 my %params = validate(
249             @_, {
250             'policy' => { type => SCALAR, }, # name/key name.
251             'candidate' => { type => SCALAR, }, # string to check.
252             }
253             );
254 0         0 assert_listref( $self->{'policy'}, 'self->{policy} is a reference to a list.');
255 0         0 $log->tracef('Entering is_valid_policy(%s)', \%params);
256              
257 0         0 my $validity = 0;
258 0 0 0     0 if(defined $self->{'policy'}->{'definition'}->{'no_limitation'}
259             && $self->{'policy'}->{'definition'}->{'no_limitation'} == 1) {
260 0         0 $log->trace('is_valid_policy', 'no_limitation: no policy check!');
261 0         0 $validity = 1;
262             }
263             else {
264 0         0 my $templates = $self->{'policy'}->{$params{'policy'}};
265 0         0 assert_listref($templates, "templates is a reference to a list");
266 0         0 foreach (@{$templates}) {
  0         0  
267 0         0 $log->tracef('is_valid_policy(): Going to comparing with raw template:\"%s\".)', $_);
268 0         0 my $template = $self->_convert_policy_to_normal_regexp($_);
269 0         0 $log->tracef('is_valid_policy(): Comparing with template:\"%s\".)', $template);
270 0 0       0 if($params{'candidate'} =~ /^$template$/xgsm) {
271 0         0 $validity = 1;
272 0         0 last;
273             }
274             }
275             }
276 0         0 $log->tracef('Exiting is_valid_policy():%d', $validity);
277 0         0 return $validity;
278             }
279              
280             # This method throws an exception of type IronPolicyException.
281              
282              
283             sub validate_with_policy {
284 9     9 1 19 my $self = shift;
285 9         170 my %params = validate(
286             @_, {
287             'policy' => { type => SCALAR, }, # name/key name.
288             'candidate' => { type => SCALAR, }, # string to check.
289             }
290             );
291 9         70 assert_hashref( $self->{'policy'}, 'self->{policy} is a reference to a hash.');
292 9         187 $log->tracef('Entering validate_with_policy(%s)', \%params);
293 9         2115 my $validity = 0;
294 9         30 my $templates = $self->{'policy'}->{$params{'policy'}};
295 9         29 assert_listref($templates, 'templates is a reference to a list');
296 9         157 foreach (@{$templates}) {
  9         25  
297 22         82 my $template = $self->_convert_policy_to_normal_regexp($_);
298 22         61 $log->tracef('validate_with_policy(): Comparing with template:\"%s\".)', $template);
299 22 100       1966 if($params{'candidate'} =~ /^$template$/xgsm) {
300 4         11 $validity = 1;
301 4         11 last;
302             }
303             }
304 9 100       33 if($validity == 0) {
305 5         45 $log->tracef('Throwing exception in validate_with_policy(): policy=%s, candidate=%s', $params{'policy'}, $params{'candidate'});
306             IronPolicyException->throw(
307             policy => $params{'policy'},
308             candidate => $params{'candidate'},
309             error => 'IronPolicyException: policy=' . $params{'policy'}
310 5         414 . ' candidate=' . $params{'candidate'},
311             );
312             }
313 4         15 $log->tracef('Exiting validate_with_policy():%d', $validity);
314 4         295 return $validity;
315             }
316              
317              
318             sub get_policies { ## no critic (Subroutines::RequireArgUnpacking)
319 2     2 1 5 my $self = shift;
320 2         37 my %params = validate(
321             @_, {
322             'policies' => { type => SCALAR|UNDEF, optional => 0, },
323             }
324             );
325 2         36 $log->tracef('Entering get_policies(%s)', \%params);
326 2         508 my %all_policies = IRON_CLIENT_DEFAULT_POLICIES(); ## Preset default policies.
327 2         11 $log->tracef('Default policies: %s', \%all_policies);
328 2 50       634 if(defined $params{'policies'}) { # policies file specified when creating the object, if given.
329             IO::Iron::Common::_read_iron_config_file(\%all_policies,
330             File::Spec->file_name_is_absolute($params{'policies'})
331 0 0       0 ? $params{'policies'} : File::Spec->catfile(File::Spec->curdir(), $params{'policies'})
332             );
333             }
334 2         5 my %policies = %{$all_policies{$self->_THIS_POLICY()}};
  2         16  
335 2         5 $policies{'definition'} = $all_policies{'definition'};
336 2         8 $log->tracef('Exiting get_policies: %s', \%policies);
337 2         900 return \%policies;
338             }
339              
340             1;
341              
342             __END__