File Coverage

blib/lib/Type/Utils.pm
Criterion Covered Total %
statement 350 385 90.9
branch 143 196 72.9
condition 35 75 46.6
subroutine 48 49 97.9
pod 24 24 100.0
total 600 729 82.3


line stmt bran cond sub pod time code
1             package Type::Utils;
2              
3 137     137   632730 use 5.008001;
  137         747  
4 137     137   1073 use strict;
  137         697  
  137         3693  
5 137     109   815 use warnings;
  109         202  
  109         9235  
6              
7             BEGIN {
8 109     109   532 $Type::Utils::AUTHORITY = 'cpan:TOBYINK';
9 109         12548 $Type::Utils::VERSION = '2.010001';
10             }
11              
12             $Type::Utils::VERSION =~ tr/_//d;
13              
14 3     3   21 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  3         20  
15              
16 109     109   852 use Scalar::Util qw< blessed >;
  109         357  
  109         8907  
17 109     109   12570 use Type::Library;
  109         325  
  109         1417  
18 109     109   8191 use Type::Tiny;
  109         216  
  109         4525  
19 109     109   668 use Types::TypeTiny qw< TypeTiny is_TypeTiny to_TypeTiny HashLike StringLike >;
  109         304  
  109         932  
20              
21             our @EXPORT = qw<
22             declare as where message inline_as
23             class_type role_type duck_type union intersection enum
24             coerce from via
25             declare_coercion to_type
26             >;
27             our @EXPORT_OK = (
28             @EXPORT,
29             qw<
30             extends type subtype
31             match_on_type compile_match_on_type
32             dwim_type english_list
33             classifier assert
34             >,
35             "is",
36             );
37             our %EXPORT_TAGS = (
38             default => [@EXPORT],
39             all => [@EXPORT_OK],
40             );
41             pop @{ $EXPORT_TAGS{all} }; # remove 'is'
42              
43             require Exporter::Tiny;
44             our @ISA = 'Exporter::Tiny';
45              
46             sub extends {
47 64 50   64 1 19087 _croak "Not a type library" unless caller->isa( "Type::Library" );
48 64         480 my $caller = caller->meta;
49            
50 64         218 foreach my $lib ( @_ ) {
51 148 50   48   15320 eval "use $lib; 1" or _croak "Could not load library '$lib': $@";
  48     44   27395  
  48         273  
  48         608  
  44         28852  
  44         243  
  44         639  
52            
53 148 100 100     2465 if ( $lib->isa( "Type::Library" ) or $lib eq 'Types::TypeTiny' ) {
    50 33        
    50          
    50          
    50          
54 147         953 $caller->add_type( $lib->get_type( $_ ) ) for sort $lib->meta->type_names;
55             $caller->add_coercion( $lib->get_coercion( $_ ) )
56 147         1647 for sort $lib->meta->coercion_names;
57             }
58             elsif ( $lib->isa( 'MooseX::Types::Base' ) ) {
59 0         0 require Moose::Util::TypeConstraints;
60 0         0 my $types = $lib->type_storage;
61 0         0 for my $name ( sort keys %$types ) {
62             my $moose =
63 0         0 Moose::Util::TypeConstraints::find_type_constraint( $types->{$name} );
64 0         0 my $tt = Types::TypeTiny::to_TypeTiny( $moose );
65 0   0     0 my $c = $moose->has_coercion && @{ $moose->coercion->type_coercion_map || [] };
66 0 0       0 $caller->add_type(
67             $tt->create_child_type(
68             library => $caller, name => $name, coercion => $c ? 1 : 0
69             )
70             );
71             } #/ for my $name ( sort keys...)
72             } #/ elsif ( $lib->isa( 'MooseX::Types::Base'...))
73             elsif ( $lib->isa( 'MouseX::Types::Base' ) ) {
74 0         0 require Mouse::Util::TypeConstraints;
75 0         0 my $types = $lib->type_storage;
76 0         0 for my $name ( sort keys %$types ) {
77             my $mouse =
78 0         0 Mouse::Util::TypeConstraints::find_type_constraint( $types->{$name} );
79 0         0 my $tt = Types::TypeTiny::to_TypeTiny( $mouse );
80 0 0       0 $caller->add_type(
81             $tt->create_child_type(
82             library => $caller, name => $name, coercion => $mouse->has_coercion ? 1 : 0
83             )
84             );
85             } #/ for my $name ( sort keys...)
86             } #/ elsif ( $lib->isa( 'MouseX::Types::Base'...))
87             elsif ( $lib->isa( 'Specio::Exporter' ) ) {
88 0         0 my $types = $lib->Specio::Registry::exportable_types_for_package;
89 0         0 for my $name ( sort keys %$types ) {
90 0         0 my $specio = $types->{$name};
91 0         0 my $tt = Types::TypeTiny::to_TypeTiny( $specio );
92 0         0 $caller->add_type(
93             $tt->create_child_type( library => $caller, name => $name )
94             );
95             }
96             }
97             elsif ( $lib->isa( 'Exporter' )
98 109     109   180870 and my $types = do { no strict 'refs'; ${"$lib\::EXPORT_TAGS"}{'types'} } ) {
  109         255  
  109         118680  
  1         2  
  1         1919  
99 1         13 for my $name ( @$types ) {
100 3         27 my $obj = $lib->$name;
101 3         40 my $tt = Types::TypeTiny::to_TypeTiny( $obj );
102 3         16 $caller->add_type(
103             $tt->create_child_type( library => $caller, name => $name )
104             );
105             }
106             }
107             else {
108 0         0 _croak( "'$lib' is not a type constraint library" );
109             }
110             } #/ foreach my $lib ( @_ )
111             } #/ sub extends
112              
113             sub declare {
114 255     255 1 500 my %opts;
115 255 100       997 if ( @_ % 2 == 0 ) {
116 140         574 %opts = @_;
117 140 100 100     635 if ( @_ == 2 and $_[0] =~ /^_*[A-Z]/ and $_[1] =~ /^[0-9]+$/ ) {
      66        
118 1         8 require Carp;
119 1         5 Carp::carp( "Possible missing comma after 'declare $_[0]'" );
120             }
121             }
122             else {
123 115         495 ( my ( $name ), %opts ) = @_;
124 115 50       386 _croak "Cannot provide two names for type" if exists $opts{name};
125 115         340 $opts{name} = $name;
126             }
127            
128 255   100     1219 my $caller = caller( $opts{_caller_level} || 0 );
129 255         602 $opts{library} = $caller;
130            
131 255 100       811 if ( defined $opts{parent} ) {
132 100         508 $opts{parent} = to_TypeTiny( $opts{parent} );
133            
134 100 100       2670 unless ( is_TypeTiny( $opts{parent} ) ) {
135             $caller->isa( "Type::Library" )
136             or _croak(
137             "Parent type cannot be a %s",
138 64 50 0     622 ref( $opts{parent} ) || 'non-reference scalar'
139             );
140             $opts{parent} = $caller->meta->get_type( $opts{parent} )
141 64 50       224 or _croak( "Could not find parent type" );
142             }
143             } #/ if ( defined $opts{parent...})
144            
145 255         441 my $type;
146 255 100       628 if ( defined $opts{parent} ) {
147 100         551 $type = delete( $opts{parent} )->create_child_type( %opts );
148             }
149             else {
150 155   100     503 my $bless = delete( $opts{bless} ) || "Type::Tiny";
151 155         19054 eval "require $bless";
152 155         1531 $type = $bless->new( %opts );
153             }
154            
155 255 100       1294 if ( not $type->is_anon ) {
156            
157 232 100       2276 $caller->meta->add_type( $type )
158             if $caller->isa( 'Type::Library' );
159            
160             $INC{'Type/Registry.pm'}
161             ? 'Type::Registry'->for_class( $caller )->add_type( $type, $opts{name} )
162 231 100       1177 : ( $Type::Registry::DELAYED{$caller}{$opts{name}} = $type );
163             }
164            
165 254         8223 return $type;
166             } #/ sub declare
167              
168             *subtype = \&declare;
169             *type = \&declare;
170              
171             sub as (@) {
172 101     101 1 1030073 parent => @_;
173             }
174              
175             sub where (&;@) {
176 86     86 1 1018407 constraint => @_;
177             }
178              
179             sub message (&;@) {
180 50     50 1 5744 message => @_;
181             }
182              
183             sub inline_as (&;@) {
184 0     0 1 0 inlined => @_;
185             }
186              
187             sub class_type {
188 51 100   51 1 550483 my $name = ref( $_[0] ) eq 'HASH' ? undef : shift;
189 51 100       91 my %opts = %{ shift or {} };
  51         730  
190            
191 51 100       225 if ( defined $name ) {
192 43 50       175 $opts{name} = $name unless exists $opts{name};
193 43 100       144 $opts{class} = $name unless exists $opts{class};
194            
195 43         167 $opts{name} =~ s/:://g;
196             }
197            
198 51         138 $opts{bless} = "Type::Tiny::Class";
199            
200 109     109   1101 { no warnings "numeric"; $opts{_caller_level}++ }
  109         315  
  109         27554  
  51         84  
  51         110  
201 51         190 declare( %opts );
202             } #/ sub class_type
203              
204             sub role_type {
205 19 100   19 1 151 my $name = ref( $_[0] ) eq 'HASH' ? undef : shift;
206 19 50       41 my %opts = %{ shift or {} };
  19         112  
207            
208 19 100       85 if ( defined $name ) {
209 18 50       88 $opts{name} = $name unless exists $opts{name};
210 18 50       81 $opts{role} = $name unless exists $opts{role};
211            
212 18         97 $opts{name} =~ s/:://g;
213             }
214            
215 19         87 $opts{bless} = "Type::Tiny::Role";
216            
217 109     109   890 { no warnings "numeric"; $opts{_caller_level}++ }
  109         324  
  109         20837  
  19         36  
  19         74  
218 19         97 declare( %opts );
219             } #/ sub role_type
220              
221             sub duck_type {
222 35 50   35 1 304340 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
223 35 50       57 my @methods = @{ shift or [] };
  35         219  
224            
225 35         64 my %opts;
226 35 50       115 $opts{name} = $name if defined $name;
227 35         89 $opts{methods} = \@methods;
228            
229 35         150 $opts{bless} = "Type::Tiny::Duck";
230            
231 109     109   845 { no warnings "numeric"; $opts{_caller_level}++ }
  109         249  
  109         19547  
  35         54  
  35         173  
232 35         150 declare( %opts );
233             } #/ sub duck_type
234              
235             sub enum {
236 15 50   15 1 765748 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
237 15 50       38 my @values = @{ shift or [] };
  15         82  
238            
239 15         250 my %opts;
240 15 50       87 $opts{name} = $name if defined $name;
241 15         78 $opts{values} = \@values;
242            
243 15         64 $opts{bless} = "Type::Tiny::Enum";
244            
245 109     109   797 { no warnings "numeric"; $opts{_caller_level}++ }
  109         247  
  109         19373  
  15         33  
  15         43  
246 15         74 declare( %opts );
247             } #/ sub enum
248              
249             sub union {
250 10 100   10 1 511610 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
251 10 50       19 my @tcs = @{ shift or [] };
  10         49  
252            
253 10         19 my %opts;
254 10 100       37 $opts{name} = $name if defined $name;
255 10         34 $opts{type_constraints} = \@tcs;
256            
257 10         28 $opts{bless} = "Type::Tiny::Union";
258            
259 109     109   821 { no warnings "numeric"; $opts{_caller_level}++ }
  109         244  
  109         19279  
  10         18  
  10         28  
260 10         69 declare( %opts );
261             } #/ sub union
262              
263             sub intersection {
264 7 100   7 1 452793 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
265 7 50       17 my @tcs = @{ shift or [] };
  7         35  
266            
267 7         14 my %opts;
268 7 100       28 $opts{name} = $name if defined $name;
269 7         24 $opts{type_constraints} = \@tcs;
270            
271 7         21 $opts{bless} = "Type::Tiny::Intersection";
272            
273 109     109   858 { no warnings "numeric"; $opts{_caller_level}++ }
  109         318  
  109         353800  
  7         12  
  7         23  
274 7         80 declare( %opts );
275             } #/ sub intersection
276              
277             sub declare_coercion {
278 33     33 1 50 my %opts;
279 33 100       221 $opts{name} = shift if !ref( $_[0] );
280            
281             # I don't like this; it is a hack
282 33 100       124 if ( ref( $_[0] ) eq 'Type::Tiny::_DeclaredType' ) {
283 1         7 $opts{name} = '' . shift;
284             }
285            
286 33   66     723 while ( Types::TypeTiny::is_HashLike( $_[0] ) and not is_TypeTiny( $_[0] ) ) {
287 33         190 %opts = ( %opts, %{ +shift } );
  33         226  
288             }
289            
290 33   50     192 my $caller = caller( $opts{_caller_level} || 0 );
291 33         83 $opts{library} = $caller;
292            
293 33   50     167 my $bless = delete( $opts{bless} ) || "Type::Coercion";
294 33         2352 eval "require $bless";
295 33         241 my $c = $bless->new( %opts );
296            
297 33         68 my @C;
298            
299 33 100       290 if ( $caller->isa( "Type::Library" ) ) {
300 32         122 my $meta = $caller->meta;
301 32 100       88 $meta->add_coercion( $c ) unless $c->is_anon;
302 32         132 while ( @_ ) {
303             push @C,
304 32 100 33     73 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  32         251  
305 32         105 push @C, shift;
306             }
307             }
308             else {
309 1         3 @C = @_;
310             }
311            
312 33         156 $c->add_type_coercions( @C );
313            
314 33         104 return $c->freeze;
315             } #/ sub declare_coercion
316              
317             sub coerce {
318 51 100   51 1 652 if ( ( scalar caller )->isa( "Type::Library" ) ) {
319 35         159 my $meta = ( scalar caller )->meta;
320             my ( $type ) =
321 35 100 33     97 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  35         199  
322 35         59 my @opts;
323 35         146 while ( @_ ) {
324             push @opts,
325 65 100 33     115 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  65         253  
326 65         138 push @opts, shift;
327             }
328 35         144 return $type->coercion->add_type_coercions( @opts );
329             } #/ if ( ( scalar caller )...)
330            
331 16         124 my ( $type, @opts ) = @_;
332 16         58 $type = to_TypeTiny( $type );
333 16         42 return $type->coercion->add_type_coercions( @opts );
334             } #/ sub coerce
335              
336             sub from (@) {
337 114     114 1 635 return @_;
338             }
339              
340             sub to_type (@) {
341 33     33 1 81 my $type = shift;
342 33 100       625 unless ( is_TypeTiny( $type ) ) {
343 30 50       267 caller->isa( "Type::Library" )
344             or _croak "Target type cannot be a string";
345 30 50       119 $type = caller->meta->get_type( $type )
346             or _croak "Could not find target type";
347             }
348 33         240 return +{ type_constraint => $type }, @_;
349             } #/ sub to_type (@)
350              
351             sub via (&;@) {
352 69     69 1 322145 return @_;
353             }
354              
355             sub match_on_type {
356 40017     40017 1 85277 my $value = shift;
357            
358 40017         102570 while ( @_ ) {
359 115043         225001 my $code;
360 115043 100       251505 if ( @_ == 1 ) {
361 1         2 $code = shift;
362             }
363             else {
364 115042         302859 ( my ( $type ), $code ) = splice( @_, 0, 2 );
365 115042 100       3446432 Types::TypeTiny::assert_TypeTiny( $type )->check( $value ) or next;
366             }
367            
368 40016 100       291828 if ( Types::TypeTiny::is_StringLike( $code ) ) {
369 30010         59114 local $_ = $value;
370 30010 100       72601 if ( wantarray ) {
371 15004         1174444 my @r = eval "$code";
372 15004 50       73687 die $@ if $@;
373 15004         137783 return @r;
374             }
375 15006 100       31180 if ( defined wantarray ) {
376 15005         1007791 my $r = eval "$code";
377 15005 50       78945 die $@ if $@;
378 15005         159265 return $r;
379             }
380 1         94 eval "$code";
381 1 50       9 die $@ if $@;
382 1         4 return;
383             } #/ if ( Types::TypeTiny::is_StringLike...)
384             else {
385 10006         38997 Types::TypeTiny::assert_CodeLike( $code );
386 10006         68872 local $_ = $value;
387 10006         37101 return $code->( $value );
388             }
389             } #/ while ( @_ )
390            
391 1         9 _croak( "No cases matched for %s", Type::Tiny::_dd( $value ) );
392             } #/ sub match_on_type
393              
394             sub compile_match_on_type {
395 5     5 1 1364 require Eval::TypeTiny::CodeAccumulator;
396 5         47 my $coderef = 'Eval::TypeTiny::CodeAccumulator'->new(
397             description => 'compiled match',
398             );
399 5         20 $coderef->add_line( 'sub {' );
400 5         16 $coderef->increase_indent;
401 5         12 $coderef->add_line( 'local $_ = $_[0];' );
402            
403 5         9 my $els = '';
404            
405 5         15 while ( @_ ) {
406 20         28 my ( $type, $code );
407 20 100       39 if ( @_ == 1 ) {
408 2         9 require Types::Standard;
409 2         7 ( $type, $code ) = ( Types::Standard::Any(), shift );
410             }
411             else {
412 18         41 ( $type, $code ) = splice( @_, 0, 2 );
413 18         413 Types::TypeTiny::assert_TypeTiny( $type );
414             }
415            
416 20 100       58 if ( $type->can_be_inlined ) {
417 19         42 $coderef->add_line( sprintf(
418             '%sif ( %s ) {',
419             $els,
420             $type->inline_check( '$_' ),
421             ) );
422             }
423             else {
424 1         3 my $varname = $coderef->add_variable( '$type', \$type );
425 1         3 $coderef->add_line( sprintf(
426             '%sif ( %s->check($_) ) {',
427             $els,
428             $varname,
429             ) );
430             }
431 20         43 $coderef->increase_indent;
432            
433 20         21 $els = 'els';
434            
435 20 100       46 if ( Types::TypeTiny::is_StringLike( $code ) ) {
436 5         9 $coderef->add_line( $code );
437             }
438             else {
439 15         60 Types::TypeTiny::assert_CodeLike( $code );
440 15         83 my $varname = $coderef->add_variable( '$action', \$code );
441 15         39 $coderef->add_line( sprintf(
442             '%s->( @_ )',
443             $varname,
444             ) );
445             }
446 20         48 $coderef->decrease_indent;
447 20         33 $coderef->add_line( '}' );
448             } #/ while ( @_ )
449            
450 5         16 $coderef->add_line( 'else {' );
451 5         12 $coderef->increase_indent;
452 5         11 $coderef->add_line( 'Type::Utils::_croak( "No cases matched for %s", Type::Tiny::_dd( $_ ) );' );
453 5         15 $coderef->decrease_indent;
454 5         17 $coderef->add_line( '}' );
455            
456 5         15 $coderef->decrease_indent;
457 5         12 $coderef->add_line( '}' );
458            
459 5         20 return $coderef->compile;
460             } #/ sub compile_match_on_type
461              
462             sub classifier {
463 1     1 1 7 my $i;
464             compile_match_on_type(
465             +(
466             map {
467 8         7 my $type = $_->[0];
468 8     10   19 $type => sub { $type };
  10         5499  
469             }
470 1 50       5 sort { $b->[1] <=> $a->[1] or $a->[2] <=> $b->[2] }
  17         24  
471             map [ $_, scalar( my @parents = $_->parents ), ++$i ],
472             @_
473             ),
474             q[ undef ],
475             );
476             } #/ sub classifier
477              
478             {
479             package #hide
480             Type::Registry::DWIM;
481            
482             our @ISA = qw(Type::Registry);
483            
484             sub foreign_lookup {
485 3     3   7 my $self = shift;
486 3         20 my $r = $self->SUPER::foreign_lookup( @_ );
487 3 50       10 return $r if $r;
488            
489 3 50 33     35 if ( my $assume = $self->{"~~assume"}
490             and $_[0] =~ /[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*/ )
491             {
492 3 50       17 my @methods = ref( $assume ) ? @$assume : $assume;
493            
494 3         9 for my $method ( @methods ) {
495 9         58 $r = $self->$method( @_ );
496 9 100       21 return $r if $r;
497             }
498             } #/ if ( my $assume = $self...)
499            
500 0         0 return;
501             } #/ sub foreign_lookup
502            
503             sub lookup_via_moose {
504 3     3   7 my $self = shift;
505            
506 3 50       11 if ( $INC{'Moose/Meta/TypeConstraint.pm'} ) {
507 0         0 require Moose::Util::TypeConstraints;
508 0         0 require Types::TypeTiny;
509 0         0 my $r = Moose::Util::TypeConstraints::find_type_constraint( $_[0] );
510 0 0       0 return Types::TypeTiny::to_TypeTiny( $r ) if defined $r;
511             }
512            
513 3         7 return;
514             } #/ sub lookup_via_moose
515            
516             sub lookup_via_mouse {
517 3     3   7 my $self = shift;
518            
519 3 50       9 if ( $INC{'Mouse.pm'} ) {
520 0         0 require Mouse::Util::TypeConstraints;
521 0         0 require Types::TypeTiny;
522 0         0 my $r = Mouse::Util::TypeConstraints::find_type_constraint( $_[0] );
523 0 0       0 return Types::TypeTiny::to_TypeTiny( $r ) if defined $r;
524             }
525            
526 3         7 return;
527             } #/ sub lookup_via_mouse
528            
529             sub simple_lookup {
530 23     23   53 my $self = shift;
531 23         39 my $r;
532            
533             # If the lookup is chained to a class, then the class' own
534             # type registry gets first refusal.
535             #
536 23 50       76 if ( defined $self->{"~~chained"} ) {
537 23         95 my $chained = "Type::Registry"->for_class( $self->{"~~chained"} );
538 23 50       117 $r = eval { $chained->simple_lookup( @_ ) } unless $self == $chained;
  23         76  
539 23 100       153 return $r if defined $r;
540             }
541            
542             # Fall back to types in Types::Standard.
543 12         1010 require Types::Standard;
544 12 100       90 return 'Types::Standard'->get_type( $_[0] )
545             if 'Types::Standard'->has_type( $_[0] );
546            
547             # Only continue any further if we've been called from Type::Parser.
548 7 100       72 return unless $_[1];
549            
550 3         6 my $meta;
551 3 50       13 if ( defined $self->{"~~chained"} ) {
552 3 50 0     57 $meta ||= Moose::Util::find_meta( $self->{"~~chained"} ) if $INC{'Moose/Util.pm'};
553 3 50 0     11 $meta ||= Mouse::Util::find_meta( $self->{"~~chained"} ) if $INC{'Mouse.pm'};
554             }
555            
556 3 50 33     24 if ( $meta and $meta->isa( 'Class::MOP::Module' ) ) {
    50 33        
557 0         0 $r = $self->lookup_via_moose( @_ );
558 0 0       0 return $r if $r;
559             }
560            
561             elsif ( $meta and $meta->isa( 'Mouse::Meta::Module' ) ) {
562 0         0 $r = $self->lookup_via_mouse( @_ );
563 0 0       0 return $r if $r;
564             }
565            
566 3         15 return $self->foreign_lookup( @_ );
567             } #/ sub simple_lookup
568             }
569              
570             our $dwimmer;
571              
572             sub dwim_type {
573 19     19 1 307 my ( $string, %opts ) = @_;
574 19 100       95 $opts{for} = caller unless defined $opts{for};
575            
576 19   66     80 $dwimmer ||= do {
577 10         4923 require Type::Registry;
578 10         126 'Type::Registry::DWIM'->new;
579             };
580            
581 19         67 local $dwimmer->{'~~chained'} = $opts{for};
582             local $dwimmer->{'~~assume'} = $opts{fallback} || [
583             qw/ lookup_via_moose lookup_via_mouse /,
584 19   50     211 $opts{does} ? 'make_role_type' : 'make_class_type',
585             ];
586            
587 19         43 local $@ = undef;
588 19         34 my $type;
589 19 100       47 unless ( eval { $type = $dwimmer->lookup( $string ); 1 } ) {
  19         120  
  18         62  
590 1         3 my $e = $@;
591 1 50       40 die( $e ) unless $e =~ /not a known type constraint/;
592             }
593            
594 18         147 $type;
595             } #/ sub dwim_type
596              
597             my $TEMPLATE = <<'SUBTEMPLATE';
598             sub SUBNAME
599             {
600             require Types::TypeTiny;
601             no warnings 'uninitialized';
602            
603             my ($type, $value) = @_;
604             my $caller = caller;
605            
606             my $uniq = Types::TypeTiny::is_TypeTiny($type) ? $type->{uniq} : "$type";
607            
608             if (not Types::TypeTiny::is_TypeTiny $type) {
609             my $orig = $type;
610            
611             $type = $is_cache{$caller}{$uniq} || do {
612             Types::TypeTiny::is_StringLike($type)
613             ? eval { dwim_type("$type", for => $caller) }
614             : undef;
615             };
616            
617             if (blessed $type) {
618             $is_cache{$caller}{$uniq} ||= $type;
619             }
620             else {
621             my $thing = Type::Tiny::_dd($orig);
622             substr($thing, 0, 1) = lc substr($thing, 0, 1);
623             require Carp;
624             FAILURE
625             }
626             }
627            
628             my $check = ( $is_cache_coderef{$caller}{$uniq} ||= $type->compiled_check );
629            
630             BODY
631             }
632             SUBTEMPLATE
633              
634             my %is_cache;
635             my %is_cache_coderef;
636              
637             {
638             my $code = $TEMPLATE;
639             $code =~ s/SUBNAME/is/g;
640             $code =~
641             s/FAILURE/Carp::carp("Expected type, but got \$thing; returning false"); return undef;/g;
642             $code =~ s/BODY/0+!! \$check->(\$value)/;
643 109 100 100 109 1 858 eval $code;
  109 100 66 6   245  
  109 100 66     39032  
  6         394842  
  6         19  
  6         20  
  6         182  
  6         276  
  4         116  
  4         25  
  4         15  
  2         13  
  2         10  
  2         12  
  2         14  
  2         373  
  2         131  
  4         48  
  4         39  
644             }
645              
646             {
647             my $code = $TEMPLATE;
648             $code =~ s/SUBNAME/assert/g;
649             $code =~
650             s/FAILURE/Carp::croak("Expected type, but got \$thing; stopping"); return undef;/g;
651             $code =~
652             s/BODY/\$check->(\$value) ? \$value : \$type->_failed_check("\$type", \$value)/;
653 109 100 33 109 1 1154 eval $code;
  109 50 0 3   665  
  109 100 33     40710  
  3 100       1550  
  3         11  
  3         8  
  3         87  
  3         116  
  1         31  
  1         8  
  1         5  
  0         0  
  1         5  
  1         6  
  1         4  
  1         170  
  0         0  
  2         15  
  2         18  
654             }
655              
656             sub english_list {
657 113 100   113 1 6333 my $conjunction = ref( $_[0] ) eq 'SCALAR' ? ${ +shift } : 'and';
  2         5  
658 113         406 my @items = sort @_;
659            
660 113 100       1265 return $items[0] if @items == 1;
661 77 100       886 return "$items[0] $conjunction $items[1]" if @items == 2;
662            
663 33         91 my $tail = pop @items;
664 33         343 join( ', ', @items, "$conjunction $tail" );
665             } #/ sub english_list
666              
667             1;
668              
669             __END__