File Coverage

blib/lib/Type/Params/Parameter.pm
Criterion Covered Total %
statement 154 156 98.7
branch 82 86 95.3
condition 46 54 85.1
subroutine 27 27 100.0
pod 0 17 0.0
total 309 340 90.8


line stmt bran cond sub pod time code
1             # INTERNAL MODULE: a parameter within a Type::Params::Signature.
2              
3             package Type::Params::Parameter;
4              
5 51     51   1245 use 5.008001;
  51         221  
6 51     51   323 use strict;
  51         128  
  51         1247  
7 51     51   287 use warnings;
  51         140  
  51         2603  
8              
9             BEGIN {
10 51 50   51   1920 if ( $] < 5.010 ) { require Devel::TypeTiny::Perl58Compat }
  0         0  
11             }
12              
13             BEGIN {
14 51     51   176 $Type::Params::Parameter::AUTHORITY = 'cpan:TOBYINK';
15 51         1814 $Type::Params::Parameter::VERSION = '2.002001';
16             }
17              
18             $Type::Params::Parameter::VERSION =~ tr/_//d;
19              
20 51     51   338 use Types::Standard qw( -is -types );
  51         130  
  51         341  
21              
22             sub _croak {
23 1     1   6 require Carp;
24 1         202 Carp::croak( pop );
25             }
26              
27             sub new {
28 704     704 0 1198 my $class = shift;
29              
30 704 50       2245 my %self = @_ == 1 ? %{$_[0]} : @_;
  0         0  
31 704   100     3311 $self{alias} ||= [];
32 704 100 66     2800 if ( defined $self{alias} and not ref $self{alias} ) {
33 7         20 $self{alias} = [ $self{alias} ];
34             }
35              
36 704         2006 bless \%self, $class;
37             }
38              
39 3     3 0 14 sub name { $_[0]{name} } sub has_name { exists $_[0]{name} }
  1560     1560 0 6874  
40 3     3 0 14 sub type { $_[0]{type} } sub has_type { exists $_[0]{type} }
  2276     2276 0 6501  
41 14     14 0 27 sub default { $_[0]{default} } sub has_default { exists $_[0]{default} }
  1581     1581 0 5599  
42 8     8 0 60 sub alias { $_[0]{alias} } sub has_alias { @{ $_[0]{alias} } }
  347     347 0 608  
  347         1264  
43 688     688 0 2536 sub strictness { $_[0]{strictness} } sub has_strictness { exists $_[0]{strictness} }
  1     1 0 4  
