File Coverage

blib/lib/Params/Validate/Checks.pm
Criterion Covered Total %
statement 34 34 100.0
branch 11 12 91.6
condition 2 2 100.0
subroutine 8 8 100.0
pod 0 2 0.0
total 55 58 94.8


line stmt bran cond sub pod time code
1             package Params::Validate::Checks;
2              
3             =head1 NAME
4              
5             Params::Validate::Checks - Named checks for use with Params::Validate
6              
7             =head1 SYNOPSIS
8              
9             use Params::Validate::Checks qw;
10              
11             sub random_insult
12             {
13             my %arg = validate @_,
14             {
15             name => {as 'string'},
16             words => {as 'pos_int'},
17             paragraphs => {as 'pos_int', default => 1},
18             };
19              
20             # Do something with $arg{name}, $arg{words}, $arg{paragraphs} ...
21             }
22              
23             =cut
24              
25              
26 6     6   173450 use warnings;
  6         14  
  6         194  
27 6     6   32 use strict;
  6         13  
  6         201  
28              
29 6     6   34 use Carp qw;
  6         15  
  6         447  
30              
31 6     6   33 use base qw;
  6         8  
  6         557  
32              
33 6     6   6855 use Params::Validate qw<:all>;
  6         83030  
  6         2910  
34              
35              
36             our $VERSION = 0.01;
37              
38              
39             =head1 DESCRIPTION
40              
41             L lets you precisely specify what are valid arguments to your
42             functions and methods, helping to catch errors sooner and make your programs
43             more robust. But if multiple parameters (in either the same or different subs)
44             have the same spec it's tedious to have to repeat this. So
45             C provides:
46              
47             =over 2
48              
49             =item *
50              
51             standard, named checks for use in C specifications
52              
53             =item *
54              
55             a way of you defining more named checks for your own re-use
56              
57             =back
58              
59             =head2 Basic Use
60              
61             Import C and C, then read a function's arguments into a hash by
62             calling the C function. Pass it C<@_> and a hash-ref specifying your
63             function's named parameters:
64              
65             sub total_price {
66             my %arg = validate @_, {
67             unit_price => {as 'pos_int'},
68             quantity => {as 'pos_int'},
69             };
70              
71             Each key in the hash-ref is a parameter's name; the corresponding value is
72             specified in braces with C followed by the name of the check to apply to
73             that parameter.
74              
75             If all the checks pass then your hash will be populated with the supplied
76             arguments.
77              
78             But if there's a problem with the arguments then your function will abort with
79             an appropriate error message. This could happen in any of these situations:
80              
81             =over 2
82              
83             =item *
84              
85             a compulsory argument is missing
86              
87             =item *
88              
89             an argument is supplied but its contents don't pass its check
90              
91             =item *
92              
93             an unexpected argument has been supplied
94              
95             =back
96              
97             =cut
98              
99              
100             # Since we've used all of Params::Validate we can re-export any of its
101             # functions, plus as which we've created:
102             our @EXPORT_OK = (@Params::Validate::EXPORT_OK, 'as');
103              
104             # Export as by default, since it's the main purpose of this module:
105             our @EXPORT = (@Params::Validate::EXPORT, 'as');
106              
107             # Make the Params::Validate tags work too; we have to do a deep copy of the tag
108             # we're changing, so that the original is left intact:
109             our %EXPORT_TAGS = %Params::Validate::EXPORT_TAGS;
110             $EXPORT_TAGS{all} = [@{$EXPORT_TAGS{all}}, 'as'];
111              
112             # registered checks:
113             my %Check;
114              
115              
116             sub as
117             {
118 56     56 0 28154 my $name = shift;
119              
120 56 50       170 my $check = $Check{$name} or croak "Check $name isn't defined";
121              
122             # Each check is a hash-ref; dereference it, so that we're returning items
123             # suitable for the caller to put in a hash, and send back to the caller any
124             # additional options that they sent us (because syntactically it's less
125             # hassle for them to send them here than distinguish them):
126 56         911 (%$check, @_);
127             }
128              
129              
130             =head2 Standard Checks
131              
132             These standard checks are supplied by this module:
133              
134             =over
135              
136             =item C
137              
138             a positive integer, such as "42" (but not "0", "007", or "24A")
139              
140             =item C
141              
142             a single-line string that isn't just whitespace, such as "yellow spog" (but not
143             "" or " ", nor anything with a line-break in it); note that unlike using
144             C in C this does permit objects which stringify to an
145             appropriate value, such as C objects
146              
147             =back
148              
149             Currently there's just those two because they're the only 'generic' checks
150             I've needed, but it's likely more will be added -- requests welcome!
151              
152             For checks specific to a particular field it makes more sense to distribute
153             them in a separate module, especially when they depend on other modules; for
154             example L contains some checks useful for
155             dealing with network-related things, such as domain names and IP addresses.
156              
157             =cut
158              
159              
160             {
161              
162             # Allow for tested arguments being undef:
163 6     6   61 no warnings qw;
  6         14  
  6         2519  
164              
165             register
166             (
167             pos_int => qr/^[1-9]\d*\z/,
168              
169             string =>
170             {
171             callbacks =>
172             {
173             'not empty' => sub { $_[0] =~ /\S/ },
174             'one line' => sub { $_[0] !~ /\n/ },
175             },
176             },
177             );
178             }
179              
180              
181             =head2 More Advanced Use
182              
183             All of L's features and flexibility can be used, and for
184             convenience any of its functions can be imported via
185             C, so you don't need 2 C lines. (The C<:all>
186             tag imports everything C would plus C from this module.)
187              
188             You can add options to individual checks, such as C to make a
189             parameter optional:
190              
191             my %arg = validate @_,
192             {
193             forename => {as 'string'},
194             middle_name => {as 'string', optional => 1},
195             surname => {as 'string'},
196             };
197              
198             or C, which makes it optional to the caller but ensures your hash
199             always has a value for it:
200              
201             my %arg = validate @_,
202             {
203             colour => {as 'string', default => 'red'},
204             quantity => {as 'pos_int', default => 99},
205             };
206              
207             You can mix named checks with 'one off' checks that are defined directly using
208             C syntax:
209              
210             my %arg = validate @_,
211             {
212             quantity => {as 'pos_int', default => 1},
213             product_code => {regex => qr/^[DOSW]\d{4}\z/},
214             };
215              
216             You can use C to validate positional parameters:
217              
218             use Params::Validate::Checks qw;
219             my ($x, $y) = validate_pos @_, {as 'pos_int'}, {as 'pos_int', default => 0};
220              
221             For details of these features and more, see L.
222              
223             =head2 Defining New Checks
224              
225             It's simple to define a new check, just call
226             C with the name and functionality of the
227             check. This can be specified as a pattern:
228              
229             Params::Validate::Checks::register sort_code => qr/^\d\d-\d\d-\d\d\z/;
230              
231             or a function to do the checking; the function is invoked each time an argument
232             is being checked, with the argument passed as a parameter:
233              
234             Params::Validate::Checks::register postcode => \&valid_postcode;
235              
236             or as a hash-ref of a C spec:
237              
238             Params::Validate::Checks::register template => {isa => 'Template'};
239              
240             While you can do this in the same file that's using the checks, the intention
241             is to create libraries of checks -- you can put checks for things like product
242             codes, office identifiers, and internal hostnames in a library for your
243             organization. And checks for 'generic' things like e-mail addresses,
244             postcodes, country codes, CSS colours, and so on can be put in modules
245             contributed to Cpan.
246              
247             Note C isn't exported (because creating checks should be rarer than
248             using them), but you can define multiple checks in a single call, so a library
249             of checks can -- in its entirety -- be as simple as:
250              
251             package PopCorp::Params::Validate::Checks;
252             use Params::Validate::Checks;
253              
254             Params::Validate::Checks::register
255             playing_card => qr/^(?:[A2-9JQK]|10)[CDHS]\z/,
256             room_number => qr/^[0-2]\.[1-9]\d*\z/,
257             palindrome => sub { $_[0] eq reverse $_[0] };
258              
259             C returns a true value, so it's valid to call it as the last thing in
260             a package, as in the above example.
261              
262             =cut
263              
264              
265             sub register
266             {
267              
268             # For each check provided turn it into a hash suitable for using directly in
269             # a Params::Validate specification:
270 11     11 0 3505 while (@_)
271             {
272 19         34 my $name = shift;
273 19 100       66 my $test = shift or croak "Registering $name failed: no check specified";
274              
275 18 100       63 warn "Overwriting existing check for $name" if $Check{$name};
276              
277 18   100     119 my $type = ref $test || 'scalar';
278              
279 18         24 my $check;
280              
281             # If we've been given a hash-ref then presume it's already what's required:
282 18 100       60 if ($type eq 'HASH')
    100          
    100          
283             {
284 7         13 $check = $test;
285             }
286              
287             # For convenience allow patterns to be specified directly, so wrap them
288             # appropriately:
289             elsif ($type eq 'Regexp')
290             {
291 8         22 $check = {regex => $test};
292             }
293            
294             # Ditto for subs; these need names (to use in the error message), so re-use
295             # this check's name:
296             elsif ($type eq 'CODE')
297             {
298 1         5 $check = {callbacks => {$name => $test}};
299             }
300              
301             else
302             {
303 2         21 croak "Unrecognized check type passed for $name: $type";
304             }
305              
306 16         73 $Check{$name} = $check;
307             }
308              
309             # Ensure it's OK to use this as the only (and therefore last) thing in a
310             # module:
311 8         27 1;
312             }
313              
314              
315             =head1 FUTURE PLANS
316              
317             More checks, such as for other sorts of numbers, are likely to be added as uses
318             for them are encountered.
319              
320             And I suspect it'll be useful to add a way of defining a check as a list of
321             permitted values.
322              
323             =head1 CAVEATS
324              
325             This module is still in its infancy; it's possible that development based on
326             experience of using it will require making backwards-incompatible changes to
327             its interface.
328              
329             Currently there is a global list of all registered checks, so it isn't possible
330             for two different libraries (used non-overlappingly) to declare different
331             checks with the same name.
332              
333             =head1 SEE ALSO
334              
335             =over 2
336              
337             =item *
338              
339             L, which provides most of the functionality here
340              
341             =item *
342              
343             L, for an example of creating a library of
344             additional checks
345              
346             =item *
347              
348             Alternative modules for checking parameters, with different syntaxes:
349             L and L
350              
351             =back
352              
353             =head1 CREDITS
354              
355             Written and maintained by Smylers
356              
357             Thanks to Aaron Crane for help with the design, and Ovid for spotting a bug.
358             And of course thank you to Dave Rolsky for creating C.
359              
360             =head1 COPYRIGHT & LICENCE
361              
362             Copyright 2006-2008 by Smylers.
363              
364             This library is software libre; you may redistribute it and modify it under the
365             terms of any of these licences:
366              
367             =over 2
368              
369             =item *
370              
371             L
372              
373             =item *
374              
375             The GNU General Public License, version 3
376              
377             =item *
378              
379             L
380              
381             =item *
382              
383             The Artistic License 2.0
384              
385             =back
386              
387             =cut
388              
389              
390             1;