File Coverage

blib/lib/Salvation/TC/Type/HashRef.pm
Criterion Covered Total %
statement 63 65 96.9
branch 22 26 84.6
condition 7 11 63.6
subroutine 14 14 100.0
pod 1 3 33.3
total 107 119 89.9


line stmt bran cond sub pod time code
1             package Salvation::TC::Type::HashRef;
2              
3 4     4   1606 use strict;
  4         6  
  4         136  
4 4     4   19 use warnings;
  4         5  
  4         109  
5              
6 4     4   18 use base 'Salvation::TC::Type::Ref';
  4         5  
  4         264  
7              
8 4     4   18 use Scalar::Util 'blessed';
  4         4  
  4         213  
9 4     4   21 use Salvation::TC::Exception::WrongType ();
  4         6  
  4         54  
10 4     4   16 use Salvation::TC::Exception::WrongType::TC ();
  4         7  
  4         2474  
11              
12              
13             sub Check {
14              
15 66     66 1 72 my ( $class, $value ) = @_;
16              
17 66 100       288 ( ref( $value ) eq 'HASH' ) || Salvation::TC::Exception::WrongType -> throw( 'type' => 'HashRef', 'value' => $value );
18             }
19              
20             sub create_validator_from_sig {
21              
22 10     10 0 13 my ( $class, $signature, $options ) = @_;
23              
24 10         13 my %checks = ();
25              
26 10         18 foreach my $el ( @$signature ) {
27              
28 13         18 my ( $param, $type ) = @$el{ 'param', 'type' };
29              
30 13 50       34 die( 'Only named parameters are supported' ) if( $param -> { 'positional' } );
31              
32             my $wrap = sub {
33              
34 13     13   15 my ( $code ) = @_;
35              
36             return sub {
37              
38 28         41 my ( @input ) = @_;
39              
40 28         26 eval { $code -> ( @input ) };
  28         37  
41              
42 28 100       112 if( $@ ) {
43              
44 3 50 33     43 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
45              
46 3 50       11 Salvation::TC::Exception::WrongType::TC -> throw(
47             type => $@ -> getType(),
48             value => $@ -> getValue(),
49             param_name => $param -> { 'name' },
50             ( $@ -> isa( 'Salvation::TC::Exception::WrongType::TC' ) ? (
51             prev => $@ -> getPrev(),
52             ) : () ),
53             );
54              
55             } else {
56              
57 0         0 die( $@ );
58             }
59             };
60 13         64 };
61 13         55 };
62              
63 13 50       33 if( exists $checks{ $param -> { 'name' } } ) {
64              
65 0         0 die( 'Invalid signature: parameter ' . $param -> { 'name' } . ' is specified twice' );
66             }
67              
68 13 100       27 if( $param -> { 'optional' } ) {
69              
70             $checks{ $param -> { 'name' } } = $wrap -> ( sub {
71              
72 8 100   8   22 if( exists $_[ 0 ] -> { $param -> { 'name' } } ) {
73              
74 4         11 $type -> check( $_[ 0 ] -> { $param -> { 'name' } } )
75             }
76              
77 4         11 } );
78              
79             } else {
80              
81             $checks{ $param -> { 'name' } } = $wrap -> ( sub {
82              
83 20 100   20   52 exists $_[ 0 ] -> { $param -> { 'name' } } || Salvation::TC::Exception::WrongType
84             -> throw( 'type' => $type -> name(), 'value' => '(not exists)' );
85              
86 19         46 $type -> check( $_[ 0 ] -> { $param -> { 'name' } } );
87              
88 9         34 } );
89             }
90             }
91              
92 10         25 my @checks = values( %checks );
93              
94             return sub {
95              
96 21     21   50 $_ -> ( $_[ 0 ] ) for @checks;
97              
98 18 100       42 if( $options -> { 'strict' } ) {
99              
100 6         6 eval {
101 6         6 while( my ( $key ) = each( %{ $_[ 0 ] } ) ) {
  12         31  
102              
103 10 100       20 unless( exists $checks{ $key } ) {
104              
105 4         21 Salvation::TC::Exception::WrongType -> throw(
106             'type' => "HashRef.${key}",
107             'value' => '(key is not expected)'
108             );
109             }
110             }
111             };
112              
113 6 100       12 if( $@ ) {
114              
115 4         2 keys( %{ $_[ 0 ] } ); # reset iterator
  4         5  
116 4         17 die( $@ );
117             }
118             }
119              
120 14         42 1;
121 10         45 };
122             }
123              
124             sub create_length_validator {
125              
126 5     5 0 11 my ( $class, $min, $max ) = @_;
127              
128             return sub {
129              
130 5     5   6 my $len = scalar( keys( %{ $_[ 0 ] } ) );
  5         11  
131              
132 5 100 66     24 if( ( $len < $min ) || ( defined $max && ( $len > $max ) ) ) {
      66        
133              
134 2   100     17 Salvation::TC::Exception::WrongType -> throw(
135             'type' => sprintf( 'HashRef{%s,%s}', $min, ( $max // '' ) ),
136             'value' => $_[ 0 ]
137             );
138             }
139              
140 3         11 1;
141 5         26 };
142             }
143              
144             1;
145              
146             __END__