File Coverage

blib/lib/Data/Rx/CoreType/rec.pm
Criterion Covered Total %
statement 47 47 100.0
branch 21 22 95.4
condition 12 12 100.0
subroutine 7 7 100.0
pod 0 3 0.0
total 87 91 95.6


line stmt bran cond sub pod time code
1 1     1   11 use v5.12.0;
  1         4  
2 1     1   5 use warnings;
  1         2  
  1         40  
3             package Data::Rx::CoreType::rec 0.200008;
4             # ABSTRACT: the Rx //rec type
5              
6 1     1   5 use parent 'Data::Rx::CoreType';
  1         1  
  1         6  
7              
8 1     1   50 use Scalar::Util ();
  1         11  
  1         639  
9              
10 70     70 0 196 sub subname { 'rec' }
11              
12             sub guts_from_arg {
13 15     15 0 47 my ($class, $arg, $rx, $type) = @_;
14              
15 15 100       83 Carp::croak("unknown arguments to new") unless
16             Data::Rx::Util->_x_subset_keys_y($arg, {
17             rest => 1,
18             required => 1,
19             optional => 1,
20             });
21              
22 13         43 my $guts = {};
23              
24 13         32 my $content_schema = {};
25              
26 13 100       54 $guts->{rest_schema} = $rx->make_schema($arg->{rest}) if $arg->{rest};
27              
28 13         36 TYPE: for my $type (qw(required optional)) {
29 26 100       82 next TYPE unless my $entries = $arg->{$type};
30              
31 21         53 for my $entry (keys %$entries) {
32             Carp::croak("$entry appears in both required and optional")
33 25 100       187 if $content_schema->{ $entry };
34              
35             $content_schema->{ $entry } = {
36             optional => $type eq 'optional',
37 24         84 schema => $rx->make_schema($entries->{ $entry }),
38             };
39             }
40             };
41              
42 12         45 $guts->{content_schema} = $content_schema;
43 12         26 return $guts;
44             }
45              
46             sub assert_valid {
47 406     406 0 20719 my ($self, $value) = @_;
48              
49 406 100 100     2157 unless (! Scalar::Util::blessed($value) and ref $value eq 'HASH') {
50 344         1630 $self->fail({
51             error => [ qw(type) ],
52             message => "value is not a hashref",
53             value => $value,
54             });
55             }
56              
57 62         139 my $c_schema = $self->{content_schema};
58              
59 62         93 my @subchecks;
60              
61 62         190 my @rest_keys = grep { ! exists $c_schema->{$_} } keys %$value;
  108         289  
62 62 100 100     267 if (@rest_keys and not $self->{rest_schema}) {
63 9         27 @rest_keys = sort @rest_keys;
64 9         105 push @subchecks,
65             $self->new_fail({
66             error => [ qw(unexpected) ],
67             keys => [@rest_keys],
68             message => "found unexpected entries: @rest_keys",
69             value => $value,
70             });
71             }
72              
73 62 50       197 for my $key ($self->rx->sort_keys ? sort keys %$c_schema : keys %$c_schema) {
74 99         167 my $check = $c_schema->{$key};
75              
76 99 100 100     340 if (not $check->{optional} and not exists $value->{ $key }) {
77 23         163 push @subchecks,
78             $self->new_fail({
79             error => [ qw(missing) ],
80             keys => [$key],
81             message => "no value given for required entry $key",
82             value => $value,
83             });
84 23         96 next;
85             }
86              
87 76 100       172 if (exists $value->{$key}) {
88             push @subchecks, [
89             $value->{$key},
90             $check->{schema},
91             { data_path => [ [$key, 'key' ] ],
92             check_path => [
93 59 100       749 [ $check->{optional} ? 'optional' : 'required', 'key' ],
94             [ $key, 'key' ],
95             ],
96             },
97             ];
98             }
99             }
100              
101 62 100 100     233 if (@rest_keys && $self->{rest_schema}) {
102 21         39 my %rest = map { $_ => $value->{$_} } @rest_keys;
  40         129  
103              
104             push @subchecks, [
105             \%rest,
106             $self->{rest_schema},
107 21         114 { check_path => [ ['rest', 'key' ] ],
108             },
109             ];
110             }
111              
112 62         231 $self->perform_subchecks(\@subchecks);
113              
114 25         108 return 1;
115             }
116              
117             1;
118              
119             __END__