File Coverage

blib/lib/Params/Validate/Micro.pm
Criterion Covered Total %
statement 68 70 97.1
branch 24 28 85.7
condition 12 15 80.0
subroutine 8 8 100.0
pod 2 2 100.0
total 114 123 92.6


line stmt bran cond sub pod time code
1             package Params::Validate::Micro;
2              
3 3     3   179707 use strict;
  3         6  
  3         190  
4 3     3   15 use warnings;
  3         6  
  3         96  
5 3     3   3086 use Params::Validate qw(:all);
  3         40135  
  3         807  
6 3     3   31 use Scalar::Util qw(reftype);
  3         6  
  3         372  
7 3     3   18 use Carp qw(croak confess);
  3         6  
  3         3849  
8              
9             require Exporter;
10             our @ISA = qw(Exporter);
11             our %EXPORT_TAGS = (
12             all => [qw(micro_validate micro_translate)],
13             );
14             our @EXPORT_OK = (@{ $EXPORT_TAGS{all} });
15              
16             =head1 NAME
17              
18             Params::Validate::Micro - Validate parameters concisely
19              
20             =head1 VERSION
21              
22             Version 0.032
23              
24             =cut
25              
26             our $VERSION = '0.032';
27              
28             =head1 SYNOPSIS
29              
30             use Params::Validate::Micro qw(:all);
31             use Params::Validate::Micro qw(micro_validate micro_translate);
32              
33             =head1 DESCRIPTION
34              
35             Params::Validate::Micro allows you to concisely represent a
36             list of arguments, their types, and whether or not they are
37             required.
38              
39             Nothing is exported by default. Use C<< :all >> or the
40             specific function name you want.
41              
42             =head1 FORMAT
43              
44             Micro argument strings are made up of lists of parameter
45             names. Each name may have an optional sigil (one of C<< $@%
46             >>), which translate directly to the Params::Validate
47             constrations of SCALAR | OBJECT, ARRAYREF, and HASHREF, respectively.
48              
49             There may be one semicolon (C<< ; >>) in your argument
50             string. If present, any parameters listed after the
51             semicolon are marked as optional.
52              
53             Examples:
54              
55             =over 4
56              
57             =item Single scalar argument
58              
59             $text
60              
61             =item Hashref and optional scalar
62              
63             %opt; $verbose
64              
65             =item Two arrayrefs and an untyped argument
66              
67             @addrs @lines message
68              
69             =back
70              
71             You may also have an empty argument string. This indicates
72             that you want no parameters at all.
73              
74             =head1 FUNCTIONS
75              
76             =head3 C<< micro_translate >>
77              
78             my %spec = micro_translate($string, $extra);
79              
80             Turns C<< $string >> into a Params::Validate spec as
81             described in L, then merges the resultant spec and
82             the optional C<< $extra >> hashref.
83              
84             This returns a list, which just happens to be a set of key
85             => value pairs. This matters because it means that if you
86             wanted to you could treat it as an array for long enough to
87             figure out what order the parameters were specified in. You
88             could use this to do your own optional positional
89             validation.
90              
91             =head3 C<< micro_validate >>
92              
93             my $arg = micro_validate(\%arg, $string, $extra);
94             my $arg = micro_validate(\@args, $string, $extra);
95              
96             Use C<< micro_translate >> with C<< $string >> and C<<
97             $extra >>, then passes the whole thing to Params::Validate.
98              
99             Named parameters should be passed in as a hashref, and
100             positional parameters as an arrayref. Positional parameters
101             will be associated with names in the order specified in C<<
102             $string >>. For example:
103              
104             micro_validate({ a => 1 }, q{$a; $b});
105             micro_validate([ 1 ], q{$a; $b});
106              
107             Both will return this:
108              
109             { a => 1 }
110              
111             When passing positional parameters, C<< micro_validate >>
112             will die if there are either too many for the spec or not
113             enough to fill all non-optional parameters.
114              
115             Returns a hashref of the validated arguments.
116              
117             =cut
118              
119             my $BARE_VAR = qr/[a-z_]\w*/i;
120              
121             my $SIGIL_VAR = qr/[%\$\@]?$BARE_VAR/i;
122              
123             my $EXTRACT_VARS = qr/\A
124             (
125             (?: \s* ; \s*)?
126             $SIGIL_VAR
127             (?:
128             (?: \s* ; )?
129             \s+ $SIGIL_VAR
130             )*
131             )?
132             \z/x;
133              
134             my %PVSPEC = (
135             '%' => {
136             type => HASHREF,
137             },
138             '@' => {
139             type => ARRAYREF,
140             },
141             '$' => {
142             type => SCALAR | OBJECT,
143             },
144             );
145              
146             my ($SIGIL) = map { qr/$_/ } '[' . join("", keys %PVSPEC) . ']';
147              
148             sub micro_translate {
149 21     21 1 4465 my ($string, $extra) = @_;
150 21         96 $string =~ s/^\s*//;
151 21         110 $string =~ s/\s*$//;
152 21 50       238 croak "'$string' does not appear to be a micro-spec"
153             unless $string =~ $EXTRACT_VARS;
154              
155             # maybe they want to say "no args at all"
156 21 100       79 return unless defined $1;
157              
158 52         97 my @vspecs = grep {
159 17         39 length($_)
160             } map {
161             # make sure that semicolons are their own 'word'
162 17         133 s/;/ ; /g;
163 17         69 split /\s+/;
164             } $string =~ $EXTRACT_VARS;
165              
166 17         27 my $optional;
167             my @spec;
168 17         31 for my $vspec (@vspecs) {
169 50 100       113 if ($vspec eq ';') {
170 7 100       23 if ($optional++) {
171 1         259 croak "micro-spec '$string' contains multiple semicolons";
172             }
173 6         10 next;
174             }
175 43         63 my $vname = $vspec;
176 43         68 my $spart = {};
177 43         283 while ($vname =~ s/^($SIGIL)//) {
178 29         54 my $sigil = $1;
179 29 50       49 $spart = { %$spart, %{$PVSPEC{$sigil} || {}} };
  29         283  
180             }
181 43 50       262 unless ($vname =~ /\A$BARE_VAR\z/) {
182 0         0 croak "illegal parameter name: '$vname'";
183             }
184 43 100       80 if ($optional) {
185 10         19 $spart->{optional} = 1;
186             }
187 43 100       97 if ($extra->{$vname}) {
188             # as of now, the only things that may be already set in $spart are 'type'
189             # and 'optional'. it is therefore safe to naively join the hashes, since
190             # we don't need to worry about more complex cases like merging nested
191             # 'callbacks' entries. re-evaluate this if more complex specs are
192             # being generated automatically. -- hdp, 2007-04-10
193 3         7 %$spart = (%$spart, %{$extra->{$vname}});
  3         13  
194             }
195 43 100       143 unless (%$spart) {
196 11         17 $spart = 1;
197             }
198 43         120 push @spec, $vname => $spart;
199             }
200              
201 16         118 return @spec;
202             }
203              
204             sub _pos_to_named {
205 10     10   20 my ($string, $args, $spec) = @_;
206 10         27 my @tmpspec = @$spec;
207 10         17 my @tmpargs = @$args;
208 10         19 my $return = {};
209 10         38 while (my ($key, $val) = splice @tmpspec, 0, 2) {
210 26 100       57 unless (@tmpargs) {
211 4 100 100     25 if (ref($val) eq 'HASH' and $val->{optional}) {
212 2         4 last;
213             } else {
214 2         301 confess "not enough arguments for '$string' (only got @$args)";
215             }
216             }
217 22         84 $return->{$key} = shift(@tmpargs);
218             }
219 8 100       19 if (@tmpargs) {
220 1         145 confess "too many arguments for '$string' (leftover: @tmpargs)";
221             }
222 7         16 return $return;
223             }
224              
225             sub micro_validate {
226 15     15 1 5505 my ($args, $string, $extra) = @_;
227 15   100     52 $args ||= {};
228 15   100     44 $string ||= "";
229 15   100     67 $extra ||= {};
230              
231 15         42 my $spec = [ micro_translate($string, $extra) ];
232              
233 15 100 66     113 if ($args and reftype($args) eq 'ARRAY') {
234 10         53 $args = _pos_to_named($string, $args, $spec);
235             }
236 12 50 33     81 unless ($args and reftype($args) eq 'HASH') {
237 0         0 croak "first argument to micro_validate must be hashref or arrayref";
238             }
239              
240             return {
241 12         5544 validate_with(
242             params => $args,
243             spec => { @$spec },
244             )
245             };
246             }
247              
248             =head1 SEE ALSO
249              
250             L
251              
252             =head1 AUTHOR
253              
254             Hans Dieter Pearcey, C<< >>
255              
256             =head1 BUGS
257              
258             Please report any bugs or feature requests to
259             C, or through the web interface at
260             L.
261             I will be notified, and then you'll automatically be notified of progress on
262             your bug as I make changes.
263              
264             =head1 COPYRIGHT & LICENSE
265              
266             Copyright 2005 Hans Dieter Pearcey, all rights reserved.
267              
268             This program is free software; you can redistribute it and/or modify it
269             under the same terms as Perl itself.
270              
271             =cut
272              
273             1; # End of Params::Validate::Micro