|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_ANY;  | 
| 
2
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
8
 | 
 sub new { my $class = shift; bless {@_}, $class }  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
    | 
| 
3
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
19
 | 
 sub optional { shift->{optional} }  | 
| 
4
 | 
84
 | 
 
 | 
 
 | 
  
84
  
 | 
 
 | 
364
 | 
 sub nillable { shift->{nillable} }  | 
| 
5
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
395
 | 
 sub empty    { shift->{empty} }  | 
| 
6
 | 
70
 | 
  
100
  
 | 
 
 | 
  
70
  
 | 
 
 | 
89
 | 
 sub error { my $self = shift; $self->{error} = shift if @_; $self->{error} }  | 
| 
 
 | 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
128
 | 
    | 
| 
 
 | 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
185
 | 
    | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub pattern {  | 
| 
8
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
 
 | 
25
 | 
     my $self         = shift;  | 
| 
9
 | 
18
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
27
 | 
     $self->{pattern} = shift if @_;  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $self->{pattern}  | 
| 
11
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
114
 | 
 }  | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
13
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
13
 | 
     my ($self, $value, $path) = @_;  | 
| 
14
 | 
6
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
10
 | 
     return 1 if ($self->nillable and not defined $value)  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($self->empty and defined $value and !ref $value and $value eq '')  | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or (defined $value && !$self->pattern)  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($self->pattern && $value =~ $self->pattern);  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
3
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
18
 | 
     $self->error("Value '$value' does not match at path " . ($path || '/'));  | 
| 
20
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     return 0;  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_WORD;  | 
| 
24
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
1292331
 | 
 use base 'IV_ANY';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1876
 | 
    | 
| 
25
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
14
 | 
 sub new { my $class = shift; bless {@_}, $class }  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
27
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
15
 | 
     my ($self, $value, $path) = @_;  | 
| 
28
 | 
6
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
20
 | 
     return 1 if ($self->nillable and not defined $value)  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($self->empty and defined $value and !ref $value and $value eq '')  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($value =~ /^\w+$/);  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
30
 | 
     $self->error("Value '$value' does not match word characters only at path " . ($path || '/'));  | 
| 
33
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     return 0;  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_FLOAT;  | 
| 
37
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
28
 | 
 use base 'IV_ANY';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1321
 | 
    | 
| 
38
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
11
 | 
 sub new { my $class = shift; bless {@_}, $class }  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
55
 | 
    | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
40
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
14
 | 
     my ($self, $value, $path) = @_;  | 
| 
41
 | 
4
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
19
 | 
     return 1 if ($self->nillable and not defined $value)  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($self->empty and defined $value and !ref $value and $value eq '')  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($value =~ /^-?\d+\.\d+$/);  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
45
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
23
 | 
     $self->error("Value '$value' is not a float at path " . ($path || '/'));  | 
| 
46
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     return 0;  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_INT;  | 
| 
50
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
32
 | 
 use base 'IV_ANY';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1385
 | 
    | 
| 
51
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
19
 | 
 sub new { my $class = shift; bless {@_}, $class }  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
    | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
53
 | 
11
 | 
 
 | 
 
 | 
  
11
  
 | 
 
 | 
27
 | 
     my ($self, $value, $path) = @_;  | 
| 
54
 | 
11
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
27
 | 
     return 1 if ($self->nillable and not defined $value)  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($self->empty and defined $value and !ref $value and $value eq '')  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($value =~ /^-?\d+$/);  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
58
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
18
 | 
     $self->error("Value '$value' is not an integer at path " . ($path || '/'));  | 
| 
59
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     return 0;  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_BOOL;  | 
| 
63
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
25
 | 
 use base 'IV_ANY';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1298
 | 
    | 
| 
64
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
19
 | 
 sub new { my $class = shift; bless {@_}, $class }  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
    | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
66
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
 
 | 
19
 | 
     my ($self, $value, $path) = @_;  | 
| 
67
 | 
10
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
15
 | 
     return 1 if ($self->nillable and not defined $value)  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($self->empty and defined $value and !ref $value and $value eq '')  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or (ref($value) =~ /^JSON::PP::Boolean$/);  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
71
 | 
2
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
16
 | 
     my $val = ref $value || $value;  | 
| 
72
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
16
 | 
     $self->error("Value '$val' is not a boolean at path " . ($path || '/'));  | 
