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 103     103   309170 use 5.008001;
  103         459  
4 103     103   713 use strict;
  103         466  
  103         2194  
5 103     88   597 use warnings;
  88         201  
  88         4180  
6              
7             BEGIN {
8 88     88   311 $Type::Utils::AUTHORITY = 'cpan:TOBYINK';
9 88         6964 $Type::Utils::VERSION = '2.004000';
10             }
11              
12             $Type::Utils::VERSION =~ tr/_//d;
13              
14 3     3   18 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  3         21  
15              
16 88     88   705 use Scalar::Util qw< blessed >;
  88         811  
  88         5702  
17 88     88   12747 use Type::Library;
  88         208  
  88         861  
18 88     88   3309 use Type::Tiny;
  88         240  
  88         2903  
19 88     88   554 use Types::TypeTiny qw< TypeTiny is_TypeTiny to_TypeTiny HashLike StringLike >;
  88         202  
  88         713  
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 51 50   51 1 14903 _croak "Not a type library" unless caller->isa( "Type::Library" );
48 51         257 my $caller = caller->meta;
49            
50 51         144 foreach my $lib ( @_ ) {
51 96 50   35   6396 eval "use $lib; 1" or _croak "Could not load library '$lib': $@";
  35     31   16054  
  35         131  
  35         1614  
  31         17478  
  31         118  
  31         345  
52            
53 96 100 100     1283 if ( $lib->isa( "Type::Library" ) or $lib eq 'Types::TypeTiny' ) {
    50 33        
    50          
    50          
    50          
54 95         454 $caller->add_type( $lib->get_type( $_ ) ) for sort $lib->meta->type_names;
55             $caller->add_coercion( $lib->get_coercion( $_ ) )
56 95         601 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 88     88   111288 and my $types = do { no strict 'refs'; ${"$lib\::EXPORT_TAGS"}{'types'} } ) {
  88         205  
  88         72042  
  1         1  
  1         8  
99 1         3 for my $name ( @$types ) {
100 3         17 my $obj = $lib->$name;
101 3         24 my $tt = Types::TypeTiny::to_TypeTiny( $obj );
102 3         11 $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 403 my %opts;
115 255 100       852 if ( @_ % 2 == 0 ) {
116 140         450 %opts = @_;
117 140 100 100     502 if ( @_ == 2 and $_[0] =~ /^_*[A-Z]/ and $_[1] =~ /^[0-9]+$/ ) {
      66        
118 1         6 require Carp;
119 1         5 Carp::carp( "Possible missing comma after 'declare $_[0]'" );
120             }
121             }
122             else {
123 115         430 ( my ( $name ), %opts ) = @_;
124 115 50       345 _croak "Cannot provide two names for type" if exists $opts{name};
125 115         275 $opts{name} = $name;
126             }
127            
128 255   100     996 my $caller = caller( $opts{_caller_level} || 0 );
129 255         445 $opts{library} = $caller;
130            
131 255 100       635 if ( defined $opts{parent} ) {
132 100         440 $opts{parent} = to_TypeTiny( $opts{parent} );
133            
134 100 100       2184 unless ( is_TypeTiny( $opts{parent} ) ) {
135             $caller->isa( "Type::Library" )
136             or _croak(
137             "Parent type cannot be a %s",
138 64 50 0     671 ref( $opts{parent} ) || 'non-reference scalar'
139             );
140             $opts{parent} = $caller->meta->get_type( $opts{parent} )
141 64 50       204 or _croak( "Could not find parent type" );
142             }
143             } #/ if ( defined $opts{parent...})
144            
145 255         420 my $type;
146 255 100       557 if ( defined $opts{parent} ) {
147 100         539 $type = delete( $opts{parent} )->create_child_type( %opts );
148             }
149             else {
150 155   100     447 my $bless = delete( $opts{bless} ) || "Type::Tiny";
151 155         8587 eval "require $bless";
152 155         1199 $type = $bless->new( %opts );
153             }
154            
155 255 100       1072 if ( not $type->is_anon ) {
156            
157 232 100       1878 $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       897 : ( $Type::Registry::DELAYED{$caller}{$opts{name}} = $type );
163             }
164            
165 254         5202 return $type;
166             } #/ sub declare
167              
168             *subtype = \&declare;
169             *type = \&declare;
170              
171             sub as (@) {
172 101     101 1 6860 parent => @_;
173             }
174              
175             sub where (&;@) {
176 86     86 1 3490 constraint => @_;
177             }
178              
179             sub message (&;@) {
180 50     50 1 4522 message => @_;
181             }
182              
183             sub inline_as (&;@) {
184 0     0 1 0 inlined => @_;
185             }
186              
187             sub class_type {
188 51 100   51 1 321 my $name = ref( $_[0] ) eq 'HASH' ? undef : shift;
189 51 100       87 my %opts = %{ shift or {} };
  51         297  
190            
191 51 100       174 if ( defined $name ) {
192 43 50       149 $opts{name} = $name unless exists $opts{name};
193 43 100       296 $opts{class} = $name unless exists $opts{class};
194            
195 43         174 $opts{name} =~ s/:://g;
196             }
197            
198 51         111 $opts{bless} = "Type::Tiny::Class";
199            
200 88     88   807 { no warnings "numeric"; $opts{_caller_level}++ }
  88         184  
  88         17404  
  51         77  
  51         105  
201 51         165 declare( %opts );
202             } #/ sub class_type
203              
204             sub role_type {
205 19 100   19 1 114 my $name = ref( $_[0] ) eq 'HASH' ? undef : shift;
206 19 50       40 my %opts = %{ shift or {} };
  19         117  
207            
208 19 100       88 if ( defined $name ) {
209 18 50       86 $opts{name} = $name unless exists $opts{name};
210 18 50       67 $opts{role} = $name unless exists $opts{role};
211            
212 18         61 $opts{name} =~ s/:://g;
213             }
214            
215 19         49 $opts{bless} = "Type::Tiny::Role";
216            
217 88     88   728 { no warnings "numeric"; $opts{_caller_level}++ }
  88         198  
  88         13094  
  19         40  
  19         50  
218 19         109 declare( %opts );
219             } #/ sub role_type
220              
221             sub duck_type {
222 35 50   35 1 274 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
223 35 50       92 my @methods = @{ shift or [] };
  35         144  
224            
225 35         60 my %opts;
226 35 50       118 $opts{name} = $name if defined $name;
227 35         93 $opts{methods} = \@methods;
228            
229 35         70 $opts{bless} = "Type::Tiny::Duck";
230            
231 88     88   738 { no warnings "numeric"; $opts{_caller_level}++ }
  88         240  
  88         12625  
  35         47  
  35         68  
232 35         114 declare( %opts );
233             } #/ sub duck_type
234              
235             sub enum {
236 15 50   15 1 2983 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
237 15 50       27 my @values = @{ shift or [] };
  15         63  
238            
239 15         31 my %opts;
240 15 50       59 $opts{name} = $name if defined $name;
241 15         33 $opts{values} = \@values;
242            
243 15         38 $opts{bless} = "Type::Tiny::Enum";
244            
245 88     88   678 { no warnings "numeric"; $opts{_caller_level}++ }
  88         191  
  88         12699  
  15         24  
  15         34  
246 15         55 declare( %opts );
247             } #/ sub enum
248              
249             sub union {
250 10 100   10 1 290 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
251 10 50       21 my @tcs = @{ shift or [] };
  10         46  
252            
253 10         21 my %opts;
254 10 100       33 $opts{name} = $name if defined $name;
255 10         71 $opts{type_constraints} = \@tcs;
256            
257 10         30 $opts{bless} = "Type::Tiny::Union";
258            
259 88     88   671 { no warnings "numeric"; $opts{_caller_level}++ }
  88         244  
  88         12809  
  10         15  
  10         27  
260 10         40 declare( %opts );
261             } #/ sub union
262              
263             sub intersection {
264 7 100   7 1 161 my $name = ref( $_[0] ) eq 'ARRAY' ? undef : shift;
265 7 50       15 my @tcs = @{ shift or [] };
  7         32  
266            
267 7         14 my %opts;
268 7 100       26 $opts{name} = $name if defined $name;
269 7         18 $opts{type_constraints} = \@tcs;
270            
271 7         18 $opts{bless} = "Type::Tiny::Intersection";
272            
273 88     88   666 { no warnings "numeric"; $opts{_caller_level}++ }
  88         219  
  88         207083  
  7         12  
  7         15  
274 7         30 declare( %opts );
275             } #/ sub intersection
276              
277             sub declare_coercion {
278 33     33 1 55 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       155 if ( ref( $_[0] ) eq 'Type::Tiny::_DeclaredType' ) {
283 1         5 $opts{name} = '' . shift;
284             }
285            
286 33   66     680 while ( Types::TypeTiny::is_HashLike( $_[0] ) and not is_TypeTiny( $_[0] ) ) {
287 33         266 %opts = ( %opts, %{ +shift } );
  33         201  
288             }
289            
290 33   50     192 my $caller = caller( $opts{_caller_level} || 0 );
291 33         85 $opts{library} = $caller;
292            
293 33   50     122 my $bless = delete( $opts{bless} ) || "Type::Coercion";
294 33         1775 eval "require $bless";
295 33         228 my $c = $bless->new( %opts );
296            
297 33         70 my @C;
298            
299 33 100       180 if ( $caller->isa( "Type::Library" ) ) {
300 32         104 my $meta = $caller->meta;
301 32 100       89 $meta->add_coercion( $c ) unless $c->is_anon;
302 32         121 while ( @_ ) {
303             push @C,
304 32 100 33     82 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  32         141  
305 32         112 push @C, shift;
306             }
307             }
308             else {
309 1         3 @C = @_;
310             }
311            
312 33         135 $c->add_type_coercions( @C );
313            
314 33         112 return $c->freeze;
315             } #/ sub declare_coercion
316              
317             sub coerce {
318 51 100   51 1 415 if ( ( scalar caller )->isa( "Type::Library" ) ) {
319 35         136 my $meta = ( scalar caller )->meta;
320             my ( $type ) =
321 35 100 33     113 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  35         200  
322 35         90 my @opts;
323 35         141 while ( @_ ) {
324             push @opts,
325 65 100 33     152 map { ref( $_ ) ? to_TypeTiny( $_ ) : $meta->get_type( $_ ) || $_ } shift;
  65         481  
326 65         173 push @opts, shift;
327             }
328 35         159 return $type->coercion->add_type_coercions( @opts );
329             } #/ if ( ( scalar caller )...)
330            
331 16         48 my ( $type, @opts ) = @_;
332 16         42 $type = to_TypeTiny( $type );
333 16         49 return $type->coercion->add_type_coercions( @opts );
334             } #/ sub coerce
335              
336             sub from (@) {
337 114     114 1 645 return @_;
338             }
339              
340             sub to_type (@) {
341 33     33 1 73 my $type = shift;
342 33 100       572 unless ( is_TypeTiny( $type ) ) {
343 30 50       311 caller->isa( "Type::Library" )
344             or _croak "Target type cannot be a string";
345 30 50       112 $type = caller->meta->get_type( $type )
346             or _croak "Could not find target type";
347             }
348 33         248 return +{ type_constraint => $type }, @_;
349             } #/ sub to_type (@)
350              
351             sub via (&;@) {
352 69     69 1 784 return @_;
353             }
354              
355             sub match_on_type {
356 40017     40017 1 77184 my $value = shift;
357            
358 40017         96640 while ( @_ ) {
359 115043         196270 my $code;
360 115043 100       212792 if ( @_ == 1 ) {
361 1         2 $code = shift;
362             }
363             else {
364 115042         220488 ( my ( $type ), $code ) = splice( @_, 0, 2 );
365 115042 100       2398232 Types::TypeTiny::assert_TypeTiny( $type )->check( $value ) or next;
366             }
367            
368 40016 100       219131 if ( Types::TypeTiny::is_StringLike( $code ) ) {
369 30010         49143 local $_ = $value;
370 30010 100       72207 if ( wantarray ) {
371 15004         827092 my @r = eval "$code";
372 15004 50       55405 die $@ if $@;
373 15004         103919 return @r;
374             }
375 15006 100       29917 if ( defined wantarray ) {
376 15005         680103 my $r = eval "$code";
377 15005 50       53249 die $@ if $@;
378 15005         112902 return $r;
379             }
380 1         57 eval "$code";
381 1 50       8 die $@ if $@;
382 1         5 return;
383             } #/ if ( Types::TypeTiny::is_StringLike...)
384             else {
385 10006         30322 Types::TypeTiny::assert_CodeLike( $code );
386 10006         47774 local $_ = $value;
387 10006         28576 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 1443 require Eval::TypeTiny::CodeAccumulator;
396 5         40 my $coderef = 'Eval::TypeTiny::CodeAccumulator'->new(
397             description => 'compiled match',
398             );
399 5         21 $coderef->add_line( 'sub {' );
400 5         18 $coderef->increase_indent;
401 5         22 $coderef->add_line( 'local $_ = $_[0];' );
402            
403 5         16 my $els = '';
404            
405 5         15 while ( @_ ) {
406 20         32 my ( $type, $code );
407 20 100       47 if ( @_ == 1 ) {
408 2         10 require Types::Standard;
409 2         12 ( $type, $code ) = ( Types::Standard::Any(), shift );
410             }
411             else {
412 18         45 ( $type, $code ) = splice( @_, 0, 2 );
413 18         424 Types::TypeTiny::assert_TypeTiny( $type );
414             }
415            
416 20 100       80 if ( $type->can_be_inlined ) {
417 19         51 $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         38 $els = 'els';
434            
435 20 100       58 if ( Types::TypeTiny::is_StringLike( $code ) ) {
436 5         14 $coderef->add_line( $code );
437             }
438             else {
439 15         50 Types::TypeTiny::assert_CodeLike( $code );
440 15         93 my $varname = $coderef->add_variable( '$action', \$code );
441 15         54 $coderef->add_line( sprintf(
442             '%s->( @_ )',
443             $varname,
444             ) );
445             }
446 20         50 $coderef->decrease_indent;
447 20         44 $coderef->add_line( '}' );
448             } #/ while ( @_ )
449            
450 5         18 $coderef->add_line( 'else {' );
451 5         14 $coderef->increase_indent;
452 5         16 $coderef->add_line( 'Type::Utils::_croak( "No cases matched for %s", Type::Tiny::_dd( $_ ) );' );
453 5         14 $coderef->decrease_indent;
454 5         18 $coderef->add_line( '}' );
455            
456 5         12 $coderef->decrease_indent;
457 5         15 $coderef->add_line( '}' );
458            
459 5         27 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         17 my $type = $_->[0];
468 8     10   19 $type => sub { $type };
  10         4969  
469             }
470 1 50       5 sort { $b->[1] <=> $a->[1] or $a->[2] <=> $b->[2] }
  17         32  
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   4 my $self = shift;
486 3         10 my $r = $self->SUPER::foreign_lookup( @_ );
487 3 50       7 return $r if $r;
488            
489 3 50 33     38 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       13 my @methods = ref( $assume ) ? @$assume : $assume;
493            
494 3         7 for my $method ( @methods ) {
495 9         30 $r = $self->$method( @_ );
496 9 100       19 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   5 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         5 return;
514             } #/ sub lookup_via_moose
515            
516             sub lookup_via_mouse {
517 3     3   4 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   16 my $self = shift;
531 11         25 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       26 if ( defined $self->{"~~chained"} ) {
537 11         41 my $chained = "Type::Registry"->for_class( $self->{"~~chained"} );
538 11 50       46 $r = eval { $chained->simple_lookup( @_ ) } unless $self == $chained;
  11         30  
539 11 100       41 return $r if defined $r;
540             }
541            
542             # Fall back to types in Types::Standard.
543 8         41 require Types::Standard;
544 8 100       45 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       91 return unless $_[1];
549            
550 3         4 my $meta;
551 3 50       5 if ( defined $self->{"~~chained"} ) {
552 3 50 0     8 $meta ||= Moose::Util::find_meta( $self->{"~~chained"} ) if $INC{'Moose.pm'};
553 3 50 0     7 $meta ||= Mouse::Util::find_meta( $self->{"~~chained"} ) if $INC{'Mouse.pm'};
554             }
555            
556 3 50 33     15 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         9 return $self->foreign_lookup( @_ );
567             } #/ sub simple_lookup
568             }
569              
570             our $dwimmer;
571              
572             sub dwim_type {
573 7     7 1 192 my ( $string, %opts ) = @_;
574 7 100       55 $opts{for} = caller unless defined $opts{for};
575            
576 7   66     22 $dwimmer ||= do {
577 3         496 require Type::Registry;
578 3         32 'Type::Registry::DWIM'->new;
579             };
580            
581 7         22 local $dwimmer->{'~~chained'} = $opts{for};
582             local $dwimmer->{'~~assume'} = $opts{fallback} || [
583             qw/ lookup_via_moose lookup_via_mouse /,
584 7   50     50 $opts{does} ? 'make_role_type' : 'make_class_type',
585             ];
586            
587 7         15 local $@ = undef;
588 7         14 my $type;
589 7 100       12 unless ( eval { $type = $dwimmer->lookup( $string ); 1 } ) {
  7         32  
  6         24  
590 1         3 my $e = $@;
591 1 50       26 die( $e ) unless $e =~ /not a known type constraint/;
592             }
593            
594 6         37 $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 88 100 100 88 1 691 eval $code;
  88 100 66 6   205  
  88 100 66     22676  
  6         1464  
  6         18  
  6         15  
  6         116  
  6         189  
  4         78  
  4         18  
  4         18  
  2         10  
  2         8  
  2         13  
  2         10  
  2         292  
  2         65  
  4         38  
  4         41  
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 88 100 33 88 1 663 eval $code;
  88 50 0 3   199  
  88 100 33     22316  
  3 100       1335  
  3         10  
  3         7  
  3         60  
  3         77  
  1         50  
  1         13  
  1         14  
  0         0  
  1         5  
  1         7  
  1         4  
  1         131  
  0         0  
  2         10  
  2         17  
654             }
655              
656             sub english_list {
657 107 100   107 1 4244 my $conjunction = ref( $_[0] ) eq 'SCALAR' ? ${ +shift } : 'and';
  2         6  
658 107         321 my @items = sort @_;
659            
660 107 100       538 return $items[0] if @items == 1;
661 75 100       557 return "$items[0] $conjunction $items[1]" if @items == 2;
662            
663 33         70 my $tail = pop @items;
664 33         310 join( ', ', @items, "$conjunction $tail" );
665             } #/ sub english_list
666              
667             1;
668              
669             __END__