File Coverage

blib/lib/Brannigan/Validations.pm
Criterion Covered Total %
statement 88 101 87.1
branch 58 74 78.3
condition 25 32 78.1
subroutine 25 26 96.1
pod 24 24 100.0
total 220 257 85.6


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