44              
45 834     834 0 2119 sub should_clone { $_[0]{clone} }
46              
47             sub coerce {
48             exists( $_[0]{coerce} )
49             ? $_[0]{coerce}
50 139 50   139 0 443 : ( $_[0]{coerce} = $_[0]->type->has_coercion )
51             }
52              
53             sub optional {
54             exists( $_[0]{optional} )
55             ? $_[0]{optional}
56 1936 100   1936 0 5301 : do {
57             $_[0]{optional} = $_[0]->has_default || grep(
58             $_->{uniq} == Optional->{uniq},
59 677   100     1595 $_[0]->type->parents,
60             );
61             }
62             }
63              
64             sub getter {
65             exists( $_[0]{getter} )
66             ? $_[0]{getter}
67             : ( $_[0]{getter} = $_[0]{name} )
68 126 100   126 0 489 }
69              
70             sub predicate {
71             exists( $_[0]{predicate} )
72             ? $_[0]{predicate}
73 126 100   126 0 451 : ( $_[0]{predicate} = ( $_[0]->optional ? 'has_' . $_[0]{name} : undef ) )
    100          
74             }
75              
76             sub might_supply_new_value {
77 147 100 100 147 0 393 $_[0]->has_default or $_[0]->coerce or $_[0]->should_clone;
78             }
79              
80             sub _code_for_default {
81 14     14   29 my ( $self, $signature, $coderef ) = @_;
82 14         33 my $default = $self->default;
83              
84 14 100       65 if ( is_CodeRef $default ) {
85             my $default_varname = $coderef->add_variable(
86             '$default_for_' . $self->{vartail},
87 4         24 \$default,
88             );
89 4         16 return sprintf( '%s->( %s )', $default_varname, $signature->method_invocant );
90             }
91 10 100       26 if ( is_Undef $default ) {
92 2         10 return 'undef';
93             }
94 8 100       20 if ( is_Str $default ) {
95 2         20 return B::perlstring( $default );
96             }
97 6 100       17 if ( is_HashRef $default ) {
98 2         10 return '{}';
99             }
100 4 100       15 if ( is_ArrayRef $default ) {
101 2         11 return '[]';
102             }
103 2 100       7 if ( is_ScalarRef $default ) {
104 1         6 return $$default;
105             }
106              
107 1         5 $self->_croak( 'Default expected to be undef, string, coderef, or empty arrayref/hashref' );
108             }
109              
110             sub _maybe_clone {
111 16     16   40 my ( $self, $varname ) = @_;
112              
113 16 100       32 if ( $self->should_clone ) {
114 2         12 return sprintf( 'Storable::dclone( %s )', $varname );
115             }
116 14         40 return $varname;
117             }
118              
119             sub _make_code {
120 688     688   3656 my ( $self, %args ) = ( shift, @_ );
121              
122 688   100     2232 my $type = $args{type} || 'arg';
123 688         1207 my $signature = $args{signature};
124 688         1155 my $coderef = $args{coderef};
125 688         1145 my $varname = $args{input_slot};
126 688         1108 my $index = $args{index};
127 688         1513 my $constraint = $self->type;
128 688         1524 my $is_optional = $self->optional;
129             my $really_optional =
130             $is_optional
131             && $constraint->parent
132             && $constraint->parent->{uniq} eq Optional->{uniq}
133 688   66     6634 && $constraint->type_parameter;
134              
135 688         1328 my $strictness;
136 688 100       1555 if ( $self->has_strictness ) {
    100          
137 1         4 $strictness = \ $self->strictness;
138             }
139             elsif ( $signature->has_strictness ) {
140 9         24 $strictness = \ $signature->strictness;
141             }
142              
143 688         1423 my ( $vartail, $exists_check );
144 688 100       1606 if ( $args{is_named} ) {
145 347         614 my $bit = $args{key};
146 347 50       978 $bit =~ s/([_\W])/$1 eq '_' ? '__' : sprintf('_%x', ord($1))/ge;
  2         13  
147 347         752 $vartail = $type . '_' . $bit;
148 347         974 $exists_check = sprintf 'exists( %s )', $args{input_slot};
149             }
150             else {
151 341   100     1807 ( my $input_count_varname = $args{input_var} || '' ) =~ s/\@/\$\#/;
152 341         897 $vartail = $type . '_' . $index;
153 341         1107 $exists_check = sprintf '%s >= %d', $input_count_varname, $index;
154             }
155              
156 688         1177 my $block_needs_ending = 0;
157 688         1561 my $needs_clone = $self->should_clone;
158 688         1185 my $in_big_optional_block = 0;
159              
160 688 100 66     1771 if ( $needs_clone and not $signature->{loaded_Storable} ) {
161 2         5 $coderef->add_line( 'use Storable ();' );
162 2         5 $coderef->add_gap;
163 2         4 $signature->{loaded_Storable} = 1;
164             }
165              
166             $coderef->add_line( sprintf(
167             '# Parameter %s (type: %s)',
168             $self->name || $args{input_slot},
169 688   66     1543 $constraint->display_name,
170             ) );
171              
172 688 100 100     2472 if ( $args{is_named} and $self->has_alias ) {
173             $coderef->add_line( sprintf(
174             'for my $alias ( %s ) {',
175 8         36 join( q{, }, map B::perlstring($_), @{ $self->alias } ),
  8         23  
176             ) );
177 8         35 $coderef->increase_indent;
178 8         23 $coderef->add_line( 'exists $in{$alias} or next;' );
179 8         38 $coderef->add_line( sprintf(
180             'if ( %s ) {',
181             $exists_check,
182             ) );
183 8         31 $coderef->increase_indent;
184             $coderef->add_line( sprintf(
185             '%s;',
186             $signature->_make_general_fail(
187             coderef => $coderef,
188 8   33     19 message => q{sprintf( 'Superfluous alias "%s" for argument "%s"', $alias, } . B::perlstring( $self->name || $args{input_slot} ) . q{ )},
189             ),
190             ) );
191 8         63 $coderef->decrease_indent;
192 8         32 $coderef->add_line( '}' );
193 8         32 $coderef->add_line( 'else {' );
194 8         25 $coderef->increase_indent;
195 8         33 $coderef->add_line( sprintf(
196             '%s = delete( $in{$alias} );',
197             $varname,
198             ) );
199 8         24 $coderef->decrease_indent;
200 8         36 $coderef->add_line( '}' );
201 8         29 $coderef->decrease_indent;
202 8         31 $coderef->add_line( '}' );
203             }
204              
205 688 100       1609 if ( $self->has_default ) {
    100          
    100          
206 14         44 $self->{vartail} = $vartail; # hack
207 14         35 $coderef->add_line( sprintf(
208             '$dtmp = %s ? %s : %s;',
209             $exists_check,
210             $self->_maybe_clone( $varname ),
211             $self->_code_for_default( $signature, $coderef ),
212             ) );
213 13         27 $varname = '$dtmp';
214 13         21 $needs_clone = 0;
215             }
216             elsif ( $self->optional ) {
217 99 100       328 if ( $args{is_named} ) {
218 80         376 $coderef->add_line( sprintf(
219             'if ( %s ) {',
220             $exists_check,
221             ) );
222 80         177 $coderef->{indent} .= "\t";
223 80         157 ++$block_needs_ending;
224 80         142 ++$in_big_optional_block;
225             }
226             else {
227 19         53 $coderef->add_line( sprintf(
228             "%s\n\tor %s;",
229             $exists_check,
230             $signature->_make_return_expression( is_early => 1 ),
231             ) );
232             }
233             }
234             elsif ( $args{is_named} ) {
235 262         1158 $coderef->add_line( sprintf(
236             "%s\n\tor %s;",
237             $exists_check,
238             $signature->_make_general_fail(
239             coderef => $coderef,
240             message => "'Missing required parameter: $args{key}'",
241             ),
242             ) );
243             }
244              
245 687 100       1780 if ( $needs_clone ) {
246 2         6 $coderef->add_line( sprintf(
247             '$dtmp = %s;',
248             $self->_maybe_clone( $varname ),
249             ) );
250 2         4 $varname = '$dtmp';
251 2         3 $needs_clone = 0;
252             }
253              
254 687 100 100     1932 if ( $constraint->has_coercion and $constraint->coercion->can_be_inlined ) {
    100          
255 84 100       342 $coderef->add_line( sprintf(
256             '$tmp%s = %s;',
257             ( $is_optional ? '{x}' : '' ),
258             $constraint->coercion->inline_coercion( $varname )
259             ) );
260 84 100       354 $varname = '$tmp' . ( $is_optional ? '{x}' : '' );
261             }
262             elsif ( $constraint->has_coercion ) {
263 83         316 my $coercion_varname = $coderef->add_variable(
264             '$coercion_for_' . $vartail,
265             \ $constraint->coercion->compiled_coercion,
266             );
267 83 100       610 $coderef->add_line( sprintf(
268             '$tmp%s = &%s( %s );',
269             ( $is_optional ? '{x}' : '' ),
270             $coercion_varname,
271             $varname,
272             ) );
273 83 100       258 $varname = '$tmp' . ( $is_optional ? '{x}' : '' );
274             }
275              
276 687         2635 undef $Type::Tiny::ALL_TYPES{ $constraint->{uniq} };
277 687         1437 $Type::Tiny::ALL_TYPES{ $constraint->{uniq} } = $constraint;
278              
279 687         1233 my $strictness_test = '';
280 687 100 100     3003 if ( $strictness and $$strictness eq 1 ) {
    100 100        
281 3         7 $strictness_test = '';
282             }
283             elsif ( $strictness and $$strictness ) {
284 5         16 $strictness_test = sprintf "( not %s )\n\tor ", $$strictness;
285             }
286              
287 687 100 100     2980 if ( $strictness and not $$strictness ) {
    100          
    100          
288 2         13 $coderef->add_line( '1; # ... nothing to do' );
289             }
290             elsif ( $constraint->{uniq} == Any->{uniq} ) {
291 13         88 $coderef->add_line( '1; # ... nothing to do' );
292             }
293             elsif ( $constraint->can_be_inlined ) {
294             $coderef->add_line( $strictness_test . sprintf(
295             "%s\n\tor %s;",
296             ( $really_optional or $constraint )->inline_check( $varname ),
297             $signature->_make_constraint_fail(
298             coderef => $coderef,
299             parameter => $self,
300             constraint => $constraint,
301             varname => $varname,
302             display_var => $args{display_var},
303 611   66     2491 ),
304             ) );
305             }
306             else {
307 61   66     377 my $compiled_check_varname = $coderef->add_variable(
308             '$check_for_' . $vartail,
309             \ ( ( $really_optional or $constraint )->compiled_check ),
310             );
311             $coderef->add_line( $strictness_test . sprintf(
312             "&%s( %s )\n\tor %s;",
313             $compiled_check_varname,
314             $varname,
315             $signature->_make_constraint_fail(
316             coderef => $coderef,
317             parameter => $self,
318             constraint => $constraint,
319             varname => $varname,
320             display_var => $args{display_var},
321 61         288 ),
322             ) );
323             }
324              
325 687 100 100     3496 if ( $args{output_var} ) {
    100          
326             $coderef->add_line( sprintf(
327             'push( %s, %s );',
328             $args{output_var},
329 99         429 $varname,
330             ) );
331             }
332             elsif ( $args{output_slot} and $args{output_slot} ne $varname ) {
333 387 100 100     1779 if ( !$in_big_optional_block and $varname =~ /\{/ ) {
334             $coderef->add_line( sprintf(
335             '%s = %s if exists( %s );',
336             $args{output_slot},
337 202         974 $varname,
338             $varname,
339             ) );
340             }
341             else {
342             $coderef->add_line( sprintf(
343             '%s = %s;',
344             $args{output_slot},
345 185         776 $varname,
346             ) );
347             }
348             }
349              
350 687 100       1774 if ( $args{is_named} ) {
351             $coderef->add_line( sprintf(
352             'delete( %s );',
353             $args{input_slot},
354 347         1201 ) );
355             }
356              
357 687 100       1603 if ( $block_needs_ending ) {
358 80         486 $coderef->{indent} =~ s/\s$//;
359 80         255 $coderef->add_line( '}' );
360             }
361              
362 687         2007 $coderef->add_gap;
363              
364 687         3146 $self;
365             }
366              
367             1;