File Coverage

blib/lib/Data/Validator/Recursive.pm
Criterion Covered Total %
statement 86 86 100.0
branch 36 40 90.0
condition 3 5 60.0
subroutine 13 13 100.0
pod 7 7 100.0
total 145 151 96.0


line stmt bran cond sub pod time code
1             package Data::Validator::Recursive;
2              
3 4     4   142579 use strict;
  4         11  
  4         148  
4 4     4   23 use warnings;
  4         7  
  4         113  
5 4     4   109 use 5.008_001;
  4         24  
  4         233  
6             our $VERSION = '0.06';
7              
8 4     4   24 use Carp 'croak';
  4         8  
  4         353  
9 4     4   4049 use Data::Validator;
  4         178220  
  4         3922  
10              
11             sub new {
12 26     26 1 26608 my ($class, @args) = @_;
13 26 100       275 croak "Usage: Data::Validator::Recursive->new(\$arg_name => \$rule [, ... ])" unless @args;
14              
15 25   66     222 my $self = bless {
16             validator => undef,
17             nested_validators => [],
18             error => undef,
19             }, ref $class || $class;
20              
21 25         102 $self->_build_rules(@args);
22 24         58491 return $self;
23             }
24              
25             sub _build_rules {
26 25     25   66 my ($self, @args) = @_;
27              
28 25         106 for (my ($i, $l) = (0, scalar @args); $i < $l; $i += 2) {
29 57         119 my ($name, $rule) = @args[$i, $i+1];
30 57 100       182 $rule = { isa => $rule } unless ref $rule eq 'HASH';
31              
32 57 100       232 if (my $nested_rule = delete $rule->{rule}) {
33 13 100       67 if (ref $nested_rule eq 'HASH') {
    100          
34 1         6 $nested_rule = [ %$nested_rule ];
35             }
36             elsif (ref $nested_rule ne 'ARRAY') {
37 1         176 croak "$name.rule must be ARRAY or HASH";
38             }
39              
40 12   50     50 $rule->{isa} ||= 'HashRef';
41 12         37 my $with = delete $rule->{with};
42 12         52 my $validator = $self->new(@$nested_rule);
43 12 100       46 if ($with) {
44 2 50       13 $with = [ $with ] unless ref $with eq 'ARRAY';
45 2         14 $validator->with(@$with);
46             }
47              
48 12         22 push @{ $self->{nested_validators} }, {
  12         106  
49             name => $name,
50             validator => $validator,
51             };
52             }
53             }
54              
55 24         230 $self->{validator} = Data::Validator->new(@args)->with('NoThrow');
56             }
57              
58             sub with {
59 4     4 1 18 my ($self, @extentions) = @_;
60 4         49 $self->{validator}->with(@extentions);
61 4         7486 return $self;
62             }
63              
64             sub validate {
65 31     31 1 20873 my ($self, $params, $_parent_name) = @_;
66 31         68 $self->{errors} = undef;
67              
68 31         193 my ($result) = $self->{validator}->validate($params);
69 31 100       3201 if (my $errors = $self->{validator}->clear_errors) {
70 9 100       39 $self->{errors} = [
71             map {
72 6         16 my $name = $_parent_name ? "$_parent_name.$_->{name}" : $_->{name};
73 9         19 my $type = $_->{type};
74 9         14 my ($message, $other_name);
75 9 100       26 if ($type eq 'ExclusiveParameter') {
76 2 50       11 $other_name = $_parent_name
77             ? "$_parent_name.$_->{conflict}" : $_->{conflict};
78 2         12 $message = sprintf q{'%s' and '%s' is %s}, $name, $other_name, $type;
79             }
80             else {
81 7         25 $message = sprintf q{'%s' is %s}, $name, $type;
82             }
83              
84             +{
85 9 100       60 type => $type,
86             name => $name,
87             message => $message,
88             defined $other_name ? (conflict => $other_name) : (),
89             };
90             } @$errors
91             ];
92 6         24 return;
93             }
94              
95 25         41 for my $rule (@{ $self->{nested_validators} }) {
  25         78  
96 15         36 my $name = $rule->{name};
97 15 50       55 next unless exists $result->{$name};
98              
99 15         34 my $validator = $rule->{validator};
100              
101 15         20 my $result_in_nested;
102 15 100       57 if (ref $result->{$name} eq 'ARRAY') {
103 9         32 $result_in_nested = [];
104 9         16 my $i = 0;
105 9         17 for my $child_params (@{ $result->{$name} }) {
  9         27  
106 10         49 my $indexed_name = sprintf('%s[%d]', $name, $i++);
107 10 100       66 my ($child_result) = $validator->validate($child_params, $_parent_name ? "$_parent_name.$indexed_name" : $indexed_name);
108 10 100       43 if (my $errors = $validator->errors) {
109 3         6 $self->{errors} = $errors;
110 3         24 return;
111             }
112 7         21 push @$result_in_nested, $child_result;
113             }
114             }
115             else {
116 6 50       31 ($result_in_nested) = $validator->validate($result->{$name}, $_parent_name ? "$_parent_name.$name" : $name);
117             }
118              
119 12 100       36 if (my $errors = $validator->errors) {
120 2         3 $self->{errors} = $errors;
121 2         13 return;
122             } else {
123 10         57 $result->{$name} = $result_in_nested;
124             }
125             }
126              
127 20         58 return $result;
128             }
129              
130             sub error {
131 15     15 1 31 my $self = shift;
132 15 100       118 my $errors = $self->errors or return;
133 6         55 $errors->[0];
134             }
135              
136             sub errors {
137 58     58 1 96 my $self = shift;
138 58         300 $self->{errors};
139             }
140              
141             sub has_error {
142 19     19 1 16473 my $self = shift;
143 19 100       115 $self->{errors} ? 1 : 0;
144             }
145              
146             sub clear_errors {
147 15     15 1 35 my $self = shift;
148 15         79 delete $self->{errors};
149             }
150              
151             1;
152             __END__