File Coverage

blib/lib/Brannigan/Validations.pm
Criterion Covered Total %
statement 82 95 86.3
branch 14 26 53.8
condition 28 35 80.0
subroutine 26 27 96.3
pod 24 24 100.0
total 174 207 84.0


line stmt bran cond sub pod time code
1             package Brannigan::Validations;
2              
3             our $VERSION = "1.100001";
4             $VERSION = eval $VERSION;
5              
6 4     4   13901 use strict;
  4         5  
  4         93  
7 4     4   12 use warnings;
  4         4  
  4         3946  
8              
9             =head1 NAME
10              
11             Brannigan::Validations - Built-in validation methods for Brannigan.
12              
13             =head1 DESCRIPTION
14              
15             This module contains all built-in validation methods provided natively
16             by the L input validation/parsing system.
17              
18             =head1 GENERAL PURPOSE VALIDATION METHOD
19              
20             All these methods receive the value of a parameter, and other values
21             that explicilty define the requirements. They return a true value if the
22             parameter's value passed the test, or a false value otherwise.
23              
24             =head2 required( $value, $boolean )
25              
26             If C<$boolean> has a true value, this method will check that a required
27             parameter was indeed provided; otherwise (i.e. if C<$boolean> is not true)
28             this method will simply return a true value to indicate success.
29              
30             You should note that if a parameter is required, and a non-true value is
31             received (i.e. 0 or the empty string ""), this method considers the
32             requirement as fulfilled (i.e. it will return true). If you need to make sure
33             your parameters receive true values, take a look at the C validation
34             method.
35              
36             Please note that if a parameter is not required and indeed isn't provided
37             with the input parameters, any other validation methods defined on the
38             parameter will not be checked.
39              
40             =cut
41              
42             sub required {
43 91     91 1 73246 my ($class, $value, $boolean) = @_;
44              
45 91   100     406 return !$boolean || defined $value;
46             }
47              
48             =head2 forbidden( $value, $boolean )
49              
50             If C<$boolean> has a true value, this method will check that a forbidden
51             parameter was indeed NOT provided; otherwise (i.e. if C<$boolean> has a
52             false value), this method will do nothing and simply return true.
53              
54             =cut
55              
56             sub forbidden {
57 2     2 1 5 my ($class, $value, $boolean) = @_;
58              
59 2   66     19 return !$boolean || !defined $value;
60             }
61              
62             =head2 is_true( $value, $boolean )
63              
64             If C<$boolean> has a true value, this method will check that C<$value>
65             has a true value (so, C<$value> cannot be 0 or the empty string); otherwise
66             (i.e. if C<$boolean> has a false value), this method does nothing and
67             simply returns true.
68              
69             =cut
70              
71             sub is_true {
72 5     5 1 8 my ($class, $value, $boolean) = @_;
73              
74 5   100     27 return !$boolean || $value;
75             }
76              
77             =head2 length_between( $value, $min_length, $max_length )
78              
79             Makes sure the value's length (stringwise) is inside the range of
80             C<$min_length>-C<$max_length>, or, if the value is an array reference,
81             makes sure it has between C<$min_length> and C<$max_length> items.
82              
83             =cut
84              
85             sub length_between {
86 25     25 1 29 my ($class, $value, $min, $max) = @_;
87              
88 25   100     41 return $class->min_length($value, $min) && $class->max_length($value, $max);
89             }
90              
91             =head2 min_length( $value, $min_length )
92              
93             Makes sure the value's length (stringwise) is at least C<$min_length>, or,
94             if the value is an array reference, makes sure it has at least C<$min_length>
95             items.
96              
97             =cut
98              
99             sub min_length {
100 39     39 1 41 my ($class, $value, $min) = @_;
101              
102 39         48 return _length($value) >= $min;
103             }
104              
105             =head2 max_length( $value, $max_length )
106              
107             Makes sure the value's length (stringwise) is no more than C<$max_length>,
108             or, if the value is an array reference, makes sure it has no more than
109             C<$max_length> items.
110              
111             =cut
112              
113             sub max_length {
114 33     33 1 33 my ($class, $value, $max) = @_;
115              
116 33         43 return _length($value) <= $max;
117             }
118              
119             =head2 exact_length( $value, $length )
120              
121             Makes sure the value's length (stringwise) is exactly C<$length>, or,
122             if the value is an array reference, makes sure it has exactly C<$exact_length>
123             items.
124              
125             =cut
126              
127             sub exact_length {
128 2     2 1 3 my ($class, $value, $exlength) = @_;
129              
130 2         4 return _length($value) == $exlength;
131             }
132              
133             =head2 integer( $value, $boolean )
134              
135             If boolean is true, makes sure the value is an integer.
136              
137             =cut
138              
139             sub integer {
140 28     28 1 44 my ($class, $value, $boolean) = @_;
141              
142 28   66     204 return !$boolean || $value =~ m/^\d+$/;
143             }
144              
145             =head2 value_between( $value, $min_value, $max_value )
146              
147             Makes sure the value is between C<$min_value> and C<$max_value>.
148              
149             =cut
150              
151             sub value_between {
152 45     45 1 50 my ($class, $value, $min, $max) = @_;
153              
154 45   100     309 return defined $value && $value >= $min && $value <= $max;
155             }
156              
157             =head2 min_value( $value, $min_value )
158              
159             Makes sure the value is at least C<$min_value>.
160              
161             =cut
162              
163             sub min_value {
164 3     3 1 5 my ($class, $value, $min) = @_;
165              
166 3   66     20 return defined $value && $value >= $min;
167             }
168              
169             =head2 max_value( $value, $max )
170              
171             Makes sure the value is no more than C<$max_value>.
172              
173             =cut
174              
175             sub max_value {
176 3     3 1 6 my ($class, $value, $max) = @_;
177              
178 3   66     21 return defined $value && $value <= $max;
179             }
180              
181             =head2 array( $value, $boolean )
182              
183             If C<$boolean> is true, makes sure the value is actually an array reference.
184              
185             =cut
186              
187             sub array {
188 12     12 1 14 my ($class, $value, $boolean) = @_;
189              
190 12 100       67 $boolean ? ref $value eq 'ARRAY' ? 1 : return : ref $value eq 'ARRAY' ? return : 1;
    0          
    50          
191             }
192              
193             =head2 hash( $value, $boolean )
194              
195             If C<$boolean> is true, makes sure the value is actually a hash reference.
196              
197             =cut
198              
199             sub hash {
200 32     32 1 35 my ($class, $value, $boolean) = @_;
201              
202 32 100       124 $boolean ? ref $value eq 'HASH' ? 1 : return : ref $value eq 'HASH' ? return : 1;
    0          
    50          
203             }
204              
205             =head2 one_of( $value, @values )
206              
207             Makes sure a parameter's value is one of the provided acceptable values.
208              
209             =cut
210              
211             sub one_of {
212 8     8 1 18 my ($class, $value, @values) = @_;
213              
214 8         12 foreach (@values) {
215 18 100       47 return 1 if $value eq $_;
216             }
217              
218 4         19 return;
219             }
220              
221             =head2 matches( $value, $regex )
222              
223             Returns true if C<$value> matches the regular express (C) provided.
224             Will return false if C<$regex> is not a regular expression.
225              
226             =cut
227              
228             sub matches {
229 3     3 1 6 my ($class, $value, $regex) = @_;
230              
231 3   66     34 return ref $regex eq 'Regexp' && $value =~ $regex;
232             }
233              
234             =head1 USEFUL PASSPHRASE VALIDATION METHODS
235              
236             The following validations are useful for passphrase strength validations:
237              
238             =head2 min_alpha( $value, $integer )
239              
240             Returns a true value if C<$value> is a string that has at least C<$integer>
241             alphabetic (C and C) characters.
242              
243             =cut
244              
245             sub min_alpha {
246 3     3 1 7 my ($class, $value, $integer) = @_;
247              
248 3         15 my @matches = ($value =~ m/[A-Za-z]/g);
249              
250 3         11 return scalar @matches >= $integer;
251             }
252              
253             =head2 max_alpha( $value, $integer )
254              
255             Returns a true value if C<$value> is a string that has at most C<$integer>
256             alphabetic (C and C) characters.
257              
258             =cut
259              
260             sub max_alpha {
261 3     3 1 4 my ($class, $value, $integer) = @_;
262              
263 3         13 my @matches = ($value =~ m/[A-Za-z]/g);
264              
265 3         13 return scalar @matches <= $integer;
266             }
267              
268             =head2 min_digits( $value, $integer )
269              
270             Returns a true value if C<$value> is a string that has at least
271             C<$integer> digits (C<0-9>).
272              
273             =cut
274              
275             sub min_digits {
276 3     3 1 5 my ($class, $value, $integer) = @_;
277              
278 3         13 my @matches = ($value =~ m/[0-9]/g);
279              
280 3         18 return scalar @matches >= $integer;
281             }
282              
283             =head2 max_digits( $value, $integer )
284              
285             Returns a true value if C<$value> is a string that has at most
286             C<$integer> digits (C<0-9>).
287              
288             =cut
289              
290             sub max_digits {
291 3     3 1 5 my ($class, $value, $integer) = @_;
292              
293 3         11 my @matches = ($value =~ m/[0-9]/g);
294              
295 3         10 return scalar @matches <= $integer;
296             }
297              
298             =head2 min_signs( $value, $integer )
299              
300             Returns a true value if C<$value> has at least C<$integer> special or
301             sign characters (e.g. C<%^&!@#>, or basically anything that isn't C).
302              
303             =cut
304              
305             sub min_signs {
306 3     3 1 4 my ($class, $value, $integer) = @_;
307              
308 3         12 my @matches = ($value =~ m/[^A-Za-z0-9]/g);
309              
310 3         10 return scalar @matches >= $integer;
311             }
312              
313             =head2 max_signs( $value, $integer )
314              
315             Returns a true value if C<$value> has at most C<$integer> special or
316             sign characters (e.g. C<%^&!@#>, or basically anything that isn't C).
317              
318             =cut
319              
320             sub max_signs {
321 3     3 1 5 my ($class, $value, $integer) = @_;
322              
323 3         11 my @matches = ($value =~ m/[^A-Za-z0-9]/g);
324              
325 3         11 return scalar @matches <= $integer;
326             }
327              
328             =head2 max_consec( $value, $integer )
329              
330             Returns a true value if C<$value> does not have a sequence of consecutive
331             characters longer than C<$integer>. Consequtive characters are either
332             alphabetic (e.g. C) or numeric (e.g. C<1234>).
333              
334             =cut
335              
336             sub max_consec {
337 6     6 1 8 my ($class, $value, $integer) = @_;
338              
339             # the idea here is to break the string intoto an array of characters,
340             # go over each character in the array, starting at the first one,
341             # and making sure that character does not begin a sequence longer
342             # than allowed ($integer). This means we have recursive loops here,
343             # because for every character, we compare it to the following character
344             # and while they form a sequence, we move to the next pair and compare
345             # them until the sequence is broken. To make it a tad faster, our
346             # outer loop won't go over the entire characters array, but only
347             # up to the last character that might possibly form an invalid
348             # sequence. This character would be positioned $integer+1 characters
349             # from the end.
350              
351 6         16 my @chars = split(//, $value);
352 6         20 for (my $i = 0; $i <= scalar(@chars) - $integer - 1; $i++) {
353 18         12 my $fc = $i; # first character for comparison
354 18         13 my $sc = $i + 1; # second character for comparison
355 18         9 my $sl = 1; # sequence length
356 18   100     64 while ($sc <= $#chars && ord($chars[$sc]) - ord($chars[$fc]) == 1) {
357             # characters are in sequence, increase counters
358             # and compare next pair
359 6         4 $sl++;
360 6         5 $fc++;
361 6         14 $sc++;
362             }
363 18 100       49 return if $sl > $integer;
364             }
365              
366 4         13 return 1;
367             }
368              
369             =head2 max_reps( $value, $integer )
370              
371             Returns a true value if C<$value> does not contain a sequence of a repeated
372             character longer than C<$integer>. So, for example, if C<$integer> is 3,
373             then "aaa901" will return true (even though there's a repetition of the
374             'a' character it is not longer than three), while "9bbbb01" will return
375             false.
376              
377             =cut
378              
379             sub max_reps {
380 6     6 1 9 my ($class, $value, $integer) = @_;
381              
382             # the idea here is pretty much the same as in max_consec but
383             # we truely compare each pair of characters
384              
385 6         16 my @chars = split(//, $value);
386 6         17 for (my $i = 0; $i <= scalar(@chars) - $integer - 1; $i++) {
387 18         11 my $fc = $i; # first character for comparison
388 18         15 my $sc = $i + 1; # second character for comparison
389 18         11 my $sl = 1; # sequence length
390 18   100     66 while ($sc <= $#chars && $chars[$sc] eq $chars[$fc]) {
391             # characters are in sequence, increase counters
392             # and compare next pair
393 6         3 $sl++;
394 6         4 $fc++;
395 6         15 $sc++;
396             }
397 18 100       42 return if $sl > $integer;
398             }
399              
400 4         18 return 1;
401             }
402              
403             =head2 max_dict( $value, $integer, [ \@dict_files ] )
404              
405             Returns a true value if C<$value> does not contain a dictionary word
406             longer than C<$integer>. By default, this method will look for the Unix
407             dict files C, C and C.
408             You can supply more dictionary files to look for with an array reference
409             of full paths.
410              
411             So, for example, if C<$integer> is 3, then "a9dog51" will return true
412             (even though "dog" is a dictionary word, it is not longer than three),
413             but "a9punk51" will return false, as "punk" is longer.
414              
415             WARNING: this method is known to not work properly when used in certain
416             environments such as C, I'm investigating the issue.
417              
418             =cut
419              
420             sub max_dict {
421 0     0 1 0 my ($class, $value, $integer, $dict_files) = @_;
422              
423             # the following code was stolen from the CheckDict function of
424             # Data::Password by Ariel Brosh (RIP) and Oded S. Resnik
425              
426 0   0     0 $dict_files ||= [];
427 0         0 unshift(@$dict_files, qw!/usr/dict/words /usr/share/dict/words /usr/share/dict/linux.words!);
428              
429 0         0 foreach (@$dict_files) {
430 0 0       0 open (DICT, $_) || next;
431 0         0 while (my $dict_line = ) {
432 0         0 chomp $dict_line;
433 0 0       0 next if length($dict_line) <= $integer;
434 0 0       0 if (index(lc($value), lc($dict_line)) > -1) {
435 0         0 close(DICT);
436 0         0 return;
437             }
438             }
439 0         0 close(DICT);
440             }
441              
442 0         0 return 1;
443             }
444              
445             ####################
446             # INTERNAL METHODS #
447             ####################
448              
449             sub _length {
450 74 100   74   313 return ref $_[0] eq 'ARRAY' ? scalar(@{$_[0]}) : length($_[0]);
  16         67  
451             }
452              
453             =head1 SEE ALSO
454              
455             L, L.
456              
457             =head1 AUTHOR
458              
459             Ido Perlmuter, C<< >>
460              
461             =head1 BUGS
462              
463             Please report any bugs or feature requests to C, or through
464             the web interface at L. I will be notified, and then you'll
465             automatically be notified of progress on your bug as I make changes.
466              
467             =head1 SUPPORT
468              
469             You can find documentation for this module with the perldoc command.
470              
471             perldoc Brannigan::Validations
472              
473             You can also look for information at:
474              
475             =over 4
476              
477             =item * RT: CPAN's request tracker
478              
479             L
480              
481             =item * AnnoCPAN: Annotated CPAN documentation
482              
483             L
484              
485             =item * CPAN Ratings
486              
487             L
488              
489             =item * Search CPAN
490              
491             L
492              
493             =back
494              
495             =head1 LICENSE AND COPYRIGHT
496              
497             Copyright 2017 Ido Perlmuter
498              
499             Licensed under the Apache License, Version 2.0 (the "License");
500             you may not use this file except in compliance with the License.
501             You may obtain a copy of the License at
502              
503             http://www.apache.org/licenses/LICENSE-2.0
504              
505             Unless required by applicable law or agreed to in writing, software
506             distributed under the License is distributed on an "AS IS" BASIS,
507             WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
508             See the License for the specific language governing permissions and
509             limitations under the License.
510              
511             =cut
512              
513             1;