File Coverage

blib/lib/Type/Simple.pm
Criterion Covered Total %
statement 114 115 99.1
branch 53 60 88.3
condition n/a
subroutine 55 55 100.0
pod 23 27 85.1
total 245 257 95.3


line stmt bran cond sub pod time code
1             package Type::Simple;
2              
3 8     8   172467 use 5.006;
  8         46  
4 8     8   58 use strict;
  8         21  
  8         240  
5 8     8   53 use warnings;
  8         27  
  8         435  
6              
7 8     8   4543 use parent 'Exporter';
  8         2723  
  8         51  
8              
9 8     8   548 use Scalar::Util qw(blessed looks_like_number);
  8         21  
  8         964  
10 8     8   67 use Carp qw(croak);
  8         25  
  8         14712  
11              
12             our @EXPORT_OK = qw(
13             validate
14             Any
15             Bool
16             Maybe
17             Undef
18             Defined
19             Value
20             Str
21             Alpha
22             Alnum
23             Ascii
24             Num
25             Int
26             Print
27             Punct
28             Space
29             Word
30             Ref
31             ScalarRef
32             ArrayRef
33             HashRef
34             CodeRef
35             RegexpRef
36             Object
37             );
38              
39             =head1 NAME
40              
41             Type::Simple - simple type validation system for Perl
42              
43             =head1 VERSION
44              
45             Version 0.01
46              
47             =cut
48              
49             our $VERSION = '0.01';
50              
51             *validate = \&apply;
52              
53             sub apply {
54 1292     1292 0 28509 my ( $fn, $x ) = @_;
55              
56 1292 100       3076 if ( ref $fn eq 'CODE' ) {
    50          
57 1286         2964 return $fn->($x);
58             } elsif ( ref $fn eq 'Regexp' ) {
59 6 100       53 return $x =~ $fn ? 1 : 0;
60             } else {
61 0         0 croak "Invalid type check $fn (expected CODE or Regexp)";
62             }
63             }
64              
65             sub AND {
66 357     357 0 894 my (@fn) = @_;
67             return sub {
68 444     444   864 my ($x) = @_;
69 444         871 foreach my $fn (@fn) {
70 848 100       1769 return 0 if not apply( $fn, $x );
71             }
72 264         958 return 1;
73 357         1995 };
74             }
75              
76             sub OR {
77 10     10 0 24 my (@fn) = @_;
78             return sub {
79 20     20   36 my ($x) = @_;
80 20         39 foreach my $fn (@fn) {
81 32 100       78 return 1 if apply( $fn, $x );
82             }
83 3         23 return 0;
84 10         70 };
85             }
86              
87             sub NOT {
88 104     104 0 231 my ($fn) = @_;
89             return sub {
90 124     124   253 my ($x) = @_;
91 124 100       255 return apply( $fn, $x ) ? 0 : 1;
92 104         417 };
93             }
94              
95             sub Any {
96 12     12 1 12436 return sub {1};
  81     81   277  
97             }
98              
99             sub Bool {
100             return sub {
101 9     9   33 my ($x) = @_;
102              
103 9 100       46 return 1 if not defined $x;
104 8 100       65 return 1 if $x eq '';
105 7 100       95 return 1 if $x =~ /^[01]$/;
106              
107 5         38 return 0;
108 9     9 1 77 };
109             }
110              
111             sub Defined {
112             return sub {
113 300     300   654 my ($x) = @_;
114 300 100       1431 return defined $x ? 1 : 0;
115 247     247 1 1349 };
116             }
117              
118             sub Undef {
119 16     16 1 50 return NOT( Defined() );
120             }
121              
122             sub Maybe {
123 7     7 1 12 my ($fn) = @_;
124              
125 7         15 return OR( Undef(), $fn, );
126             }
127              
128             sub Ref {
129             return AND(
130             Defined(),
131             sub {
132 169     169   347 my ($x) = @_;
133 169 100       913 return ref $x ? 1 : 0;
134             },
135 141     141 1 332 );
136             }
137              
138             sub Value { # defined and not reference
139 81     81 1 188 return AND( Defined(), NOT( Ref() ), );
140             }
141              
142             sub Str {
143 72     72 1 195 return Value(); # same thing as value?
144             }
145              
146             sub Alpha {
147             return AND(
148             Str(),
149             sub {
150 6     6   13 my ($x) = @_;
151 6 100       51 return $x =~ /^[[:alpha:]]+$/ ? 1 : 0;
152             },
153 4     4 1 15 );
154             }
155              
156             sub Alnum {
157             return AND(
158             Str(),
159             sub {
160 2     2   5 my ($x) = @_;
161 2 100       16 return $x =~ /^[[:alnum:]]+$/ ? 1 : 0;
162             },
163 2     2 1 5 );
164             }
165              
166             sub Ascii {
167             return AND(
168             Str(),
169             sub {
170 2     2   6 my ($x) = @_;
171 2 100       17 return $x =~ /^[[:ascii:]]+$/ ? 1 : 0;
172             },
173 2     2 1 3 );
174             }
175              
176             sub Print {
177             return AND(
178             Str(),
179             sub {
180 2     2   5 my ($x) = @_;
181 2 50       29 return $x =~ /^[[:print:]]+$/ ? 1 : 0;
182             },
183 2     2 1 5 );
184             }
185              
186             sub Punct {
187             return AND(
188             Str(),
189             sub {
190 2     2   19 my ($x) = @_;
191 2 100       27 return $x =~ /^[[:punct:]]+$/ ? 1 : 0;
192             },
193 2     2 1 5 );
194             }
195              
196             sub Space {
197             return AND(
198             Str(),
199             sub {
200 1     1   3 my ($x) = @_;
201 1 50       7 return $x =~ /^[[:space:]]+$/ ? 1 : 0;
202             },
203 1     1 1 3 );
204             }
205              
206             sub Word {
207             return AND(
208             Str(),
209             sub {
210 1     1   5 my ($x) = @_;
211 1 50       9 return $x =~ /^[[:word:]]+$/ ? 1 : 0;
212             },
213 1     1 1 3 );
214             }
215              
216             sub Num {
217             return AND(
218             Str(),
219             sub {
220 45     45   88 my ($x) = @_;
221 45 100       329 return looks_like_number($x) ? 1 : 0;
222             },
223 43     43 1 114 );
224             }
225              
226             sub Int {
227             return AND(
228             Num(),
229             sub {
230 22     22   44 my ($x) = @_;
231 22 100       169 return 1 if $x =~ /^[0-9]+$/;
232 2         10 return 0;
233             },
234 24     24 1 84 );
235             }
236              
237             sub ScalarRef {
238             return AND(
239             Ref(),
240             sub {
241 1     1   4 my ($x) = @_;
242 1 50       9 return ref $x eq 'SCALAR' ? 1 : 0;
243             },
244 1     1 1 5 );
245             }
246              
247             sub ArrayRef {
248 21     21 1 99 my ($fn) = @_;
249              
250             return AND(
251             Ref(),
252             sub {
253 14     14   45 my ($x) = @_;
254 14 100       59 return 0 unless ref $x eq 'ARRAY';
255 13 100       44 return 1 unless $fn;
256              
257             # check items
258 11         24 foreach my $item ( @{$x} ) {
  11         37  
259 46 100       125 return 0 unless apply( $fn, $item );
260             }
261              
262 9         29 return 1;
263             },
264 21         72 );
265             }
266              
267             sub HashRef {
268 23     23 1 77 my ($fn) = @_;
269              
270             return AND(
271             Ref(),
272             sub {
273 37     37   75 my ($x) = @_;
274 37 100       125 return 0 unless ref $x eq 'HASH';
275 36 100       107 return 1 unless $fn;
276              
277             # check items
278 34         57 foreach my $key ( keys %{$x} ) {
  34         122  
279 90 100       210 return 0 unless apply( $fn, $x->{$key} );
280             }
281              
282 32         121 return 1;
283             },
284 23         91 );
285             }
286              
287             sub CodeRef {
288             return AND(
289             Ref(),
290             sub {
291 1     1   3 my ($x) = @_;
292 1 50       7 return ref $x eq 'CODE' ? 1 : 0;
293             },
294 1     1 1 7 );
295             }
296              
297             sub RegexpRef {
298             return AND(
299             Ref(),
300             sub {
301 1     1   4 my ($x) = @_;
302 1 50       9 return ref $x eq 'Regexp' ? 1 : 0;
303             },
304 1     1 1 5 );
305             }
306              
307             sub Object {
308             return AND(
309             Ref(),
310             sub {
311 2     2   6 my ($x) = @_;
312 2 100       27 return blessed $x ? 1 : 0;
313             },
314 2     2 1 7 );
315             }
316              
317             =head1 SYNOPSIS
318              
319             use Type::Simple qw(:all);
320              
321             # simple values
322             validate( Int(), 123 ); # -> true
323             validate( Str(), 'xyz' ); # -> false
324              
325             # compound values
326             validate( ArrayRef(Int()), [ 1, 2, 3 ] ); # -> true
327             validate( HashRef(Bool()), { foo => 1, bar => 0 } ); # -> true
328              
329             You can pass your own validation functions as code references:
330              
331             my $greater_than_one = sub { $_[0] > 1 };
332             my $less_than_ten = sub { $_[0] < 10 };
333              
334             validate( $greater_than_one, 50 ); # -> true
335             validate( $less_than_ten, 50 ); # -> false
336              
337             It's possible to combine and modify tests using the boolean functions
338             C, C and C:
339              
340             validate(
341             Type::Simple::OR( CodeRef(), RegexpRef() ),
342             $code_or_regexp,
343             );
344              
345             validate(
346             Type::Simple::AND(
347             Num(),
348             $greater_than_one,
349             $less_than_ten
350             ),
351             $number
352             );
353              
354             validate(
355             Type::Simple::AND(
356             Num(),
357             Type::Simple::NOT(Int()),
358             ),
359             $non_integer_number
360             );
361              
362             =head1 DESCRIPTION
363              
364             Any
365             Bool
366             Maybe
367             Undef
368             Defined
369             Value
370             Str
371             Alpha
372             Alnum
373             Ascii
374             Num
375             Int
376             Print
377             Punct
378             Space
379             Word
380             Ref
381             ScalarRef
382             ArrayRef
383             HashRef
384             CodeRef
385             RegexpRef
386             Object
387              
388             =head1 EXPORT
389              
390             None by default.
391              
392             All the subroutines below can be exported:
393              
394             =head1 SUBROUTINES
395              
396             =head2 validate( type, value)
397              
398             Try to validate a value using a type. Example:
399              
400             validate( Num(), 123 ); # -> true
401             validate( Num(), 'x' ); # -> false
402              
403             The validation functions are the following:
404              
405             =head2 Any()
406              
407             Anything.
408              
409             =head2 Bool()
410              
411             Perl boolean values: C<1>, C<0>, C<''> and C.
412              
413             =head2 Maybe(`a)
414              
415             Type `a or C.
416              
417             =head2 Undef()
418              
419             C.
420              
421             =head2 Defined()
422              
423             Defined value. (Not C)
424              
425             =head2 Value()
426              
427             Number or string. (Not references)
428              
429             =head2 Str()
430              
431             String.
432              
433             Since numbers can be stringified, it will also accept numbers.
434             If you want a non-numeric string, you can use:
435              
436             Type::Simple::AND(
437             Str(),
438             Type::Simple::NOT(Num()),
439             );
440              
441             =head2 Alpha()
442              
443             A string of alphabetical characters (C<[A-Za-z]>).
444              
445             =head2 Alnum()
446              
447             A string of alphanumeric characters (C<[A-Za-z0-9]>)
448              
449             =head2 Ascii()
450              
451             A string of characters in the ASCII character set.
452              
453             =head2 Num()
454              
455             Looks like a number.
456              
457             =head2 Int()
458              
459             An integer.
460              
461             =head2 Print()
462              
463             A string of printable characters, including spaces.
464              
465             =head2 Punct()
466              
467             A string of non-alphanumeric, non-space characters
468             (C<<[-!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~]>>).
469              
470             =head2 Space()
471              
472             A string of whitespace characters (equivalent to C<\s>).
473              
474             =head2 Word()
475              
476             A string of word characters (C<[A-Za-z0-9_]>, equivalent to C<\w>).
477              
478             =head2 Ref()
479              
480             A reference.
481              
482             =head2 ScalarRef()
483              
484             A scalar reference.
485              
486             =head2 ArrayRef(`a)
487              
488             An array reference.
489              
490             If you specify `a, the array elements should be of type `a.
491              
492             =head2 HashRef(`a)
493              
494             A hash reference.
495              
496             If you specify `a, the hash values should be of type `a.
497              
498             =head2 CodeRef()
499              
500             A code reference.
501              
502             =head2 RegexpRef()
503              
504             A regexp reference.
505              
506             =head2 Object()
507              
508             A blessed object.
509              
510             =head1 AUTHOR
511              
512             Nelson Ferraz, C<< >>
513              
514             =head1 BUGS
515              
516             Please report any bugs or feature requests to
517             L. I will be notified,
518             and then you'll automatically be notified of progress on your bug
519             as I make changes.
520              
521             =head1 SUPPORT
522              
523             You can find documentation for this module with the perldoc command.
524              
525             perldoc Type::Simple
526              
527             You can also look for information at:
528              
529             =over 4
530              
531             =item * GitHub
532              
533             L
534              
535             =item * Search CPAN
536              
537             L
538              
539             =back
540              
541              
542             =head1 ACKNOWLEDGEMENTS
543              
544              
545             =head1 LICENSE AND COPYRIGHT
546              
547             Copyright 2017 Nelson Ferraz.
548              
549             This program is distributed under the MIT (X11) License:
550             L
551              
552             Permission is hereby granted, free of charge, to any person
553             obtaining a copy of this software and associated documentation
554             files (the "Software"), to deal in the Software without
555             restriction, including without limitation the rights to use,
556             copy, modify, merge, publish, distribute, sublicense, and/or sell
557             copies of the Software, and to permit persons to whom the
558             Software is furnished to do so, subject to the following
559             conditions:
560              
561             The above copyright notice and this permission notice shall be
562             included in all copies or substantial portions of the Software.
563              
564             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
565             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
566             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
567             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
568             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
569             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
570             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
571             OTHER DEALINGS IN THE SOFTWARE.
572              
573              
574             =cut
575              
576             1; # End of Type::Simple