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 97     97   329157 use 5.008001;
  97         438  
4 97     97   666 use strict;
  97         275  
  97         2148  
5 97     85   571 use warnings;
  85         180  
  85         4010  
6              
7             BEGIN {
8 85     85   293 $Type::Utils::AUTHORITY = 'cpan:TOBYINK';
9 85         7012 $Type::Utils::VERSION = '2.002001';
10             }
11              
12             $Type::Utils::VERSION =~ tr/_//d;
13              
14 3     3   705 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  3         20  
15              
16 85     85   653 use Scalar::Util qw< blessed >;
  85         252  
  85         5279  
17 85     85   11458 use Type::Library;
  85         200  
  85         892  
18 85     85   3372 use Type::Tiny;
  85         251  
  85         2979  
19 85     85   496 use Types::TypeTiny qw< TypeTiny is_TypeTiny to_TypeTiny HashLike StringLike >;
  85         237  
  85         679  
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 48 50   48 1 15636 _croak "Not a type library" unless caller->isa( "Type::Library" );
48 48         261 my $caller = caller->meta;
49            
50 48         146 foreach my $lib ( @_ ) {
51 84 50   32   5810 eval "use $lib; 1" or _croak "Could not load library '$lib': $@";
  32     28   15168  
  32         180  
  32         360  
  28         14870  
  28         117  
  28         308  
52            
53 84 100 100     1016 if ( $lib->isa( "Type::Library" ) or $lib eq 'Types::TypeTiny' ) {
    50 33        
    50          
    50          
    50          
54 83         395 $caller->add_type( $lib->get_type( $_ ) ) for sort $lib->meta->type_names;
55             $caller->add_coercion( $lib->get_coercion( $_ ) )
56 83         615 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 85     85   102883 and my $types = do { no strict 'refs'; ${"$lib\::EXPORT_TAGS"}{'types'} } ) {
  85         198  
  85         73566  
  1         2  
  1         6  
99 1         2 for my $name ( @$types ) {
100 3         15 my $obj = $lib->$name;
101 3         61 my $tt = Types::TypeTiny::to_TypeTiny( $obj );
102 3         10 $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 374 my %opts;
115 255 100       840 if ( @_ % 2 == 0 ) {
116 140         468 %opts = @_;
117 140 100 100     477 if ( @_ == 2 and $_[0] =~ /^_*[A-Z]/ and $_[1] =~ /^[0-9]+$/ ) {
      66        
118 1         6 require Carp;
119 1         4 Carp::carp( "Possible missing comma after 'declare $_[0]'" );
120             }
121             }
122             else {
123 115         433 ( my ( $name ), %opts ) = @_;
124 115 50       334 _croak "Cannot provide two names for type" if exists $opts{name};
125 115         246 $opts{name} = $name;
126             }
127            
128 255   100     1098 my $caller = caller( $opts{_caller_level} || 0 );
129 255         498 $opts{library} = $caller;
130            
131 255 100       575 if ( defined $opts{parent} ) {
132 100         352 $opts{parent} = to_TypeTiny( $opts{parent} );
133            
134 100 100       2076 unless ( is_TypeTiny( $opts{parent} ) ) {
135             $caller->isa( "Type::Library" )
136             or _croak(
137             "Parent type cannot be a %s",
138 64 50 0     686 ref( $opts{parent} ) || 'non-reference scalar'
139             );
140             $opts{parent} = $caller->meta->get_type( $opts{parent} )
141 64 50       202 or _croak( "Could not find parent type" );
142             }
143             } #/ if ( defined $opts{parent...})
144            
145 255         434 my $type;
146 255 100       561 if ( defined $opts{parent} ) {
147 100         540 $type = delete( $opts{parent} )->create_child_type( %opts );
148             }
149             else {
150 155   100     469 my $bless = delete( $opts{bless} ) || "Type::Tiny";
151 155         8681 eval "require $bless";
152 155         1187 $type = $bless->new( %opts );
153             }
154            
155 255 100       1049 if ( not $type->is_anon ) {
156            
157 232 100       1700 $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       936 : ( $Type::Registry::DELAYED{$caller}{$opts{name}} = $type );
163             }
164            
165 254         5269 return $type;
166             } #/ sub declare
167              
168             *subtype = \&declare;
169             *type = \&declare;
170              
171             sub as (@) {
172 101     101 1 5804 parent => @_;
173             }
174              
175             sub where (&;@) {
176 86     86 1 3544 constraint => @_;
177             }
178              
179             sub message (&;@) {
180 50     50 1 4787 message => @_;
181             }
182              
183             sub inline_as (&;@) {
184 0     0 1 0 inlined => @_;
185             }
186              
187             sub class_type {
188 51 100   51 1 318 my $name = ref( $_[0] ) eq 'HASH' ? undef : shift;
189 51 100       86 my %opts = %{ shift or {} };
  51         314  
190            
191 51 100       239 if ( defined $name ) {
192 43 50       157 $opts{name} = $name unless exists $opts{name};
193 43 100       178 $opts{class} = $name unless exists $opts{class};
194            
195 43         169 $opts{name} =~ s/:://g;
196             }
197            
198 51         118 $opts{bless} = "Type::Tiny::Class";
199            
200 85     85   739 { no warnings "numeric"; $opts{_caller_level}++ }
  85         196  
  85         16447  
  51         90  
  51         111  
201 51         178 declare( %opts );
202             } #/ sub class_type
203              
204             sub role_type {
205 19 100   19 1 124 my $name = ref( $_[0] ) eq 'HASH' ? undef : shift;
206 19 50       41 my %opts = %{ shift or {} };
  19         133  
207            
208 19 100       71 if ( defined $name ) {
209 18 50       155 $opts{name} = $name unless exists $opts{name};
210 18 50       69 $opts{role} = $name unless exists $opts{role};
211            
212 18         70 $opts{name} =~ s/:://g;
213             }
214            
215 19         47 $opts{bless} = "Type::Tiny::Role";
216            
217 85     85   738 { no warnings "numeric"; $opts{_caller_level}++ }
  85         216  
  85         13264  
  19         29  
  19         43  
218 19         87 declare( %opts );
219             } #/ sub role_type
220              
221             sub duck_type {
222 35 50   35 1 232 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
223 35 50       59 my @methods = @{ shift or [] };
  35         133  
224            
225 35         58 my %opts;
226 35 50       111 $opts{name} = $name if defined $name;
227 35         73 $opts{methods} = \@methods;
228            
229 35         67 $opts{bless} = "Type::Tiny::Duck";
230            
231 85     85   654 { no warnings "numeric"; $opts{_caller_level}++ }
  85         218  
  85         13112  
  35         48  
  35         63  
232 35         131 declare( %opts );
233             } #/ sub duck_type
234              
235             sub enum {
236 15 50   15 1 2939 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
237 15 50       32 my @values = @{ shift or [] };
  15         61  
238            
239 15         382 my %opts;
240 15 50       53 $opts{name} = $name if defined $name;
241 15         36 $opts{values} = \@values;
242            
243 15         32 $opts{bless} = "Type::Tiny::Enum";
244            
245 85     85   608 { no warnings "numeric"; $opts{_caller_level}++ }
  85         219  
  85         12802  
  15         21  
  15         29  
246 15         56 declare( %opts );
247             } #/ sub enum
248              
249             sub union {
250 10 100   10 1 310 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
251 10 50       21 my @tcs = @{ shift or [] };
  10         43  
252            
253 10         18 my %opts;
254 10 100       37 $opts{name} = $name if defined $name;
255 10         28 $opts{type_constraints} = \@tcs;
256            
257 10         21 $opts{bless} = "Type::Tiny::Union";
258            
259 85     85   637 { no warnings "numeric"; $opts{_caller_level}++ }
  85         198  
  85         12793  
  10         17  
  10         23  
260 10         43 declare( %opts );
261             } #/ sub union
262              
263             sub intersection {
264 7 100   7 1 180 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
265 7 50       16 my @tcs = @{ shift or [] };
  7         31  
266            
267 7         13 my %opts;
268 7 100       28 $opts{name} = $name if defined $name;
269 7         22 $opts{type_constraints} = \@tcs;
270            
271 7         16 $opts{bless} = "Type::Tiny::Intersection";
272            
273 85     85   625 { no warnings "numeric"; $opts{_caller_level}++ }
  85         190  
  85         209457  
  7         12  
  7         19  
274 7         27 declare( %opts );
275             } #/ sub intersection
276              
277             sub declare_coercion {
278 33     33 1 61 my %opts;
279 33 100       136 $opts{name} = shift if !ref( $_[0] );
280            
281             # I don't like this; it is a hack
282 33 100       117 if ( ref( $_[0] ) eq 'Type::Tiny::_DeclaredType' ) {
283 1         5 $opts{name} = '' . shift;
284             }
285            
286 33   66     686 while ( Types::TypeTiny::is_HashLike( $_[0] ) and not is_TypeTiny( $_[0] ) ) {
287 33         319 %opts = ( %opts, %{ +shift } );
  33         221  
288             }
289            
290 33   50     196 my $caller = caller( $opts{_caller_level} || 0 );
291 33         71 $opts{library} = $caller;
292            
293 33   50     155 my $bless = delete( $opts{bless} ) || "Type::Coercion";
294 33         1902 eval "require $bless";
295 33         332 my $c = $bless->new( %opts );
296            
297 33         64 my @C;
298            
299 33 100       170 if ( $caller->isa( "Type::Library" ) ) {
300 32         106 my $meta = $caller->meta;
301 32 100       352 $meta->add_coercion( $c ) unless $c->is_anon;
302 32         160 while ( @_ ) {
303             push @C,
304 32 100 33     111 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  32         137  
305 32         122 push @C, shift;
306             }
307             }
308             else {
309 1         4 @C = @_;
310             }
311            
312 33         327 $c->add_type_coercions( @C );
313            
314 33         125 return $c->freeze;
315             } #/ sub declare_coercion
316              
317             sub coerce {
318 51 100   51 1 288 if ( ( scalar caller )->isa( "Type::Library" ) ) {
319 35         145 my $meta = ( scalar caller )->meta;
320             my ( $type ) =
321 35 100 33     120 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  35         150  
322 35         64 my @opts;
323 35         149 while ( @_ ) {
324             push @opts,
325 65 100 33     138 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  65         244  
326 65         153 push @opts, shift;
327             }
328 35         140 return $type->coercion->add_type_coercions( @opts );
329             } #/ if ( ( scalar caller )...)
330            
331 16         42 my ( $type, @opts ) = @_;
332 16         37 $type = to_TypeTiny( $type );
333 16         48 return $type->coercion->add_type_coercions( @opts );
334             } #/ sub coerce
335              
336             sub from (@) {
337 114     114 1 598 return @_;
338             }
339              
340             sub to_type (@) {
341 33     33 1 109 my $type = shift;
342 33 100       513 unless ( is_TypeTiny( $type ) ) {
343 30 50       321 caller->isa( "Type::Library" )
344             or _croak "Target type cannot be a string";
345 30 50       276 $type = caller->meta->get_type( $type )
346             or _croak "Could not find target type";
347             }
348 33         261 return +{ type_constraint => $type }, @_;
349             } #/ sub to_type (@)
350              
351             sub via (&;@) {
352 69     69 1 582 return @_;
353             }
354              
355             sub match_on_type {
356 40017     40017 1 77157 my $value = shift;
357            
358 40017         92317 while ( @_ ) {
359 115043         189276 my $code;
360 115043 100       204320 if ( @_ == 1 ) {
361 1         2 $code = shift;
362             }
363             else {
364 115042         224355 ( my ( $type ), $code ) = splice( @_, 0, 2 );
365 115042 100       2318328 Types::TypeTiny::assert_TypeTiny( $type )->check( $value ) or next;
366             }
367            
368 40016 100       214880 if ( Types::TypeTiny::is_StringLike( $code ) ) {
369 30010         51653 local $_ = $value;
370 30010 100       56808 if ( wantarray ) {
371 15004         805711 my @r = eval "$code";
372 15004 50       54874 die $@ if $@;
373 15004         100103 return @r;
374             }
375 15006 100       27896 if ( defined wantarray ) {
376 15005         661905 my $r = eval "$code";
377 15005 50       55904 die $@ if $@;
378 15005         103263 return $r;
379             }
380 1         61 eval "$code";
381 1 50       7 die $@ if $@;
382 1         7 return;
383             } #/ if ( Types::TypeTiny::is_StringLike...)
384             else {
385 10006         33706 Types::TypeTiny::assert_CodeLike( $code );
386 10006         46001 local $_ = $value;
387 10006         26121 return $code->( $value );
388             }
389             } #/ while ( @_ )
390            
391 1         8 _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 1301 require Eval::TypeTiny::CodeAccumulator;
396 5         41 my $coderef = 'Eval::TypeTiny::CodeAccumulator'->new(
397             description => 'compiled match',
398             );
399 5         21 $coderef->add_line( 'sub {' );
400 5         19 $coderef->increase_indent;
401 5         15 $coderef->add_line( 'local $_ = $_[0];' );
402            
403 5         12 my $els = '';
404            
405 5         30 while ( @_ ) {
406 20         38 my ( $type, $code );
407 20 100       43 if ( @_ == 1 ) {
408 2         11 require Types::Standard;
409 2         11 ( $type, $code ) = ( Types::Standard::Any(), shift );
410             }
411             else {
412 18         43 ( $type, $code ) = splice( @_, 0, 2 );
413 18         426 Types::TypeTiny::assert_TypeTiny( $type );
414             }
415            
416 20 100       67 if ( $type->can_be_inlined ) {
417 19         57 $coderef->add_line( sprintf(
418             '%sif ( %s ) {',
419             $els,
420             $type->inline_check( '$_' ),
421             ) );
422             }
423             else {
424 1         5 my $varname = $coderef->add_variable( '$type', \$type );
425 1         6 $coderef->add_line( sprintf(
426             '%sif ( %s->check($_) ) {',
427             $els,
428             $varname,
429             ) );
430             }
431 20         64 $coderef->increase_indent;
432            
433 20         33 $els = 'els';
434            
435 20 100       59 if ( Types::TypeTiny::is_StringLike( $code ) ) {
436 5         11 $coderef->add_line( $code );
437             }
438             else {
439 15         51 Types::TypeTiny::assert_CodeLike( $code );
440 15         91 my $varname = $coderef->add_variable( '$action', \$code );
441 15         52 $coderef->add_line( sprintf(
442             '%s->( @_ )',
443             $varname,
444             ) );
445             }
446 20         57 $coderef->decrease_indent;
447 20         43 $coderef->add_line( '}' );
448             } #/ while ( @_ )
449            
450 5         20 $coderef->add_line( 'else {' );
451 5         16 $coderef->increase_indent;
452 5         16 $coderef->add_line( 'Type::Utils::_croak( "No cases matched for %s", Type::Tiny::_dd( $_ ) );' );
453 5         18 $coderef->decrease_indent;
454 5         16 $coderef->add_line( '}' );
455            
456 5         23 $coderef->decrease_indent;
457 5         628 $coderef->add_line( '}' );
458            
459 5         24 return $coderef->compile;
460             } #/ sub compile_match_on_type
461              
462             sub classifier {
463 1     1 1 9 my $i;
464             compile_match_on_type(
465             +(
466             map {
467 8         14 my $type = $_->[0];
468 8     10   24 $type => sub { $type };
  10         5149  
469             }
470 1 50       6 sort { $b->[1] <=> $a->[1] or $a->[2] <=> $b->[2] }
  17         70  
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   5 my $self = shift;
486 3         12 my $r = $self->SUPER::foreign_lookup( @_ );
487 3 50       7 return $r if $r;
488            
489 3 50 33     22 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       12 my @methods = ref( $assume ) ? @$assume : $assume;
493            
494 3         6 for my $method ( @methods ) {
495 9         32 $r = $self->$method( @_ );
496 9 100       18 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   6 my $self = shift;
505            
506 3 50       7 if ( $INC{'Moose.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         12 return;
514             } #/ sub lookup_via_moose
515            
516             sub lookup_via_mouse {
517 3     3   5 my $self = shift;
518            
519 3 50       7 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         4 return;
527             } #/ sub lookup_via_mouse
528            
529             sub simple_lookup {
530 11     11   17 my $self = shift;
531 11         15 my $r;
532            
533             # If the lookup is chained to a class, then the class' own
534             # type registry gets first refusal.
535             #
536 11 50       30 if ( defined $self->{"~~chained"} ) {
537 11         39 my $chained = "Type::Registry"->for_class( $self->{"~~chained"} );
538 11 50       29 $r = eval { $chained->simple_lookup( @_ ) } unless $self == $chained;
  11         71  
539 11 100       45 return $r if defined $r;
540             }
541            
542             # Fall back to types in Types::Standard.
543 8         38 require Types::Standard;
544 8 100       40 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       30 return unless $_[1];
549            
550 3         6 my $meta;
551 3 50       14 if ( defined $self->{"~~chained"} ) {
552 3 50 0     19 $meta ||= Moose::Util::find_meta( $self->{"~~chained"} ) if $INC{'Moose.pm'};
553 3 50 0     10 $meta ||= Mouse::Util::find_meta( $self->{"~~chained"} ) if $INC{'Mouse.pm'};
554             }
555            
556 3 50 33     17 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         10 return $self->foreign_lookup( @_ );
567             } #/ sub simple_lookup
568             }
569              
570             our $dwimmer;
571              
572             sub dwim_type {
573 7     7 1 190 my ( $string, %opts ) = @_;
574 7 100       30 $opts{for} = caller unless defined $opts{for};
575            
576 7   66     27 $dwimmer ||= do {
577 3         530 require Type::Registry;
578 3         32 'Type::Registry::DWIM'->new;
579             };
580            
581 7         24 local $dwimmer->{'~~chained'} = $opts{for};
582             local $dwimmer->{'~~assume'} = $opts{fallback} || [
583             qw/ lookup_via_moose lookup_via_mouse /,
584 7   50     55 $opts{does} ? 'make_role_type' : 'make_class_type',
585             ];
586            
587 7         15 local $@ = undef;
588 7         12 my $type;
589 7 100       14 unless ( eval { $type = $dwimmer->lookup( $string ); 1 } ) {
  7         34  
  6         29  
590 1         3 my $e = $@;
591 1 50       36 die( $e ) unless $e =~ /not a known type constraint/;
592             }
593            
594 6         54 $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 85 100 100 85 1 645 eval $code;
  85 100 66 6   214  
  85 100 66     24087  
  6         1220  
  6         19  
  6         14  
  6         114  
  6         185  
  4         76  
  4         20  
  4         20  
  2         12  
  2         8  
  2         13  
  2         11  
  2         362  
  2         103  
  4         30  
  4         36  
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 85 100 33 85 1 695 eval $code;
  85 50 0 3   254  
  85 100 33     22513  
  3 100       1176  
  3         11  
  3         6  
  3         59  
  3         75  
  1         20  
  1         6  
  1         12  
  0         0  
  1         4  
  1         6  
  1         4  
  1         119  
  0         0  
  2         12  
  2         18  
654             }
655              
656             sub english_list {
657 107 100   107 1 4344 my $conjunction = ref( $_[0] ) eq 'SCALAR' ? ${ +shift } : 'and';
  2         5  
658 107         364 my @items = sort @_;
659            
660 107 100       551 return $items[0] if @items == 1;
661 75 100       536 return "$items[0] $conjunction $items[1]" if @items == 2;
662            
663 33         72 my $tail = pop @items;
664 33         303 join( ', ', @items, "$conjunction $tail" );
665             } #/ sub english_list
666              
667             1;
668              
669             __END__