File Coverage

lib/Types/Standard/HashRef.pm
Criterion Covered Total %
statement 107 108 100.0
branch 36 44 81.8
condition 9 14 64.2
subroutine 22 22 100.0
pod n/a
total 174 188 93.0


line stmt bran cond sub pod time code
1             # INTERNAL MODULE: guts for HashRef type from Types::Standard.
2              
3             package Types::Standard::HashRef;
4              
5 22     22   1277 use 5.008001;
  22         88  
6 22     22   129 use strict;
  22         45  
  22         651  
7 22     22   95 use warnings;
  22         42  
  22         1971  
8              
9             BEGIN {
10 22     22   76 $Types::Standard::HashRef::AUTHORITY = 'cpan:TOBYINK';
11 22         976 $Types::Standard::HashRef::VERSION = '2.010001';
12             }
13              
14             $Types::Standard::HashRef::VERSION =~ tr/_//d;
15              
16 22     22   129 use Type::Tiny ();
  22         40  
  22         467  
17 22     22   139 use Types::Standard ();
  22         41  
  22         366  
18 22     22   91 use Types::TypeTiny ();
  22         58  
  22         1643  
19              
20 3     3   46 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  3         19  
21              
22 22     22   123 use Exporter::Tiny 1.004001 ();
  22         462  
  22         8167  
23             our @ISA = qw( Exporter::Tiny );
24              
25             sub _exporter_fail {
26 2     2   481 my ( $class, $type_name, $values, $globals ) = @_;
27 2         7 my $caller = $globals->{into};
28            
29 2 100       8 my $of = exists( $values->{of} ) ? $values->{of} : $values->{type};
30 2 50       9 defined $of or _croak( qq{Expected option "of" for type "$type_name"} );
31 2 100       111 if ( not Types::TypeTiny::is_TypeTiny($of) ) {
32 1         632 require Type::Utils;
33 1         7 $of = Type::Utils::dwim_type( $of, for => $caller );
34             }
35            
36 2         13 my $type = Types::Standard::HashRef->of( $of );
37             $type = $type->create_child_type(
38             name => $type_name,
39             $type->has_coercion ? ( coercion => 1 ) : (),
40 2 50       10 exists( $values->{where} ) ? ( constraint => $values->{where} ) : (),
    50          
41             );
42            
43             $INC{'Type/Registry.pm'}
44             ? 'Type::Registry'->for_class( $caller )->add_type( $type, $type_name )
45             : ( $Type::Registry::DELAYED{$caller}{$type_name} = $type )
46 2 100 33     45 unless( ref($caller) or $caller eq '-lexical' or $globals->{'lexical'} );
    50 33        
47 2         5 return map +( $_->{name} => $_->{code} ), @{ $type->exportables };
  2         11  
48             }
49              
50 22     22   213 no warnings;
  22         56  
  22         28442  