| 
73
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     return 0;  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_ARRAY;  | 
| 
77
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
28
 | 
 use base 'IV_ANY';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2168
 | 
    | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
79
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
6
 | 
     my $class     = shift;  | 
| 
80
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my $options   = {};  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
82
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     while (@_) {  | 
| 
83
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         my $elem = shift;  | 
| 
84
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
         if (ref $elem eq 'ARRAY') {  | 
| 
85
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
             $options->{pattern} = $elem;  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         else {  | 
| 
88
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
             $options->{$elem} = shift;  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     bless $options, $class  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
95
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
9
 | 
     my ($self, $value, $path) = @_;  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
97
 | 
4
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
10
 | 
     return 1 if $self->nillable and not defined $value;  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
99
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     unless (ref $value eq 'ARRAY') {  | 
| 
100
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
         $self->error("Array expected at path " . ($path || '/'));  | 
| 
101
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return 0;  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
104
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     my $elems = scalar @$value;  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
106
 | 
4
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
15
 | 
     if (defined $self->{max} && $elems > $self->{max}) {  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $self->error(sprintf("Too many elements in array (%d vs %d) at path %s",  | 
| 
108
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
             $elems, $self->{max}, $path || '/'));  | 
| 
109
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return 0;  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
112
 | 
4
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
10
 | 
     if (defined $self->{min} && $elems < $self->{min}) {  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $self->error(sprintf("Too few elements in array (%d vs %d) at path %s",  | 
| 
114
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
             $elems, $self->{min}, $path || '/'));  | 
| 
115
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return 0;  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
118
 | 
4
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
18
 | 
     if ($self->{of}) {  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
3
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
18
 | 
         for (my $i = 0; $i < ($self->{max} // $elems); $i++) {  | 
| 
120
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
             my $err = Mojolicious::Plugin::InputValidation::_validate_structure($value->[$i], $self->{of}, "$path/$i");  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
122
 | 
7
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
23
 | 
             if ($err) {  | 
| 
123
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
                 $self->error($err);  | 
| 
124
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
                 return 0;  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     elsif ($self->{pattern} && !$self->{min} && !$self->{min}) {  | 
| 
129
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
         for (my $i = 0; $i < scalar @{$self->{pattern}}; $i++) {  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
130
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             my $err = Mojolicious::Plugin::InputValidation::_validate_structure($value->[$i], $self->{pattern}[$i], "$path/$i");  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
132
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
             if ($err) {  | 
| 
133
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $self->error($err);  | 
| 
134
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 return 0;  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else {  | 
| 
139
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
         $self->error('Error: illegal pattern for array at path ' . ($path // '/'));  | 
| 
140
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return 0;  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
143
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     return 1;  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_OBJECT;  | 
| 
147
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
43
 | 
 use base 'IV_ANY';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1997
 | 
    | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
149
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
58
 | 
     my $class     = shift;  | 
| 
150
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
     my $options   = {};  | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
152
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
98
 | 
     while (@_) {  | 
| 
153
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
65
 | 
         my $elem = shift;  | 
| 
154
 | 
40
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
87
 | 
         if (ref $elem eq 'HASH') {  | 
| 
155
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
131
 | 
             $options->{pattern} = $elem;  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         else {  | 
| 
158
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $options->{$elem} = shift;  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
162
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
95
 | 
     bless $options, $class  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
165
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
90
 | 
     my ($self, $value, $path) = @_;  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
167
 | 
40
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
90
 | 
     return 1 if $self->nillable and not defined $value;  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
169
 | 
40
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
108
 | 
     unless (ref $value eq 'HASH') {  | 
| 
170
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
         $self->error("Object expected at path " . ($path || '/'));  | 
| 
171
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return 0;  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
174
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
172
 | 
     my @have_keys  = sort keys %$value;  | 
| 
175
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68
 | 
     my @want_keys  = sort keys %{$self->{pattern}};  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110
 | 
    | 
| 
176
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
82
 | 
     my %want_keys  = map { $_ => 1 } @want_keys;  | 
| 
 
 | 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
146
 | 
    | 
| 
177
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
63
 | 
     my %have_keys  = map { $_ => 1 } @have_keys;  | 
| 
 
 | 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
111
 | 
    | 
| 
178
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
65
 | 
     my @unexpected = grep { !$want_keys{$_} } @have_keys;  | 
| 
 
 | 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
188
 | 
    | 
| 
179
 | 
40
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
65
 | 
     my @missing    = grep { !$have_keys{$_} && !$self->{pattern}{$_}->optional } @want_keys;  | 
| 
 
 | 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
152
 | 
    | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
181
 | 
40
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
78
 | 
     if (@unexpected) {  | 
| 
182
 | 
1
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
13
 | 
         $self->error(sprintf("Unexpected keys '%s' found at path %s", join(',', @unexpected), $path || '/'));  | 
| 
183
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         return 0;  | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
186
 | 
39
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
88
 | 
     if (@missing) {  | 
| 
187
 | 
1
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
11
 | 
         $self->error(sprintf("Missing keys '%s' at path %s", join(',', @missing), $path || '/'));  | 
| 
188
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         return 0;  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
191
 | 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
     for my $key (grep { $have_keys{$_} } @want_keys) {  | 
| 
 
 | 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
100
 | 
    | 
| 
192
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
167
 | 
         my $err = Mojolicious::Plugin::InputValidation::_validate_structure($value->{$key}, $self->{pattern}{$key}, "$path/$key");  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
194
 | 
50
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
125
 | 
         if ($err) {  | 
| 
195
 | 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
             $self->error($err);  | 
| 
196
 | 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
             return 0;  | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
200
 | 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
     return 1;  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IV_DATETIME;  | 
| 
204
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
25
 | 
 use base 'IV_ANY';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1447
 | 
    | 
| 
205
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
10
 | 
 sub new { my $class = shift; bless {@_}, $class }  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
    | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub pattern {  | 
| 
207
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
7
 | 
     my $self         = shift;  | 
| 
208
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     $self->{pattern} = shift if @_;  | 
| 
209
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
42
 | 
     $self->{pattern} || qr/^20\d\d-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d\d\d)?(Z|[+-]\d\d\d\d)$/  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub accepts {  | 
| 
212
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
6
 | 
     my ($self, $value, $path) = @_;  | 
| 
213
 | 
3
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
9
 | 
     return 1 if ($self->nillable and not defined $value)  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($self->empty and defined $value and !ref $value and $value eq '')  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              or ($value =~ $self->pattern);  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
217
 | 
1
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
12
 | 
     $self->error("Value '$value' does not match datetime format at path " . ($path || '/'));  | 
| 
218
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     return 0;  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Mojolicious::Plugin::InputValidation;  | 
| 
222
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
598
 | 
 use Mojo::Base 'Mojolicious::Plugin';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
199935
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
    | 
| 
223
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
1582
 | 
 no strict 'subs';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
159
 | 
    | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '0.09';  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
227
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
32
 | 
 use Mojo::Util 'monkey_patch';  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2592
 | 
    | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
229
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
116
 | 
 sub iv_datetime { IV_DATETIME->new(@_) }  | 
| 
230
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
105
 | 
 sub iv_object   { IV_OBJECT->new(@_) }  | 
| 
231
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
14
 | 
 sub iv_array    { IV_ARRAY->new(@_) }  | 
| 
232
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
48951
 | 
 sub iv_int      { IV_INT->new(@_) }  | 
| 
233
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
32
 | 
 sub iv_float    { IV_FLOAT->new(@_) }  | 
| 
234
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
43212
 | 
 sub iv_bool     { IV_BOOL->new(@_) }  | 
| 
235
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
38
 | 
 sub iv_word     { IV_WORD->new(@_) }  | 
| 
236
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
20
 | 
 sub iv_any      { IV_ANY->new(@_) }  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub import {  | 
| 
239
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
39
 | 
     my $caller = caller;  | 
| 
240
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     monkey_patch $caller, 'iv_datetime', \&iv_datetime;  | 
| 
241
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
     monkey_patch $caller, 'iv_object',   \&iv_object;  | 
| 
242
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
     monkey_patch $caller, 'iv_array',    \&iv_array;  | 
| 
243
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
     monkey_patch $caller, 'iv_int',      \&iv_int;  | 
| 
244
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
     monkey_patch $caller, 'iv_float',    \&iv_float;  | 
| 
245
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
     monkey_patch $caller, 'iv_bool',     \&iv_bool;  | 
| 
246
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
     monkey_patch $caller, 'iv_word',     \&iv_word;  | 
| 
247
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
     monkey_patch $caller, 'iv_any',      \&iv_any;  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub register {  | 
| 
251
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
432
 | 
     my ($self, $app, $conf) = @_;  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $app->helper(validate_json_request => sub {  | 
| 
254
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
 
 | 
122
 | 
         my ($c, $pattern) = @_;  | 
| 
255
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
         return _validate_structure($c->req->json, $pattern);  | 
| 
256
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     });  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $app->helper(validate_params => sub {  | 
| 
258
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
         my ($c, $pattern) = @_;  | 
| 
259
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return _validate_structure($c->params, $pattern);  | 
| 
260
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
353
 | 
     });  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $app->helper(validate_structure => sub {  | 
| 
262
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
         my ($c, $structure, $pattern) = @_;  | 
| 
263
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return _validate_structure($structure, $pattern);  | 
| 
264
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
183
 | 
     });  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _validate_structure {  | 
| 
268
 | 
84
 | 
 
 | 
 
 | 
  
84
  
 | 
 
 | 
2303
 | 
     my ($input, $pattern, $path) = @_;  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
270
 | 
84
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
220
 | 
     if (ref $pattern eq 'HASH') {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
271
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
         $pattern = iv_object($pattern);  | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     elsif (ref $pattern eq 'ARRAY') {  | 
| 
274
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
         $pattern = iv_array($pattern);  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
277
 | 
84
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
233
 | 
     return sprintf("Error: pattern '%s' must be of kind iv_*", $pattern)  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         unless UNIVERSAL::isa($pattern, IV_ANY);  | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
280
 | 
84
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
285
 | 
     return $pattern->error unless $pattern->accepts($input, $path // '');  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
282
 | 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
181
 | 
     return '';  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =encoding utf8  | 
| 
286
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Mojolicious::Plugin::InputValidation - Validate incoming requests  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use Mojolicious::Lite;  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   plugin 'InputValidation';  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # This needs to be done where one wants to use the iv_* routines.  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use Mojolicious::Plugin::InputValidation;  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   post '/books' => sub {  | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       my $c = shift;  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # Validate incoming requests against our data model.  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       if (my $error = $c->validate_json_request({  | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           title    => iv_any,  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           abstract => iv_any(optional => 1, empty => 1),  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           author   => {  | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               firstname => iv_word,  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               lastname  => iv_word,  | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           },  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           published => iv_datetime,  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           price     => iv_float,  | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           revision  => iv_int,  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           isbn      => iv_any(pattern => qr/^[0-9\-]{10,13}$/),  | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           advertise => iv_bool,  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       })) {  | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           return $c->render(status => 400, text => $error);  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # Now the payload is safe to use.  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       my $payload = $c->req->json;  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       ...  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   };  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L compares structures against a pattern.  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The pattern is usually a nested structure, so the compare methods search  | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 recursively for the first non-matching value. If such a value is found a  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 speaking error message is returned, otherwise a false value.  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 METHODS  | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L adds methods to the connection object  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 in a mojolicous controller. This way input validation becomes easy.  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 validate_json_request  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $error = $c->validate_json_request($pattern);  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This method try to match the json request payload ($c->req->json) against the  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 given pattern. If the payload matches, a false value is returned. If the payload  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 on the other hand does not match the pattern, the first non-matching value is  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 returned along with a speaking error message. The error message could look like:  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   "Unexpected keys 'id,name' found at path /author"  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 TYPES  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The pattern consists of one or more types the input is matched against.  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The following types are available.  | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_any  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This is the base type for all other types. By default it matches defined values  | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 only. It supports beeing optional, means that it is okay if this element is  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 missing entirely in the payload.  | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 When this type is marked as nillable, it also accepts a null/undef value.  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 To accept an empty string, mark it as empty.  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This type supports a regex pattern to match against. All options can be combined.  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo  => iv_any,  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar  => iv_any(optional => 1, empty => 1),  | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz  => iv_any(nillable => 1),  | 
| 
367
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       quux => iv_any(pattern => qr/^new|mint|used$/),  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_int  | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This type matches integers, literally digits with an optional leading dash.  | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo => iv_int,  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar => iv_int(optional => 1),  | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz => iv_int(nillable => 1),  | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_float  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This type matches floats, so digits divided by a single dot, with an optional  | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 leading dash.  | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo => iv_float,  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar => iv_float(optional => 1),  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz => iv_float(nillable => 1),  | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_bool  | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This type matches booleans: true and false.  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo => iv_bool,  | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar => iv_bool(optional => 1),  | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz => iv_bool(nillable => 1),  | 
| 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
400
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
401
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_word  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This type is meant to match identifiers. It matches word character strings (\w+).  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Using the iv_any type one can achieve the same with: iv_any(pattern => qr/^\w+$/)  | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 To accept an empty string, mark it as empty.  | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
407
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo => iv_word,  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar => iv_word(optional => 1, empty => 1),  | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz => iv_word(nillable => 1),  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_datetime  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This type matches datetime strings in the following format:  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   YYYY-mm-DDTHH:mm:ssZ  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   YYYY-mm-DDTHH:mm:ss-0100  | 
| 
419
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   YYYY-mm-DDTHH:mm:ss+0000  | 
| 
420
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   YYYY-mm-DDTHH:mm:ss+0100  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   YYYY-mm-DDTHH:mm:ss.uuu+0100  | 
| 
422
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 It also supports a regex pattern, but that kinda defeats the purpose of this type.  | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo  => iv_datetime,  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar  => iv_datetime(optional => 1),  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz  => iv_datetime(nillable => 1),  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       quux => iv_datetime(pattern => qr/^\d\d\d\d-\d\d-\d\d$/,  | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_object  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This types matches objects (hashes). It will recurse into the elements it contains.  | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A hash as a pattern is automatically turned into a iv_object. Using a hash is the  | 
| 
436
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 idiomatic way, unless you need to mark it as optional or nillable.  | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
439
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo => { ... },  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar => iv_object(optional => 1, { ... }),  | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz => iv_object(nillable => 1, { ... }),  | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item iv_array - will match arrays  | 
| 
445
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This type will match arrays in two different ways. For one it can match a payload  | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 against a fixed shape, and second it can match against an elemnt base type.  | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A literal array reference ([]) is turned into an iv_array of the first kind  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 automatically. The following is valid:  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
451
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   {  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       foo  => [iv_int, iv_word, ...],  | 
| 
453
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       bar  => iv_array(optional => 1, [iv_int, iv_word, ...]),  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       baz  => iv_array(nillable => 1, [iv_int, iv_word, ...]),  | 
| 
455
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       quux => iv_array(of => iv_int, min => 1, max => 7),  | 
| 
456
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
458
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 ALERT  | 
| 
461
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This plugin is in alpha state, means it might not work at all or not as advertised.  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
464
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SEE ALSO  | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L, L, L.  | 
| 
467
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 LICENSE AND COPYRIGHT  | 
| 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Copyright 2018 Tobias Leich.  | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This program is free software; you can redistribute it and/or modify it  | 
| 
473
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 under the terms of the the Artistic License (2.0). You may obtain a  | 
| 
474
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 copy of the full license at:  | 
| 
475
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
477
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
478
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Any use, modification, and distribution of the Standard or Modified  | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Versions is governed by this Artistic License. By using, modifying or  | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 distributing the Package, you accept this license. Do not use, modify,  | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 or distribute the Package, if you do not accept this license.  | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
483
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If your Modified Version has been derived from a Modified Version made  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 by someone other than you, you are nevertheless required to ensure that  | 
| 
485
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 your Modified Version complies with the requirements of this license.  | 
| 
486
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
487
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This license does not grant you the right to use any trademark, service  | 
| 
488
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 mark, tradename, or logo of the Copyright Holder.  | 
| 
489
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
490
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This license includes the non-exclusive, worldwide, free-of-charge  | 
| 
491
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 patent license to make, have made, use, offer to sell, sell, import and  | 
| 
492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 otherwise transfer the Package with respect to any patent claims  | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 licensable by the Copyright Holder that are necessarily infringed by the  | 
| 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Package. If you institute patent litigation (including a cross-claim or  | 
| 
495
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 counterclaim) against any party alleging that the Package constitutes  | 
| 
496
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 direct or contributory patent infringement, then this Artistic License  | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 to you shall terminate on the date that such litigation is filed.  | 
| 
498
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER  | 
| 
500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.  | 
| 
501
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR  | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY  | 
| 
503
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR  | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR  | 
| 
505
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,  | 
| 
506
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  |