File Coverage

blib/lib/Venus/Assert.pm
Criterion Covered Total %
statement 180 199 90.4
branch 67 84 79.7
condition 25 48 52.0
subroutine 45 48 93.7
pod 16 22 72.7
total 333 401 83.0


line stmt bran cond sub pod time code
1             package Venus::Assert;
2              
3 11     11   276 use 5.018;
  11         44  
4              
5 11     11   66 use strict;
  11         33  
  11         261  
6 11     11   57 use warnings;
  11         37  
  11         424  
7              
8 11     11   63 use Venus::Class 'attr', 'base', 'with';
  11         32  
  11         89  
9              
10             base 'Venus::Kind::Utility';
11              
12             with 'Venus::Role::Buildable';
13              
14             use overload (
15 0     0   0 '&{}' => sub{$_[0]->validator},
16 11         160 fallback => 1,
17 11     11   115 );
  11         28  
18              
19             # ATTRIBUTES
20              
21             attr 'name';
22              
23             # BUILDERS
24              
25             sub build_arg {
26 186     186 0 435 my ($self, $name) = @_;
27              
28             return {
29 186         708 name => $name,
30             };
31             }
32              
33             sub build_self {
34 206     206 0 435 my ($self, $data) = @_;
35              
36 206         668 $self->conditions;
37              
38 206         339 return $self;
39             }
40              
41             # METHODS
42              
43             sub accept {
44 179     179 1 448 my ($self, $name, @args) = @_;
45              
46 179 50       454 return $self if !$name;
47              
48 179         415 $self->check->accept($name, @args);
49              
50 179         728 return $self;
51             }
52              
53             sub check {
54 438     438 1 1255 my ($self, @args) = @_;
55              
56 438         9554 require Venus::Check;
57              
58 438 100       1161 $self->{check} = $args[0] if @args;
59              
60 438   66     6429 $self->{check} ||= Venus::Check->new;
61              
62 438         2275 return $self->{check};
63             }
64              
65             sub clear {
66 1     1 1 3 my ($self) = @_;
67              
68 1         4 $self->check->clear;
69 1         5 $self->constraint->clear;
70 1         11 $self->coercion->clear;
71              
72 1         10 return $self;
73             }
74              
75             sub coerce {
76 56     56 1 964 my ($self, $data) = @_;
77              
78 56         572 return $self->coercion->result($self->value($data));
79             }
80              
81             sub coercion {
82 66     66 1 138 my ($self, @args) = @_;
83              
84 66         1817 require Venus::Coercion;
85              
86 66 100       387 $self->{coercion} = $args[0] if @args;
87              
88 66   66     606 $self->{coercion} ||= Venus::Coercion->new->do('check', $self->check);
89              
90 66         273 return $self->{coercion};
91             }
92              
93             sub conditions {
94 206     206 1 423 my ($self) = @_;
95              
96 206         349 return $self;
97             }
98              
99             sub constraint {
100 206     206 1 383 my ($self, @args) = @_;
101              
102 206         7365 require Venus::Constraint;
103              
104 206 100       587 $self->{constraint} = $args[0] if @args;
105              
106 206   66     1254 $self->{constraint} ||= Venus::Constraint->new->do('check', $self->check);
107              
108 206         771 return $self->{constraint};
109             }
110              
111             sub ensure {
112 3     3 1 11 my ($self, @code) = @_;
113              
114 3         12 $self->constraint->ensure(@code);
115              
116 3         56 return $self;
117             }
118              
119             sub expression {
120 102     102 1 261 my ($self, $data) = @_;
121              
122 102 50       214 return $self if !$data;
123              
124 102         872 $data =
125             $data =~ s/\s*\n+\s*/ /gr =~ s/^\s+|\s+$//gr =~ s/\[\s+/[/gr =~ s/\s+\]/]/gr;
126              
127 102 100       291 $self->name($data) if !$self->name;
128              
129 102         324 my $parsed = $self->parse($data);
130              
131             $self->accept(
132 102         402 @{$parsed} > 0
133 13         54 ? ((ref $parsed->[0] eq 'ARRAY') ? @{$parsed->[0]} : @{$parsed})
  89         351  
134 102 100       183 : @{$parsed}
  0 50       0  
135             );
136              
137 102         458 return $self;
138             }
139              
140             sub format {
141 5     5 1 16 my ($self, @code) = @_;
142              
143 5         19 $self->coercion->format(@code);
144              
145 5         99 return $self;
146             }
147              
148             sub match {
149 228     228 0 491 my ($self, @args) = @_;
150              
151 228         3355 require Venus::Coercion;
152 228         741 my $match = Venus::Coercion->new->accept(@args);
153              
154 228         492 push @{$self->matches}, sub {
155 675     675   1229 my ($source, $value) = @_;
156 675         1008 local $_ = $value;
157 675         1544 return $match->result($value);
158 228         329 };
159              
160 228         1352 return $match;
161             }
162              
163             sub matches {
164 535     535 0 904 my ($self) = @_;
165              
166 535   100     1870 my $matches = $self->{'matches'} ||= [];
167              
168 535 100       1657 return wantarray ? (@{$matches}) : $matches;
  307         757  
169             }
170              
171             sub parse {
172 126     126 1 291 my ($self, $expr) = @_;
173              
174 126   100     286 $expr ||= '';
175              
176 126         1004 $expr =
177             $expr =~ s/\s*\n+\s*/ /gr =~ s/^\s+|\s+$//gr =~ s/\[\s+/[/gr =~ s/\s+\]/]/gr;
178              
179 126         309 return _type_parse($expr);
180             }
181              
182             sub received {
183 29     29 0 104 my ($self, $data) = @_;
184              
185 29         131 require Scalar::Util;
186              
187 29 100       110 if (!defined $data) {
188 9         29 return '';
189             }
190              
191 20         80 my $blessed = Scalar::Util::blessed($data);
192 20   33     84 my $isvenus = $blessed && $data->isa('Venus::Core') && $data->can('does');
193              
194 20 100 66     150 if (!$blessed && !ref $data) {
195 12         38 return $data;
196             }
197 8 50 33     27 if ($blessed && ref($data) eq 'Regexp') {
198 0         0 return "$data";
199             }
200 8 50 33     21 if ($isvenus && $data->does('Venus::Role::Explainable')) {
201 0     0   0 return $self->dump(sub{$data->explain});
  0         0  
202             }
203 8 50 33     28 if ($isvenus && $data->does('Venus::Role::Valuable')) {
204 0     0   0 return $self->dump(sub{$data->value});
  0         0  
205             }
206 8 50 33     23 if ($isvenus && $data->does('Venus::Role::Dumpable')) {
207 0         0 return $data->dump;
208             }
209 8 50 33     21 if ($blessed && overload::Method($data, '""')) {
210 0         0 return "$data";
211             }
212 8 50 33     35 if ($blessed && $data->can('as_string')) {
213 0         0 return $data->as_string;
214             }
215 8 50 33     20 if ($blessed && $data->can('to_string')) {
216 0         0 return $data->to_string;
217             }
218 8 50 33     26 if ($blessed && $data->isa('Venus::Kind')) {
219 0         0 return $data->stringified;
220             }
221             else {
222 8     8   96 return $self->dump(sub{$data});
  8         32  
223             }
224             }
225              
226             sub render {
227 23     23 1 53 my ($self, $into, $data) = @_;
228              
229 23         52 return _type_render($into, $data);
230             }
231              
232             sub result {
233 53     53 1 147 my ($self, $data) = @_;
234              
235 53         159 return $self->coerce($self->validate($self->value($data)));
236             }
237              
238             sub valid {
239 198     198 1 1283 my ($self, $data) = @_;
240              
241 198         498 return $self->constraint->result($self->value($data));
242             }
243              
244             sub validate {
245 133     133 1 293 my ($self, $data) = @_;
246              
247 133         450 my $valid = $self->valid($data);
248              
249 133 100       636 return $data if $valid;
250              
251 29         119 my $error = $self->check->catch('result');
252              
253 29         129 my $received = $self->received($data);
254              
255 29 50 50     130 my $message = join("\n\n",
    100          
256             'Type:',
257             ($self->name || 'Unknown'),
258             'Failure:',
259             $error->message,
260             'Received:',
261             (defined $data ? ($received eq '' ? '""' : $received) : ('(undefined)')),
262             );
263              
264 29         130 $error->message($message);
265              
266 29         137 return $error->throw;
267             }
268              
269             sub validator {
270 2     2 1 8 my ($self) = @_;
271              
272 2         22 return $self->defer('validate');
273             }
274              
275             sub value {
276 307     307 0 587 my ($self, $data) = @_;
277              
278 307         479 my $result = $data;
279              
280 307         657 for my $match ($self->matches) {
281 675         1549 $result = $match->($self, $result);
282             }
283              
284 307         1047 return $result;
285             }
286              
287             # ROUTINES
288              
289             sub _type_parse {
290 389     389   883 my @items = _type_parse_pipes(@_);
291              
292 389         807 my $either = @items > 1;
293              
294 389         1105 @items = map _type_parse_nested($_), @items;
295              
296 389 100 100     2648 return wantarray && !$either ? (@items) : [$either ? ("either") : (), @items];
    100          
297             }
298              
299             sub _type_parse_lists {
300 133     133   258 my @items = @_;
301              
302 133         187 my $r0 = '[\"\'\[\]]';
303 133         204 my $r1 = '[^\"\'\[\]]';
304 133         193 my $r2 = _type_subexpr_type_2();
305 133         243 my $r3 = _type_subexpr_delimiter();
306              
307             return (
308             grep length,
309 133         211 map {split/,\s*(?=(?:$r1*$r0$r1*$r0)*$r1*$)(${r2}(?:${r3}[^,]*)?)?/}
  133         1689  
310             @items
311             );
312             }
313              
314             sub _type_parse_nested {
315 467     467   961 my ($expr) = @_;
316              
317 467 100       796 return ($expr) if $expr !~ _type_regexp(_type_subexpr_type_2());
318              
319 66         242 my @items = ($expr);
320              
321 66         350 @items = ($expr =~ /^(\w+)\s*\[\s*(.*)\s*\]+$/g);
322              
323 66         202 @items = map _type_parse_lists($_), @items;
324              
325 66 100       185 @items = map +(
326 261         447 $_ =~ qr/^@{[_type_subexpr_type_2()]},.*$/ ? _type_parse_lists($_) : $_
327             ),
328             @items;
329              
330 66         131 @items = map {s/^["']+|["']+$//gr} @items;
  263         1023  
331              
332 66         210 @items = map _type_parse($_), @items;
333              
334 66 100       296 return (@items > 1 ? [@items] : @items);
335             }
336              
337             sub _type_parse_pipes {
338 460     460   821 my ($expr) = @_;
339              
340 460         630 my @items;
341              
342             # i.e. tuple[number, string] | tuple[string, number]
343 460 100       829 if
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
344             (
345             _type_regexp_eval(
346             $expr, _type_regexp(_type_subexpr_type_2(), _type_subexpr_type_2())
347             )
348             )
349             {
350 3         8 @items = map _type_parse_tuples($_),
351             _type_regexp_eval($expr,
352             _type_regexp_groups(_type_subexpr_type_2(), _type_subexpr_type_2()));
353             }
354             # i.e. string | tuple[number, string]
355             elsif
356             (
357             _type_regexp_eval($expr,
358             _type_regexp(_type_subexpr_type_1(), _type_subexpr_type_2()))
359             )
360             {
361 4         12 @items = map _type_parse_tuples($_),
362             _type_regexp_eval($expr,
363             _type_regexp_groups(_type_subexpr_type_1(), _type_subexpr_type_2()));
364             }
365             # i.e. tuple[number, string] | string
366             elsif
367             (
368             _type_regexp_eval($expr,
369             _type_regexp(_type_subexpr_type_2(), _type_subexpr_type_1()))
370             )
371             {
372 3         13 @items = map _type_parse_tuples($_),
373             _type_regexp_eval($expr,
374             _type_regexp_groups(_type_subexpr_type_2(), _type_subexpr_type_1()));
375             }
376             # special condition: i.e. tuple[number, string]
377             elsif
378             (
379             _type_regexp_eval($expr, _type_regexp(_type_subexpr_type_2()))
380             )
381             {
382 49         118 @items = ($expr);
383             }
384             # i.e. "..." | tuple[number, string]
385             elsif
386             (
387             _type_regexp_eval($expr,
388             _type_regexp(_type_subexpr_type_3(), _type_subexpr_type_2()))
389             )
390             {
391 4         21 @items = _type_regexp_eval($expr,
392             _type_regexp_groups(_type_subexpr_type_3(), _type_subexpr_type_2()));
393 4         25 @items = (_type_parse_pipes($items[0]), _type_parse_tuples($items[1]));
394             }
395             # i.e. tuple[number, string] | "..."
396             elsif
397             (
398             _type_regexp_eval($expr,
399             _type_regexp(_type_subexpr_type_2(), _type_subexpr_type_3()))
400             )
401             {
402 3         9 @items = _type_regexp_eval($expr,
403             _type_regexp_groups(_type_subexpr_type_2(), _type_subexpr_type_3()));
404 3         14 @items = (_type_parse_tuples($items[0]), _type_parse_pipes($items[1]));
405             }
406             # i.e. Package::Name | "..."
407             elsif
408             (
409             _type_regexp_eval($expr,
410             _type_regexp(_type_subexpr_type_4(), _type_subexpr_type_3()))
411             )
412             {
413 61         165 @items = _type_regexp_eval($expr,
414             _type_regexp_groups(_type_subexpr_type_4(), _type_subexpr_type_3()));
415 61         353 @items = ($items[0], _type_parse_pipes($items[1]));
416             }
417             # i.e. "..." | Package::Name
418             elsif
419             (
420             _type_regexp_eval($expr,
421             _type_regexp(_type_subexpr_type_3(), _type_subexpr_type_4()))
422             )
423             {
424 0         0 @items = _type_regexp_eval($expr,
425             _type_regexp_groups(_type_subexpr_type_3(), _type_subexpr_type_4()));
426 0         0 @items = (_type_parse_pipes($items[0]), $items[1]);
427             }
428             # i.e. string | "..."
429             elsif
430             (
431             _type_regexp_eval($expr,
432             _type_regexp(_type_subexpr_type_1(), _type_subexpr_type_3()))
433             )
434             {
435 0         0 @items = _type_regexp_eval($expr,
436             _type_regexp_groups(_type_subexpr_type_1(), _type_subexpr_type_3()));
437 0         0 @items = ($items[0], _type_parse_pipes($items[1]));
438             }
439             # i.e. "..." | string
440             elsif
441             (
442             _type_regexp_eval($expr,
443             _type_regexp(_type_subexpr_type_3(), _type_subexpr_type_1()))
444             )
445             {
446 0         0 @items = _type_regexp_eval($expr,
447             _type_regexp_groups(_type_subexpr_type_3(), _type_subexpr_type_1()));
448 0         0 @items = (_type_parse_pipes($items[0]), $items[1]);
449             }
450             # i.e. "..." | "..."
451             elsif
452             (
453             _type_regexp_eval($expr,
454             _type_regexp(_type_subexpr_type_3(), _type_subexpr_type_3()))
455             )
456             {
457 0         0 @items = map _type_parse_pipes($_),
458             _type_regexp_eval($expr,
459             _type_regexp_groups(_type_subexpr_type_3(), _type_subexpr_type_3()));
460             }
461             else {
462 333         781 @items = ($expr);
463             }
464              
465 460         4816 return (@items);
466             }
467              
468             sub _type_parse_tuples {
469 27 100   27   182 map +(scalar(_type_regexp_eval($_,
470             _type_regexp(_type_subexpr_type_2(), _type_subexpr_type_2())))
471             ? (_type_parse_pipes($_))
472             : ($_)), @_
473             }
474              
475             sub _type_regexp {
476 4838     4838   5759 qr/^@{[_type_regexp_joined(@_)]}$/
  4838         7203  
477             }
478              
479             sub _type_regexp_eval {
480 4449     4449   21516 map {s/^\s+|\s+$//gr} ($_[0] =~ $_[1])
  286         1525  
481             }
482              
483             sub _type_regexp_groups {
484 78     78   115 qr/^@{[_type_regexp_joined(_type_subexpr_groups(@_))]}$/
  78         176  
485             }
486              
487             sub _type_regexp_joined {
488 4916     4916   6945 join(_type_subexpr_delimiter(), @_)
489             }
490              
491             sub _type_render {
492 77     77   141 my ($into, $data) = @_;
493              
494 77 100       165 if (ref $data eq 'HASH') {
495             $data = join ', ', map +(qq("$_"), _type_render($into, $$data{$_})),
496 33         45 sort keys %{$data};
  33         168  
497 33         97 $data = "$into\[$data\]";
498             }
499              
500 77 100       131 if (ref $data eq 'ARRAY') {
501 1 50       3 $data = join ', ', map +(/^\w+$/ ? qq("$_") : $_), @{$data};
  1         23  
502 1         7 $data = "$into\[$data\]";
503             }
504              
505 77         220 return $data;
506             }
507              
508             sub _type_subexpr_delimiter {
509 5049     5049   103989 '\s*\|\s*'
510             }
511              
512             sub _type_subexpr_groups {
513 78     78   365 map "($_)", @_
514             }
515              
516             sub _type_subexpr_type_1 {
517 1583     1583   2933 '\w+'
518             }
519              
520             sub _type_subexpr_type_2 {
521 4013     4013   8156 '\w+\s*\[.*\]+'
522             }
523              
524             sub _type_subexpr_type_3 {
525 2925     2925   5304 '.*'
526             }
527              
528             sub _type_subexpr_type_4 {
529 788     788   1466 '[A-Za-z][:\^\w]+\w*'
530             }
531              
532             1;
533              
534              
535              
536             =head1 NAME
537              
538             Venus::Assert - Assert Class
539              
540             =cut
541              
542             =head1 ABSTRACT
543              
544             Assert Class for Perl 5
545              
546             =cut
547              
548             =head1 SYNOPSIS
549              
550             package main;
551              
552             use Venus::Assert;
553              
554             my $assert = Venus::Assert->new('Float');
555              
556             # $assert->accept('float');
557              
558             # $assert->format(sub{sprintf('%.2f', $_)});
559              
560             # $assert->result(123.456);
561              
562             # 123.46
563              
564             =cut
565              
566             =head1 DESCRIPTION
567              
568             This package provides a mechanism for asserting type constraints and coercions
569             on data. Type constraints are handled via L, and coercions
570             are handled via L, using L to perform data type
571             validations.
572              
573             =cut
574              
575             =head1 ATTRIBUTES
576              
577             This package has the following attributes:
578              
579             =cut
580              
581             =head2 name
582              
583             name(string $data) (string)
584              
585             The name attribute is read-write, accepts C<(string)> values, and is
586             optional.
587              
588             I>
589              
590             =over 4
591              
592             =item name example 1
593              
594             # given: synopsis
595              
596             package main;
597              
598             my $set_name = $assert->name("Example");
599              
600             # "Example"
601              
602             =back
603              
604             =over 4
605              
606             =item name example 2
607              
608             # given: synopsis
609              
610             # given: example-1 name
611              
612             package main;
613              
614             my $get_name = $assert->name;
615              
616             # "Example"
617              
618             =back
619              
620             =cut
621              
622             =head1 INHERITS
623              
624             This package inherits behaviors from:
625              
626             L
627              
628             =cut
629              
630             =head1 INTEGRATES
631              
632             This package integrates behaviors from:
633              
634             L
635              
636             =cut
637              
638             =head1 METHODS
639              
640             This package provides the following methods:
641              
642             =cut
643              
644             =head2 accept
645              
646             accept(string $name, any @args) (Venus::Assert)
647              
648             The accept method registers a condition via L based on the arguments
649             provided. The built-in types are defined as methods in L.
650              
651             I>
652              
653             =over 4
654              
655             =item accept example 1
656              
657             # given: synopsis
658              
659             package main;
660              
661             $assert = $assert->accept('float');
662              
663             # bless(..., "Venus::Assert")
664              
665             # $assert->valid;
666              
667             # false
668              
669             # $assert->valid(1.01);
670              
671             # true
672              
673             =back
674              
675             =over 4
676              
677             =item accept example 2
678              
679             # given: synopsis
680              
681             package main;
682              
683             $assert = $assert->accept('number');
684              
685             # bless(..., "Venus::Assert")
686              
687             # $assert->valid(1.01);
688              
689             # false
690              
691             # $assert->valid(1_01);
692              
693             # true
694              
695             =back
696              
697             =over 4
698              
699             =item accept example 3
700              
701             # given: synopsis
702              
703             package Example1;
704              
705             sub new {
706             bless {};
707             }
708              
709             package Example2;
710              
711             sub new {
712             bless {};
713             }
714              
715             package main;
716              
717             $assert = $assert->accept('object');
718              
719             # bless(..., "Venus::Assert")
720              
721             # $assert->valid;
722              
723             # false
724              
725             # $assert->valid(qr//);
726              
727             # false
728              
729             # $assert->valid(Example1->new);
730              
731             # true
732              
733             # $assert->valid(Example2->new);
734              
735             # true
736              
737             =back
738              
739             =over 4
740              
741             =item accept example 4
742              
743             # given: synopsis
744              
745             package Example1;
746              
747             sub new {
748             bless {};
749             }
750              
751             package Example2;
752              
753             sub new {
754             bless {};
755             }
756              
757             package main;
758              
759             $assert = $assert->accept('Example1');
760              
761             # bless(..., "Venus::Assert")
762              
763             # $assert->valid;
764              
765             # false
766              
767             # $assert->valid(qr//);
768              
769             # false
770              
771             # $assert->valid(Example1->new);
772              
773             # true
774              
775             # $assert->valid(Example2->new);
776              
777             # false
778              
779             =back
780              
781             =cut
782              
783             =head2 check
784              
785             check(Venus::Check $data) (Venus::Check)
786              
787             The check method gets or sets the L object used for performing
788             runtime data type validation.
789              
790             I>
791              
792             =over 4
793              
794             =item check example 1
795              
796             # given: synopsis
797              
798             package main;
799              
800             my $check = $assert->check(Venus::Check->new);
801              
802             # bless(..., 'Venus::Check')
803              
804             =back
805              
806             =over 4
807              
808             =item check example 2
809              
810             # given: synopsis
811              
812             package main;
813              
814             $assert->check(Venus::Check->new);
815              
816             my $check = $assert->check;
817              
818             # bless(..., 'Venus::Check')
819              
820             =back
821              
822             =cut
823              
824             =head2 clear
825              
826             clear() (Venus::Assert)
827              
828             The clear method resets the L, L, and L
829             attributes and returns the invocant.
830              
831             I>
832              
833             =over 4
834              
835             =item clear example 1
836              
837             # given: synopsis
838              
839             package main;
840              
841             $assert->accept('string');
842              
843             $assert = $assert->clear;
844              
845             # bless(..., "Venus::Assert")
846              
847             =back
848              
849             =cut
850              
851             =head2 coerce
852              
853             coerce(any $data) (any)
854              
855             The coerce method dispatches to the L object and returns the result
856             of the L operation.
857              
858             I>
859              
860             =over 4
861              
862             =item coerce example 1
863              
864             # given: synopsis
865              
866             package main;
867              
868             $assert->accept('float');
869              
870             $assert->format(sub{sprintf('%.2f', $_)});
871              
872             my $coerce = $assert->coerce(123.456);
873              
874             # 123.46
875              
876             =back
877              
878             =over 4
879              
880             =item coerce example 2
881              
882             # given: synopsis
883              
884             package main;
885              
886             $assert->accept('string');
887              
888             $assert->format(sub{ucfirst lc $_});
889              
890             my $coerce = $assert->coerce('heLLo');
891              
892             # "Hello"
893              
894             =back
895              
896             =cut
897              
898             =head2 coercion
899              
900             coercion(Venus::Coercion $data) (Venus::Coercion)
901              
902             The coercion method gets or sets the L object used for
903             performing runtime data type coercions.
904              
905             I>
906              
907             =over 4
908              
909             =item coercion example 1
910              
911             # given: synopsis
912              
913             package main;
914              
915             my $coercion = $assert->coercion(Venus::Coercion->new);
916              
917             # bless(..., 'Venus::Coercion')
918              
919             =back
920              
921             =over 4
922              
923             =item coercion example 2
924              
925             # given: synopsis
926              
927             package main;
928              
929             $assert->coercion(Venus::Coercion->new);
930              
931             my $coercion = $assert->coercion;
932              
933             # bless(..., 'Venus::Coercion')
934              
935             =back
936              
937             =cut
938              
939             =head2 conditions
940              
941             conditions() (Venus::Assert)
942              
943             The conditions method is an object construction hook that allows subclasses to
944             configure the object on construction setting up constraints and coercions and
945             returning the invocant.
946              
947             I>
948              
949             =over 4
950              
951             =item conditions example 1
952              
953             # given: synopsis
954              
955             package main;
956              
957             $assert = $assert->conditions;
958              
959             # bless(..., 'Venus::Assert')
960              
961             =back
962              
963             =over 4
964              
965             =item conditions example 2
966              
967             package Example::Type::PositveNumber;
968              
969             use base 'Venus::Assert';
970              
971             sub conditions {
972             my ($self) = @_;
973              
974             $self->accept('number', sub {
975             $_ >= 0
976             });
977              
978             return $self;
979             }
980              
981             package main;
982              
983             my $assert = Example::Type::PositveNumber->new;
984              
985             # $assert->valid(0);
986              
987             # true
988              
989             # $assert->valid(1);
990              
991             # true
992              
993             # $assert->valid(-1);
994              
995             # false
996              
997             =back
998              
999             =cut
1000              
1001             =head2 constraint
1002              
1003             constraint(Venus::Constraint $data) (Venus::Constraint)
1004              
1005             The constraint method gets or sets the L object used for
1006             performing runtime data type constraints.
1007              
1008             I>
1009              
1010             =over 4
1011              
1012             =item constraint example 1
1013              
1014             # given: synopsis
1015              
1016             package main;
1017              
1018             my $constraint = $assert->constraint(Venus::Constraint->new);
1019              
1020             # bless(..., 'Venus::Constraint')
1021              
1022             =back
1023              
1024             =over 4
1025              
1026             =item constraint example 2
1027              
1028             # given: synopsis
1029              
1030             package main;
1031              
1032             $assert->constraint(Venus::Constraint->new);
1033              
1034             my $constraint = $assert->constraint;
1035              
1036             # bless(..., 'Venus::Constraint')
1037              
1038             =back
1039              
1040             =cut
1041              
1042             =head2 ensure
1043              
1044             ensure(coderef $code) (Venus::Assert)
1045              
1046             The ensure method registers a custom (not built-in) constraint condition and
1047             returns the invocant.
1048              
1049             I>
1050              
1051             =over 4
1052              
1053             =item ensure example 1
1054              
1055             # given: synopsis
1056              
1057             package main;
1058              
1059             $assert->accept('number');
1060              
1061             my $ensure = $assert->ensure(sub {
1062             $_ >= 0
1063             });
1064              
1065             # bless(.., "Venus::Assert")
1066              
1067             =back
1068              
1069             =cut
1070              
1071             =head2 expression
1072              
1073             expression(string $expr) (Venus::Assert)
1074              
1075             The expression method parses a string representation of an type assertion,
1076             registers the subexpressions using the L method, and returns the
1077             invocant.
1078              
1079             I>
1080              
1081             =over 4
1082              
1083             =item expression example 1
1084              
1085             # given: synopsis
1086              
1087             package main;
1088              
1089             $assert = $assert->expression('string');
1090              
1091             # bless(..., 'Venus::Assert')
1092              
1093             # $assert->valid('hello');
1094              
1095             # true
1096              
1097             # $assert->valid(['goodbye']);
1098              
1099             # false
1100              
1101             =back
1102              
1103             =over 4
1104              
1105             =item expression example 2
1106              
1107             # given: synopsis
1108              
1109             package main;
1110              
1111             $assert = $assert->expression('string | coderef');
1112              
1113             # bless(..., 'Venus::Assert')
1114              
1115             # $assert->valid('hello');
1116              
1117             # true
1118              
1119             # $assert->valid(sub{'hello'});
1120              
1121             # true
1122              
1123             # $assert->valid(['goodbye']);
1124              
1125             # false
1126              
1127             =back
1128              
1129             =over 4
1130              
1131             =item expression example 3
1132              
1133             # given: synopsis
1134              
1135             package main;
1136              
1137             $assert = $assert->expression('string | coderef | Venus::Assert');
1138              
1139             # bless(..., 'Venus::Assert')
1140              
1141             # $assert->valid('hello');
1142              
1143             # true
1144              
1145             # $assert->valid(sub{'hello'});
1146              
1147             # true
1148              
1149             # $assert->valid($assert);
1150              
1151             # true
1152              
1153             # $assert->valid(['goodbye']);
1154              
1155             # false
1156              
1157             =back
1158              
1159             =over 4
1160              
1161             =item expression example 4
1162              
1163             # given: synopsis
1164              
1165             package main;
1166              
1167             $assert = $assert->expression('Venus::Assert | within[arrayref, Venus::Assert]');
1168              
1169             # bless(..., 'Venus::Assert')
1170              
1171             # $assert->valid('hello');
1172              
1173             # false
1174              
1175             # $assert->valid(sub{'hello'});
1176              
1177             # false
1178              
1179             # $assert->valid($assert);
1180              
1181             # true
1182              
1183             # $assert->valid(['goodbye']);
1184              
1185             # false
1186              
1187             # $assert->valid([$assert]);
1188              
1189             # true
1190              
1191             =back
1192              
1193             =over 4
1194              
1195             =item expression example 5
1196              
1197             # given: synopsis
1198              
1199             package main;
1200              
1201             $assert = $assert->expression('
1202             string
1203             | within[
1204             arrayref, within[
1205             hashref, string
1206             ]
1207             ]
1208             ');
1209              
1210             # bless(..., 'Venus::Assert')
1211              
1212             # $assert->valid('hello');
1213              
1214             # true
1215              
1216             # $assert->valid(sub{'hello'});
1217              
1218             # false
1219              
1220             # $assert->valid($assert);
1221              
1222             # false
1223              
1224             # $assert->valid([]);
1225              
1226             # false
1227              
1228             # $assert->valid([{'test' => ['okay']}]);
1229              
1230             # false
1231              
1232             # $assert->valid([{'test' => 'okay'}]);
1233              
1234             # true
1235              
1236             =back
1237              
1238             =cut
1239              
1240             =head2 format
1241              
1242             format(coderef $code) (Venus::Assert)
1243              
1244             The format method registers a custom (not built-in) coercion condition and
1245             returns the invocant.
1246              
1247             I>
1248              
1249             =over 4
1250              
1251             =item format example 1
1252              
1253             # given: synopsis
1254              
1255             package main;
1256              
1257             $assert->accept('number');
1258              
1259             my $format = $assert->format(sub {
1260             sprintf '%.2f', $_
1261             });
1262              
1263             # bless(.., "Venus::Assert")
1264              
1265             =back
1266              
1267             =cut
1268              
1269             =head2 parse
1270              
1271             parse(string $expr) (any)
1272              
1273             The parse method accepts a string representation of a type assertion and
1274             returns a data structure representing one or more method calls to be used for
1275             validating the assertion signature.
1276              
1277             I>
1278              
1279             =over 4
1280              
1281             =item parse example 1
1282              
1283             # given: synopsis
1284              
1285             package main;
1286              
1287             my $parsed = $assert->parse('');
1288              
1289             # ['']
1290              
1291             =back
1292              
1293             =over 4
1294              
1295             =item parse example 2
1296              
1297             # given: synopsis
1298              
1299             package main;
1300              
1301             my $parsed = $assert->parse('any');
1302              
1303             # ['any']
1304              
1305             =back
1306              
1307             =over 4
1308              
1309             =item parse example 3
1310              
1311             # given: synopsis
1312              
1313             package main;
1314              
1315             my $parsed = $assert->parse('string | number');
1316              
1317             # ['either', 'string', 'number']
1318              
1319             =back
1320              
1321             =over 4
1322              
1323             =item parse example 4
1324              
1325             # given: synopsis
1326              
1327             package main;
1328              
1329             my $parsed = $assert->parse('enum[up,down,left,right]');
1330              
1331             # [['enum', 'up', 'down', 'left', 'right']]
1332              
1333             =back
1334              
1335             =over 4
1336              
1337             =item parse example 5
1338              
1339             # given: synopsis
1340              
1341             package main;
1342              
1343             my $parsed = $assert->parse('number | float | boolean');
1344              
1345             # ['either', 'number', 'float', 'boolean']
1346              
1347             =back
1348              
1349             =over 4
1350              
1351             =item parse example 6
1352              
1353             # given: synopsis
1354              
1355             package main;
1356              
1357             my $parsed = $assert->parse('Example');
1358              
1359             # ['Example']
1360              
1361             =back
1362              
1363             =over 4
1364              
1365             =item parse example 7
1366              
1367             # given: synopsis
1368              
1369             package main;
1370              
1371             my $parsed = $assert->parse('coderef | Venus::Code');
1372              
1373             # ['either', 'coderef', 'Venus::Code']
1374              
1375             =back
1376              
1377             =over 4
1378              
1379             =item parse example 8
1380              
1381             # given: synopsis
1382              
1383             package main;
1384              
1385             my $parsed = $assert->parse('tuple[number, arrayref, coderef]');
1386              
1387             # [['tuple', 'number', 'arrayref', 'coderef']]
1388              
1389             =back
1390              
1391             =over 4
1392              
1393             =item parse example 9
1394              
1395             # given: synopsis
1396              
1397             package main;
1398              
1399             my $parsed = $assert->parse('tuple[number, within[arrayref, hashref], coderef]');
1400              
1401             # [['tuple', 'number', ['within', 'arrayref', 'hashref'], 'coderef']]
1402              
1403             =back
1404              
1405             =over 4
1406              
1407             =item parse example 10
1408              
1409             # given: synopsis
1410              
1411             package main;
1412              
1413             my $parsed = $assert->parse(
1414             'tuple[number, within[arrayref, hashref] | arrayref, coderef]'
1415             );
1416              
1417             # [
1418             # ['tuple', 'number',
1419             # ['either', ['within', 'arrayref', 'hashref'], 'arrayref'], 'coderef']
1420             # ]
1421              
1422              
1423              
1424              
1425             =back
1426              
1427             =over 4
1428              
1429             =item parse example 11
1430              
1431             # given: synopsis
1432              
1433             package main;
1434              
1435             my $parsed = $assert->parse(
1436             'hashkeys["id", number | float, "upvotes", within[arrayref, boolean]]'
1437             );
1438              
1439             # [[
1440             # 'hashkeys',
1441             # 'id',
1442             # ['either', 'number', 'float'],
1443             # 'upvotes',
1444             # ['within', 'arrayref', 'boolean']
1445             # ]]
1446              
1447             =back
1448              
1449             =cut
1450              
1451             =head2 render
1452              
1453             render(string $into, string $expression) (string)
1454              
1455             The render method builds and returns a type expressions suitable for providing
1456             to L based on the data provided.
1457              
1458             I>
1459              
1460             =over 4
1461              
1462             =item render example 1
1463              
1464             # given: synopsis
1465              
1466             package main;
1467              
1468             $assert = $assert->render;
1469              
1470             # undef
1471              
1472             =back
1473              
1474             =over 4
1475              
1476             =item render example 2
1477              
1478             # given: synopsis
1479              
1480             package main;
1481              
1482             $assert = $assert->render(undef, 'string');
1483              
1484             # "string"
1485              
1486             =back
1487              
1488             =over 4
1489              
1490             =item render example 3
1491              
1492             # given: synopsis
1493              
1494             package main;
1495              
1496             $assert = $assert->render('routines', ['say', 'say_pretty']);
1497              
1498             # 'routines["say", "say_pretty"]'
1499              
1500             =back
1501              
1502             =over 4
1503              
1504             =item render example 4
1505              
1506             # given: synopsis
1507              
1508             package main;
1509              
1510             $assert = $assert->render('hashkeys', {id => 'number', name => 'string'});
1511              
1512             # 'hashkeys["id", number, "name", string]'
1513              
1514             =back
1515              
1516             =over 4
1517              
1518             =item render example 5
1519              
1520             # given: synopsis
1521              
1522             package main;
1523              
1524             $assert = $assert->render('hashkeys', {
1525             id => 'number',
1526             profile => {
1527             level => 'string',
1528             },
1529             });
1530              
1531             # 'hashkeys["id", number, "profile", hashkeys["level", string]]'
1532              
1533             =back
1534              
1535             =cut
1536              
1537             =head2 result
1538              
1539             result(any $data) (any)
1540              
1541             The result method validates the value provided against the registered
1542             constraints and if valid returns the result of the value having any registered
1543             coercions applied. If the value is invalid an exception from L
1544             will be thrown.
1545              
1546             I>
1547              
1548             =over 4
1549              
1550             =item result example 1
1551              
1552             # given: synopsis
1553              
1554             package main;
1555              
1556             $assert->accept('number')->format(sub{sprintf '%.2f', $_});
1557              
1558             my $result = $assert->result(1);
1559              
1560             # "1.00"
1561              
1562             =back
1563              
1564             =over 4
1565              
1566             =item result example 2
1567              
1568             # given: synopsis
1569              
1570             package main;
1571              
1572             $assert->accept('number')->format(sub{sprintf '%.2f', $_});
1573              
1574             my $result = $assert->result('hello');
1575              
1576             # Exception! (isa Venus::Check::Error) (see error_on_coded)
1577              
1578             =back
1579              
1580             =cut
1581              
1582             =head2 valid
1583              
1584             valid(any $data) (any)
1585              
1586             The valid method dispatches to the L object and returns the result
1587             of the L operation.
1588              
1589             I>
1590              
1591             =over 4
1592              
1593             =item valid example 1
1594              
1595             # given: synopsis
1596              
1597             package main;
1598              
1599             $assert->accept('float');
1600              
1601             $assert->ensure(sub{$_ >= 1});
1602              
1603             my $valid = $assert->valid('1.00');
1604              
1605             # true
1606              
1607             =back
1608              
1609             =over 4
1610              
1611             =item valid example 2
1612              
1613             # given: synopsis
1614              
1615             package main;
1616              
1617             $assert->accept('float');
1618              
1619             $assert->ensure(sub{$_ >= 1});
1620              
1621             my $valid = $assert->valid('0.99');
1622              
1623             # false
1624              
1625             =back
1626              
1627             =cut
1628              
1629             =head2 validate
1630              
1631             validate(any $data) (any)
1632              
1633             The validate method validates the value provided against the registered
1634             constraints and if valid returns the value. If the value is invalid an
1635             exception from L will be thrown.
1636              
1637             I>
1638              
1639             =over 4
1640              
1641             =item validate example 1
1642              
1643             # given: synopsis
1644              
1645             package main;
1646              
1647             $assert->accept('number');
1648              
1649             my $validate = $assert->validate(1);
1650              
1651             # 1
1652              
1653             =back
1654              
1655             =over 4
1656              
1657             =item validate example 2
1658              
1659             # given: synopsis
1660              
1661             package main;
1662              
1663             $assert->accept('number');
1664              
1665             my $validate = $assert->validate('hello');
1666              
1667             # Exception! (isa Venus::Check::Error) (see error_on_coded)
1668              
1669             =back
1670              
1671             =cut
1672              
1673             =head2 validator
1674              
1675             validator(any @args) (coderef)
1676              
1677             The validator method returns a coderef which calls the L method with
1678             the invocant when called.
1679              
1680             I>
1681              
1682             =over 4
1683              
1684             =item validator example 1
1685              
1686             # given: synopsis
1687              
1688             package main;
1689              
1690             $assert->accept('string');
1691              
1692             my $validator = $assert->validator;
1693              
1694             # sub{...}
1695              
1696             # my $result = $validator->();
1697              
1698             # Exception! (isa Venus::Check::Error) (see error_on_coded)
1699              
1700             =back
1701              
1702             =over 4
1703              
1704             =item validator example 2
1705              
1706             # given: synopsis
1707              
1708             package main;
1709              
1710             $assert->accept('string');
1711              
1712             my $validator = $assert->validator;
1713              
1714             # sub{...}
1715              
1716             # my $result = $validator->('hello');
1717              
1718             # "hello"
1719              
1720             =back
1721              
1722             =cut
1723              
1724             =head1 AUTHORS
1725              
1726             Awncorp, C
1727              
1728             =cut
1729              
1730             =head1 LICENSE
1731              
1732             Copyright (C) 2000, Awncorp, C.
1733              
1734             This program is free software, you can redistribute it and/or modify it under
1735             the terms of the Apache license version 2.0.
1736              
1737             =cut