51              
52             sub __constraint_generator {
53 43 50   43   2204 return Types::Standard::HashRef unless @_;
54            
55 43         9319 require Error::TypeTiny::WrongNumberOfParameters;
56 43         278 Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Standard', 'HashRef', \@_, 1 );
57 43         102 my $param = shift;
58 43 100       1256 Types::TypeTiny::is_TypeTiny( $param )
59             or _croak(
60             "Parameter to HashRef[`a] expected to be a type constraint; got $param" );
61            
62 40         211 my $param_compiled_check = $param->compiled_check;
63 40         85 my $xsub;
64 40         77 if ( Type::Tiny::_USE_XS ) {
65 40         192 my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
66 40 100       453 $xsub = Type::Tiny::XS::get_coderef_for( "HashRef[$paramname]" )
67             if $paramname;
68             }
69             elsif ( Type::Tiny::_USE_MOUSE and $param->_has_xsub ) {
70             require Mouse::Util::TypeConstraints;
71             my $maker = "Mouse::Util::TypeConstraints"->can( "_parameterize_HashRef_for" );
72             $xsub = $maker->( $param ) if $maker;
73             }
74            
75             return (
76             sub {
77 116     116   252 my $hash = shift;
78 116   100     413 $param->check( $_ ) || return for values %$hash;
79 99         336 return !!1;
80             },
81 40         1772 $xsub,
82             );
83             } #/ sub __constraint_generator
84              
85             sub __inline_generator {
86 40     40   89 my $param = shift;
87            
88 40         121 my $compiled = $param->compiled_check;
89 40         90 my $xsubname;
90 40 100       145 if ( Type::Tiny::_USE_XS and not $Type::Tiny::AvoidCallbacks ) {
91 37         121 my $paramname = Type::Tiny::XS::is_known( $compiled );
92 37         323 $xsubname = Type::Tiny::XS::get_subname_for( "HashRef[$paramname]" );
93             }
94            
95 40 100       645 return unless $param->can_be_inlined;
96             return sub {
97 340     340   676 my $v = $_[1];
98 340 100 100     1892 return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
99 123         432 my $p = Types::Standard::HashRef->inline_check( $v );
100 123         367 my $param_check = $param->inline_check( '$i' );
101            
102 123         541 "$p and do { "
103             . "my \$ok = 1; "
104             . "for my \$i (values \%{$v}) { "
105             . "(\$ok = 0, last) unless $param_check " . "}; " . "\$ok " . "}";
106 38         323 };
107             } #/ sub __inline_generator
108              
109             sub __deep_explanation {
110 2     2   12 require B;
111 2         7 my ( $type, $value, $varname ) = @_;
112 2         8 my $param = $type->parameters->[0];
113            
114 2         10 for my $k ( sort keys %$value ) {
115 4         9 my $item = $value->{$k};
116 4 100       23 next if $param->check( $item );
117             return [
118             sprintf( '"%s" constrains each value in the hash with "%s"', $type, $param ),
119             @{
120 2         10 $param->validate_explain(
  2         18  
121             $item, sprintf( '%s->{%s}', $varname, B::perlstring( $k ) )
122             )
123             },
124             ];
125             } #/ for my $k ( sort keys %$value)
126            
127             # This should never happen...
128 0         0 return; # uncoverable statement
129             } #/ sub __deep_explanation
130              
131             sub __coercion_generator {
132 30     30   103 my ( $parent, $child, $param ) = @_;
133 30 100       119 return unless $param->has_coercion;
134            
135 12         53 my $coercable_item = $param->coercion->_source_type_union;
136 12         65 my $C = "Type::Coercion"->new( type_constraint => $child );
137            
138 12 100 66     47 if ( $param->coercion->can_be_inlined and $coercable_item->can_be_inlined ) {
139             $C->add_type_coercions(
140             $parent => Types::Standard::Stringable {
141 6     6   15 my @code;
142 6         19 push @code, 'do { my ($orig, $return_orig, %new) = ($_, 0);';
143 6         15 push @code, 'for (keys %$orig) {';
144 6         40 push @code,
145             sprintf(
146             '$return_orig++ && last unless (%s);',
147             $coercable_item->inline_check( '$orig->{$_}' )
148             );
149 6         32 push @code,
150             sprintf(
151             '$new{$_} = (%s);',
152             $param->coercion->inline_coercion( '$orig->{$_}' )
153             );
154 6         22 push @code, '}';
155 6         20 push @code, '$return_orig ? $orig : \\%new';
156 6         20 push @code, '}';
157 6         72 "@code";
158             }
159 6         89 );
160             } #/ if ( $param->coercion->...)
161             else {
162             $C->add_type_coercions(
163             $parent => sub {
164 12 50   12   5582 my $value = @_ ? $_[0] : $_;
165 12         31 my %new;
166 12         53 for my $k ( keys %$value ) {
167 35 100       444 return $value unless $coercable_item->check( $value->{$k} );
168 34         282 $new{$k} = $param->coerce( $value->{$k} );
169             }
170 11         234 return \%new;
171             },
172 6         62 );
173             } #/ else [ if ( $param->coercion->...)]
174            
175 12         53 return $C;
176             } #/ sub __coercion_generator
177              
178             sub __hashref_allows_key {
179 19     19   45 my $self = shift;
180 19         177 Types::Standard::is_Str( $_[0] );
181             }
182              
183             sub __hashref_allows_value {
184 6     6   11 my $self = shift;
185 6         15 my ( $key, $value ) = @_;
186            
187 6 100       26 return !!0 unless $self->my_hashref_allows_key( $key );
188 5 100       17 return !!1 if $self == Types::Standard::HashRef();
189            
190             my $href = $self->find_parent(
191 3 50   3   23 sub { $_->has_parent && $_->parent == Types::Standard::HashRef() } );
  3         10  
192 3         21 my $param = $href->type_parameter;
193            
194 3 50       20 Types::Standard::is_Str( $key ) and $param->check( $value );
195             } #/ sub __hashref_allows_value
196              
197             1;
198              
199             __END__