File Coverage

blib/lib/Data/FormValidator/Constraints/MethodsFactory.pm
Criterion Covered Total %
statement 83 83 100.0
branch 22 22 100.0
condition 5 6 83.3
subroutine 29 29 100.0
pod 12 12 100.0
total 151 152 99.3


line stmt bran cond sub pod time code
1             package Data::FormValidator::Constraints::MethodsFactory;
2              
3             ###############################################################################
4             # Required inclusions.
5             ###############################################################################
6 3     3   374287 use strict;
  3         65  
  3         97  
7 3     3   21 use warnings;
  3         7  
  3         153  
8              
9             ###############################################################################
10             # Version number.
11             ###############################################################################
12             our $VERSION = '0.03';
13              
14             ###############################################################################
15             # Allow our methods to be exported
16             ###############################################################################
17 3     3   22 use Exporter;
  3         6  
  3         129  
18 3     3   18 use base qw( Exporter );
  3         8  
  3         318  
19 3     3   23 use vars qw( @EXPORT_OK %EXPORT_TAGS );
  3         12  
  3         3305  
20             %EXPORT_TAGS = (
21             'set' => [qw( FV_set FV_set_num FV_set_word FV_set_cmp )],
22             'num' => [qw( FV_clamp FV_lt FV_gt FV_le FV_ge )],
23             'bool' => [qw( FV_not FV_or FV_and )],
24             );
25             @EXPORT_OK = map { @{$_} } values %EXPORT_TAGS;
26              
27             ###############################################################################
28             # Subroutine: FV_set($result, @set)
29             ###############################################################################
30             # Creates a constraint closure that will return the provided '$result' if the
31             # value is a member of the given '@set', or the negation of '$result'
32             # otherwise.
33             #
34             # The 'eq' operator is used for comparison.
35             ###############################################################################
36             sub FV_set {
37 10     10 1 1071 my ($result, @set) = @_;
38             return sub {
39 9     9   762 my $dfv = shift;
40 9         30 my $val = $dfv->get_current_constraint_value();
41 9         53 foreach my $elem (@set) {
42 15 100       46 return $result if ($val eq $elem);
43             }
44 5         16 return !$result;
45             }
46 10         68 }
47              
48             ###############################################################################
49             # Subroutine: FV_set_num($result, @set)
50             ###############################################################################
51             # Creates a constraint closure that will return the provided '$result' if the
52             # value is a member of the given '@set', or the negation of '$result'
53             # otherwise.
54             #
55             # The '==' operator is used for comparison.
56             ###############################################################################
57             sub FV_set_num {
58 2     2 1 886 my ($result, @set) = @_;
59             return sub {
60 2     2   504 my $dfv = shift;
61 2         8 my $val = $dfv->get_current_constraint_value();
62 2         15 foreach my $elem (@set) {
63 14 100       57 return $result if ($val == $elem);
64             }
65 1         4 return !$result;
66             }
67 2         13 }
68              
69             ###############################################################################
70             # Subroutine: FV_set_word($result, $set)
71             ###############################################################################
72             # Creates a constraint closure that will return the provided '$result' if the
73             # value is a word in the given '$set', or the negation of '$result' otherwise.
74             ###############################################################################
75             sub FV_set_word {
76 2     2 1 742 my ($result, $set) = @_;
77             return sub {
78 2     2   528 my $dfv = shift;
79 2         9 my $val = $dfv->get_current_constraint_value();
80 2 100       40 return ($set =~ /\b$val\b/i) ? $result : !$result;
81             }
82 2         13 }
83              
84             ###############################################################################
85             # Subroutine: FV_set_cmp($result, $cmp, @set)
86             ###############################################################################
87             # Creates a constraint closure that will return the provided '$result' if the
88             # value is a member of the given '@set', or the negation of '$result'
89             # otherwise.
90             #
91             # '$cmp' is a function which takes two arguments, and should return true if the
92             # two elements are considered equal, otherwise returning false.
93             ###############################################################################
94             sub FV_set_cmp {
95 2     2 1 693 my ($result, $cmp, @set) = @_;
96             return sub {
97 2     2   497 my $dfv = shift;
98 2         6 my $val = $dfv->get_current_constraint_value();
99 2         12 foreach my $elem (@set) {
100 5 100       22 return $result if ($cmp->($val,$elem));
101             }
102 1         6 return !$result;
103             }
104 2         18 }
105              
106             ###############################################################################
107             # Subroutine: FV_clamp($result, $low, $high)
108             ###############################################################################
109             # Creates a constraint closure that will return the provided '$result' if the
110             # value is numerically between the given '$low' and '$high' bounds, or the
111             # negation of '$result' otherwise.
112             ###############################################################################
113             sub FV_clamp {
114 3     3 1 105 my ($result, $low, $high) = @_;
115             return sub {
116 3     3   947 my $dfv = shift;
117 3         10 my $val = $dfv->get_current_constraint_value();
118 3 100 100     43 return (($val < $low) or ($val > $high)) ? !$result : $result;
119             }
120 3         29 }
121              
122             ###############################################################################
123             # Subroutine: FV_lt($result, $bound)
124             ###############################################################################
125             # Creates a constraint closure that will return the provided '$result' if the
126             # value is numerically less than the given '$bound', or the negation of
127             # '$result' otherwise.
128             ###############################################################################
129             sub FV_lt {
130 5     5 1 1168 my ($result, $bound) = @_;
131             return sub {
132 5     5   660 my $dfv = shift;
133 5         14 my $val = $dfv->get_current_constraint_value();
134 5 100       36 return ($val < $bound) ? $result : !$result;
135             }
136 5         26 }
137              
138             ###############################################################################
139             # Subroutine: FV_gt($result, $bound)
140             ###############################################################################
141             # Creates a constraint closure that will return the provided '$result' if the
142             # value is numerically greater than the given '$bound', or the negation of
143             # '$result' otherwise.
144             ###############################################################################
145             sub FV_gt {
146 5     5 1 2083 my ($result, $bound) = @_;
147             return sub {
148 5     5   625 my $dfv = shift;
149 5         17 my $val = $dfv->get_current_constraint_value();
150 5 100       35 return ($val > $bound) ? $result : !$result;
151             }
152 5         32 }
153              
154             ###############################################################################
155             # Subroutine: FV_le($result, $bound)
156             ###############################################################################
157             # Creates a constraint closure that will return the provided '$result' if the
158             # value is numerically less than or equal to the given '$bound', or the
159             # negation of '$result' otherwise.
160             ###############################################################################
161             sub FV_le {
162 3     3 1 1014 my ($result, $bound) = @_;
163             return sub {
164 3     3   627 my $dfv = shift;
165 3         8 my $val = $dfv->get_current_constraint_value();
166 3 100       21 return ($val <= $bound) ? $result : !$result;
167             }
168 3         59 }
169              
170             ###############################################################################
171             # Subroutine: FV_ge($result, $bound)
172             ###############################################################################
173             # Creates a constraint closure that will return the provided '$result' if the
174             # value is numerically greater than or equal to the given '$bound', or the
175             # negation of '$result' otherwise.
176             ###############################################################################
177             sub FV_ge {
178 3     3 1 1043 my ($result, $bound) = @_;
179             return sub {
180 3     3   620 my $dfv = shift;
181 3         9 my $val = $dfv->get_current_constraint_value();
182 3 100       29 return ($val >= $bound) ? $result : !$result;
183             }
184 3         19 }
185              
186             ###############################################################################
187             # Subroutine: FV_not($constraint)
188             ###############################################################################
189             # Creates a constraint closure that will return the negation of the result of
190             # the given '$constraint'.
191             ###############################################################################
192             sub FV_not {
193 2     2 1 5 my $constraint = shift;
194 2     2   19 return sub { !$constraint->(@_) };
  2         733  
195             }
196              
197             ###############################################################################
198             # Subroutine: FV_or(@constraints)
199             ###############################################################################
200             # Creates a constraint closure that will return the result of the first
201             # constraint that returns a non-false result.
202             ###############################################################################
203             sub FV_or {
204 3     3 1 8 my @closures = @_;
205             return sub {
206 3     3   631 foreach my $c (@closures) {
207 5         14 my $res = $c->(@_);
208 5 100       16 return $res if $res;
209             }
210 1         2 return;
211             }
212 3         19 }
213              
214             ###############################################################################
215             # Subroutine: FV_and(@constraints)
216             ###############################################################################
217             # Creates a constraint closure that will return the result of the first
218             # constraint to return a non-false result, -IF- ALL of the constraints return
219             # non-false results.
220             ###############################################################################
221             sub FV_and {
222 2     2 1 55 my @closures = @_;
223 2         5 my $results;
224             return sub {
225 2     2   515 foreach my $c (@closures) {
226 4         9 my $res = $c->(@_);
227 4 100       13 return $res if (!$res);
228 3   66     12 $results ||= $res;
229             }
230 1         3 return $results;
231             }
232 2         18 }
233              
234             1;
235              
236             =for stopwords MX num
237              
238             =head1 NAME
239              
240             Data::FormValidator::Constraints::MethodsFactory - Create constraints for Data::FormValidator
241              
242             =head1 SYNOPSIS
243              
244             use Data::FormValidator::Constraints::MethodsFactory qw(:set :num :bool);
245              
246             # SET constraints (:set)
247             constraint_methods => {
248             status => FV_set(1, qw(new active disabled)),
249             how_many => FV_set_num(1, (1 .. 20)),
250             province => FV_set_word(1, "AB QC ON TN NU"),
251             seen_before => FV_set_cmp(1, sub { $seen{ $_[0] } }, qw(foo bar)),
252             }
253              
254             # NUMERIC constraints (:num)
255             constraint_methods => {
256             how_many => FV_clamp(1, 1, 10),
257             small_amount => FV_lt(1, 3),
258             large_amount => FV_gt(1, 10),
259             small_again => FV_le(1, 3),
260             large_again => FV_ge(1, 10),
261             }
262              
263             # BOOLEAN constraints (:bool)
264             constraint_methods => {
265             # e.g. NOT in the given set
266             bad_status => FV_not(
267             FV_set(1, qw(new active disabled))
268             ),
269              
270             # e.g. either the current value, OR validates as an e-mail address
271             email => FV_or(
272             FV_set(1, $current_value),
273             Data::FormValidator::Constraints::email(),
274             ),
275              
276             # e.g. valid length, AND matches password validation routine
277             password => FV_and(
278             FV_length_between(6, 32),
279             my_password_validation_constraint(),
280             ),
281             }
282              
283             =head1 DESCRIPTION
284              
285             C provides a variety of
286             functions that can be used to generate constraint closures for use with
287             C.
288              
289             The functions/constraints provided are based on those from
290             C, B are designed to be used as
291             "new-style" constraints (while C was
292             designed for use with "old-style" constraints). Functionally, this module
293             provides equivalents for all of the constraints that were in
294             C, but if you're trying to do things
295             with the new-style you'll want to use the versions from this module instead.
296              
297             The constraints provided by this module are broken up into three main
298             categories/sections:
299              
300             =over
301              
302             =item Set constraints (:set)
303              
304             Constraint methods for working with "sets" of data. Useful for when you want
305             to check and make sure that the provided value is from a list of valid choices.
306              
307             The following constraints are exported via the C<:set> tag:
308              
309             FV_set
310             FV_set_num
311             FV_set_word
312             FV_set_cmp
313              
314             =item Numeric constraints (:num)
315              
316             Constraint methods for working with numbers. Useful when you want to check and
317             make sure that the provided value is within a specified range.
318              
319             The following constraints are exported via the C<:num> tag:
320              
321             FV_clamp
322             FV_lt
323             FV_gt
324             FV_le
325             FV_ge
326              
327             =item Boolean constraints (:bool)
328              
329             Constraint methods for working with boolean conditions. Useful when you want
330             to combine constraints together to create much more powerful constraints (e.g.
331             validating an e-mail address to make sure that it looks valid and has an
332             associated MX record, BUT only if the value actually changed from what we had
333             in the record previously).
334              
335             The following constraints are exported via the C<:bool> tag:
336              
337             FV_not
338             FV_or
339             FV_and
340              
341             =back
342              
343             =head1 METHODS
344              
345             =over
346              
347             =item FV_set($result, @set)
348              
349             Creates a constraint closure that will return the provided C<$result> if
350             the value is a member of the given C<@set>, or the negation of C<$result>
351             otherwise.
352              
353             The C operator is used for comparison.
354              
355             =item FV_set_num($result, @set)
356              
357             Creates a constraint closure that will return the provided C<$result> if
358             the value is a member of the given C<@set>, or the negation of C<$result>
359             otherwise.
360              
361             The C<==> operator is used for comparison.
362              
363             =item FV_set_word($result, $set)
364              
365             Creates a constraint closure that will return the provided C<$result> if
366             the value is a word in the given C<$set>, or the negation of C<$result>
367             otherwise.
368              
369             =item FV_set_cmp($result, $cmp, @set)
370              
371             Creates a constraint closure that will return the provided C<$result> if
372             the value is a member of the given C<@set>, or the negation of C<$result>
373             otherwise.
374              
375             C<$cmp> is a function which takes two arguments, and should return true if
376             the two elements are considered equal, otherwise returning false.
377              
378             =item FV_clamp($result, $low, $high)
379              
380             Creates a constraint closure that will return the provided C<$result> if
381             the value is numerically between the given C<$low> and C<$high> bounds, or
382             the negation of C<$result> otherwise.
383              
384             =item FV_lt($result, $bound)
385              
386             Creates a constraint closure that will return the provided C<$result> if
387             the value is numerically less than the given C<$bound>, or the negation of
388             C<$result> otherwise.
389              
390             =item FV_gt($result, $bound)
391              
392             Creates a constraint closure that will return the provided C<$result> if
393             the value is numerically greater than the given C<$bound>, or the negation
394             of C<$result> otherwise.
395              
396             =item FV_le($result, $bound)
397              
398             Creates a constraint closure that will return the provided C<$result> if
399             the value is numerically less than or equal to the given C<$bound>, or the
400             negation of C<$result> otherwise.
401              
402             =item FV_ge($result, $bound)
403              
404             Creates a constraint closure that will return the provided C<$result> if
405             the value is numerically greater than or equal to the given C<$bound>, or
406             the negation of C<$result> otherwise.
407              
408             =item FV_not($constraint)
409              
410             Creates a constraint closure that will return the negation of the result of
411             the given C<$constraint>.
412              
413             =item FV_or(@constraints)
414              
415             Creates a constraint closure that will return the result of the first
416             constraint that returns a non-false result.
417              
418             =item FV_and(@constraints)
419              
420             Creates a constraint closure that will return the result of the first
421             constraint to return a non-false result, -IF- ALL of the constraints return
422             non-false results.
423              
424             =back
425              
426             =head1 AUTHOR
427              
428             Graham TerMarsch (cpan@howlingfrog.com)
429              
430             =head1 COPYRIGHT
431              
432             Copyright (C) 2007, Graham TerMarsch. All Rights Reserved.
433              
434             This is free software; you can redistribute it and/or modify it under the same
435             license as Perl itself.
436              
437             =head1 SEE ALSO
438              
439             L.
440              
441             =cut