File Coverage

blib/lib/Types/TypeTiny.pm
Criterion Covered Total %
statement 373 443 80.3
branch 171 228 75.0
condition 74 99 74.7
subroutine 91 102 82.3
pod 8 21 38.1
total 717 893 77.6


line stmt bran cond sub pod time code
1             package Types::TypeTiny;
2              
3 317     317   7722 use 5.008001;
  317         1980  
4 317     317   1832 use strict;
  317         678  
  317         7231  
5 317     317   1541 use warnings;
  317         893  
  317         26205  
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '2.003_000';
9              
10             $VERSION =~ tr/_//d;
11              
12 317     317   2381 use Scalar::Util qw< blessed refaddr weaken >;
  317         898  
  317         45934  
13              
14             BEGIN {
15             *__XS = eval {
16 317         160494 require Type::Tiny::XS;
17 317         1002871 'Type::Tiny::XS'->VERSION( '0.022' );
18 317         26202 1;
19             }
20             ? eval "sub () { '$Type::Tiny::XS::VERSION' }"
21 317 50   317   1298 : sub () { !!0 };
22             }
23              
24             our @EXPORT_OK = (
25             map( @{ [ $_, "is_$_", "assert_$_" ] }, __PACKAGE__->type_names ),
26             qw/to_TypeTiny/
27             );
28             our %EXPORT_TAGS = (
29             types => [ __PACKAGE__->type_names ],
30             is => [ map "is_$_", __PACKAGE__->type_names ],
31             assert => [ map "assert_$_", __PACKAGE__->type_names ],
32             );
33              
34             my %cache;
35              
36             # This `import` method is designed to avoid loading Exporter::Tiny.
37             # This is so that if you stick to only using the purely OO parts of
38             # Type::Tiny, you can skip loading the exporter.
39             #
40             sub import {
41              
42             # If this sub succeeds, it will replace itself.
43             # uncoverable subroutine
44 38 100   38   2924 return unless @_ > 1; # uncoverable statement
45 317     317   2498 no warnings "redefine"; # uncoverable statement
  317         809  
  317         75983  
46 36         781 our @ISA = qw( Exporter::Tiny ); # uncoverable statement
47 36         296 require Exporter::Tiny; # uncoverable statement
48 36         153 my $next = \&Exporter::Tiny::import; # uncoverable statement
49 36         174 *import = $next; # uncoverable statement
50 36         105 my $class = shift; # uncoverable statement
51 36 50       274 my $opts = { ref( $_[0] ) ? %{ +shift } : () }; # uncoverable statement
  0         0  
52 36   50     379 $opts->{into} ||= scalar( caller ); # uncoverable statement
53 36         216 _mkall(); # uncoverable statement
54 36         295 return $class->$next( $opts, @_ ); # uncoverable statement
55             } #/ sub import
56              
57             for ( __PACKAGE__->type_names ) { # uncoverable statement
58 0     0 0 0 eval qq{ # uncoverable statement
  115092     115092 0 327908  
  0     0 0 0  
  5     5 0 57  
  12331     12331 0 39612  
  0     0 0 0  
  0     0 0    
59             sub is_$_ { $_()->check(shift) } # uncoverable statement
60             sub assert_$_ { $_()->assert_return(shift) } # uncoverable statement
61             }; # uncoverable statement
62             } # uncoverable statement
63              
64             sub _reinstall_subs {
65              
66             # uncoverable subroutine
67 734     734   1797 my $type = shift; # uncoverable statement
68 317     317   2894 no strict 'refs'; # uncoverable statement
  317         945  
  317         12931  
69 317     317   2216 no warnings 'redefine'; # uncoverable statement
  317         840  
  317         86301  
70 731         2448 *{ 'is_' . $type->name } = $type->compiled_check; # uncoverable statement
  731         2331  
71 731         3439 *{ 'assert_' . $type->name } = \&$type; # uncoverable statement
  731         3007  
72 731         4121 $type; # uncoverable statement
73             } # uncoverable statement
74              
75             sub _mkall {
76              
77             # uncoverable subroutine
78 144 100   144   724 return unless $INC{'Type/Tiny.pm'}; # uncoverable statement
79 141         688 __PACKAGE__->get_type( $_ ) for __PACKAGE__->type_names; # uncoverable statement
80             } # uncoverable statement
81              
82             sub meta {
83 35     35 1 303 return $_[0];
84             }
85              
86             sub type_names {
87 2862     2862 1 19661 qw(
88             StringLike BoolLike
89             HashLike ArrayLike CodeLike
90             TypeTiny _ForeignTypeConstraint
91             );
92             }
93              
94             sub has_type {
95 1117     1117 1 2490 my %has = map +( $_ => 1 ), shift->type_names;
96 1117         5402 !!$has{ $_[0] };
97             }
98              
99             sub get_type {
100 1108     1108 1 2139 my $self = shift;
101 1108 100       2632 return unless $self->has_type( @_ );
102 317     317   2608 no strict qw(refs);
  317         901  
  317         48886  
103 1107         1996 &{ $_[0] }();
  1107         5406  
104             }
105              
106             sub coercion_names {
107 21     21 1 548 qw();
108             }
109              
110             sub has_coercion {
111 2     2 1 6 my %has = map +( $_ => 1 ), shift->coercion_names;
112 2         12 !!$has{ $_[0] };
113             }
114              
115             sub get_coercion {
116 1     1 1 3 my $self = shift;
117 1 50       3 return unless $self->has_coercion( @_ );
118 317     317   2480 no strict qw(refs);
  317         1044  
  317         35450  
119 0         0 &{ $_[0] }(); # uncoverable statement
  0         0  
120             }
121              
122             my ( $__get_linear_isa_dfs, $tried_mro );
123             $__get_linear_isa_dfs = sub {
124             if ( !$tried_mro && eval { require mro } ) {
125             $__get_linear_isa_dfs = \&mro::get_linear_isa;
126             goto $__get_linear_isa_dfs;
127             }
128 317     317   2507 no strict 'refs';
  317         969  
  317         1527635  
129             my $classname = shift;
130             my @lin = ( $classname );
131             my %stored;
132             foreach my $parent ( @{"$classname\::ISA"} ) {
133             my $plin = $__get_linear_isa_dfs->( $parent );
134             foreach ( @$plin ) {
135             next if exists $stored{$_};
136             push( @lin, $_ );
137             $stored{$_} = 1;
138             }
139             }
140             return \@lin;
141             };
142              
143             sub _check_overload {
144 217     217   889 my $package = shift;
145 217 50       536 if ( ref $package ) {
146 217         574 $package = blessed( $package );
147 217 50       554 return !!0 if !defined $package;
148             }
149 217         368 my $op = shift;
150 217         837 my $mro = $__get_linear_isa_dfs->( $package );
151 217         483 foreach my $p ( @$mro ) {
152 253         559 my $fqmeth = $p . q{::(} . $op;
153 253 100       388 return !!1 if defined &{$fqmeth};
  253         1579  
154             }
155 178         1873 !!0;
156             } #/ sub _check_overload
157              
158             sub _get_check_overload_sub {
159 533 100   533   1216 if ( $Type::Tiny::AvoidCallbacks ) {
160             return
161 357         1785 '(sub { require overload; overload::Overloaded(ref $_[0] or $_[0]) and overload::Method((ref $_[0] or $_[0]), $_[1]) })->';
162             }
163 176         765 return 'Types::TypeTiny::_check_overload';
164             }
165              
166             sub StringLike () {
167 439 100   439 0 24003 return $cache{StringLike} if defined $cache{StringLike};
168 290         1615 require Type::Tiny;
169             my %common = (
170             name => "StringLike",
171             library => __PACKAGE__,
172             constraint => sub {
173 57 100 100 57   610 defined( $_ ) && !ref( $_ )
      100        
174             or blessed( $_ ) && _check_overload( $_, q[""] );
175             },
176             inlined => sub {
177 57     57   222 qq/defined($_[1]) && !ref($_[1]) or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[""])/;
  57         147  
178             },
179 1     1   5 type_default => sub { return '' },
180 290         3797 );
181 290         759 if ( __XS ) {
182 290         1474 my $xsub = Type::Tiny::XS::get_coderef_for( 'StringLike' );
183 290         4446 my $xsubname = Type::Tiny::XS::get_subname_for( 'StringLike' );
184 290         2472 my $inlined = $common{inlined};
185             $cache{StringLike} = "Type::Tiny"->new(
186             %common,
187             compiled_type_constraint => $xsub,
188             inlined => sub {
189            
190             # uncoverable subroutine
191 405 100 66 405   4335 ( $Type::Tiny::AvoidCallbacks or not $xsubname )
192             ? goto( $inlined )
193             : qq/$xsubname($_[1])/ # uncoverable statement
194             },
195 290         3581 );
196 290         2055 _reinstall_subs $cache{StringLike};
197             } #/ if ( __XS )
198             else {
199             $cache{StringLike} = "Type::Tiny"->new( %common );
200             }
201             } #/ sub StringLike
202              
203             sub HashLike (;@) {
204 227 100 100 227 0 23979 return $cache{HashLike} if defined( $cache{HashLike} ) && !@_;
205 144         871 require Type::Tiny;
206             my %common = (
207             name => "HashLike",
208             library => __PACKAGE__,
209             constraint => sub {
210 71 100 100 71   700 ref( $_ ) eq q[HASH]
211             or blessed( $_ ) && _check_overload( $_, q[%{}] );
212             },
213             inlined => sub {
214 71     71   248 qq/ref($_[1]) eq q[HASH] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\%{}])/;
  71         163  
215             },
216 1     1   8 type_default => sub { return {} },
217             constraint_generator => sub {
218 2     2   7 my $param = TypeTiny()->assert_coerce( shift );
219 2         7 my $check = $param->compiled_check;
220 2         3 if ( __XS ge '0.025' ) {
221 2         8 my $paramname = Type::Tiny::XS::is_known( $check );
222 2 50       25 my $xsub = defined($paramname)
223             ? Type::Tiny::XS::get_coderef_for( "HashLike[$paramname]" )
224             : undef;
225 2 50       93 return $xsub if $xsub;
226             }
227             sub {
228 0         0 my %hash = %$_;
229 0         0 for my $key ( sort keys %hash ) {
230 0 0       0 $check->( $hash{$key} ) or return 0;
231             }
232 0         0 return 1;
233 0         0 };
234             },
235             inline_generator => sub {
236 2     2   5 my $param = TypeTiny()->assert_coerce( shift );
237 2 50       7 return unless $param->can_be_inlined;
238 2         7 my $check = $param->compiled_check;
239 2         4 my $xsubname;
240 2         4 if ( __XS ge '0.025' ) {
241 2         6 my $paramname = Type::Tiny::XS::is_known( $check );
242 2 50       20 $xsubname = defined($paramname)
243             ? Type::Tiny::XS::get_subname_for( "HashLike[$paramname]" )
244             : undef;
245             }
246             sub {
247 23         39 my $var = pop;
248 23 100 66     119 return "$xsubname($var)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
249 10         49 my $code = sprintf(
250             'do { my $ok=1; my %%h = %%{%s}; for my $k (sort keys %%h) { ($ok=0,next) unless (%s) }; $ok }',
251             $var,
252             $param->inline_check( '$h{$k}' ),
253             );
254 10         30 return ( undef, $code );
255 2         22 };
256             },
257             coercion_generator => sub {
258 1     1   5 my ( $parent, $child, $param ) = @_;
259 1 50       5 return unless $param->has_coercion;
260 1         6 my $coercible = $param->coercion->_source_type_union->compiled_check;
261 1         10 my $C = "Type::Coercion"->new( type_constraint => $child );
262             $C->add_type_coercions(
263             $parent => sub {
264 4 50       70 my $origref = @_ ? $_[0] : $_;
265 4         12 my %orig = %$origref;
266 4         16 my %new;
267 4         14 for my $k ( sort keys %orig ) {
268 8 100       91 return $origref unless $coercible->( $orig{$k} );
269 6         90 $new{$k} = $param->coerce( $orig{$k} );
270             }
271 2         36 \%new;
272             },
273 1         9 );
274 1         4 return $C;
275             },
276 144         4034 );
277 144         445 if ( __XS ) {
278 144         802 my $xsub = Type::Tiny::XS::get_coderef_for( 'HashLike' );
279 144         2315 my $xsubname = Type::Tiny::XS::get_subname_for( 'HashLike' );
280 144         1245 my $inlined = $common{inlined};
281             $cache{HashLike} = "Type::Tiny"->new(
282             %common,
283             compiled_type_constraint => $xsub,
284             inlined => sub {
285            
286             # uncoverable subroutine
287 278 100 66 278   2727 ( $Type::Tiny::AvoidCallbacks or not $xsubname )
288             ? goto( $inlined )
289             : qq/$xsubname($_[1])/ # uncoverable statement
290             },
291 144         1725 );
292 144         781 _reinstall_subs $cache{HashLike};
293             } #/ if ( __XS )
294             else {
295             $cache{HashLike} = "Type::Tiny"->new( %common );
296             }
297            
298 144 100       1495 @_ ? $cache{HashLike}->parameterize( @{ $_[0] } ) : $cache{HashLike};
  2         14  
299             } #/ sub HashLike (;@)
300              
301             sub ArrayLike (;@) {
302 232 100 100 232 0 23943 return $cache{ArrayLike} if defined( $cache{ArrayLike} ) && !@_;
303 148         908 require Type::Tiny;
304             my %common = (
305             name => "ArrayLike",
306             library => __PACKAGE__,
307             constraint => sub {
308 67 100 100 67   595 ref( $_ ) eq q[ARRAY]
309             or blessed( $_ ) && _check_overload( $_, q[@{}] );
310             },
311             inlined => sub {
312 67     67   220 qq/ref($_[1]) eq q[ARRAY] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\@{}])/;
  67         135  
313             },
314 1     1   5 type_default => sub { return [] },
315             constraint_generator => sub {
316 2     2   6 my $param = TypeTiny()->assert_coerce( shift );
317 2         8 my $check = $param->compiled_check;
318 2         4 if ( __XS ge '0.025' ) {
319 2         7 my $paramname = Type::Tiny::XS::is_known( $check );
320 2 50       26 my $xsub = defined($paramname)
321             ? Type::Tiny::XS::get_coderef_for( "ArrayLike[$paramname]" )
322             : undef;
323 2 50       99 return $xsub if $xsub;
324             }
325             sub {
326 0         0 my @arr = @$_;
327 0         0 for my $val ( @arr ) {
328 0 0       0 $check->( $val ) or return 0;
329             }
330 0         0 return 1;
331 0         0 };
332             },
333             inline_generator => sub {
334 2     2   6 my $param = TypeTiny()->assert_coerce( shift );
335 2 50       6 return unless $param->can_be_inlined;
336 2         6 my $check = $param->compiled_check;
337 2         2 my $xsubname;
338 2         4 if ( __XS ge '0.025' ) {
339 2         6 my $paramname = Type::Tiny::XS::is_known( $check );
340 2 50       18 $xsubname = defined($paramname)
341             ? Type::Tiny::XS::get_subname_for( "ArrayLike[$paramname]" )
342             : undef;
343             }
344             sub {
345 23         39 my $var = pop;
346 23 100 66     136 return "$xsubname($var)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
347 10         31 my $code = sprintf(
348             'do { my $ok=1; for my $v (@{%s}) { ($ok=0,next) unless (%s) }; $ok }',
349             $var,
350             $param->inline_check( '$v' ),
351             );
352 10         30 return ( undef, $code );
353 2         40 };
354             },
355             coercion_generator => sub {
356 1     1   4 my ( $parent, $child, $param ) = @_;
357 1 50       5 return unless $param->has_coercion;
358 1         6 my $coercible = $param->coercion->_source_type_union->compiled_check;
359 1         11 my $C = "Type::Coercion"->new( type_constraint => $child );
360             $C->add_type_coercions(
361             $parent => sub {
362 4 50       62 my $origref = @_ ? $_[0] : $_;
363 4         9 my @orig = @$origref;
364 4         11 my @new;
365 4         9 for my $v ( @orig ) {
366 10 100       96 return $origref unless $coercible->( $v );
367 8         111 push @new, $param->coerce( $v );
368             }
369 2         31 \@new;
370             },
371 1         8 );
372 1         4 return $C;
373             },
374 148         3165 );
375 148         915 if ( __XS ) {
376 148         633 my $xsub = Type::Tiny::XS::get_coderef_for( 'ArrayLike' );
377 148         2064 my $xsubname = Type::Tiny::XS::get_subname_for( 'ArrayLike' );
378 148         1196 my $inlined = $common{inlined};
379             $cache{ArrayLike} = "Type::Tiny"->new(
380             %common,
381             compiled_type_constraint => $xsub,
382             inlined => sub {
383            
384             # uncoverable subroutine
385 274 100 66 274   2558 ( $Type::Tiny::AvoidCallbacks or not $xsubname )
386             ? goto( $inlined )
387             : qq/$xsubname($_[1])/ # uncoverable statement
388             },
389 148         1618 );
390 148         790 _reinstall_subs $cache{ArrayLike};
391             } #/ if ( __XS )
392             else {
393             $cache{ArrayLike} = "Type::Tiny"->new( %common );
394             }
395            
396 148 100       1625 @_ ? $cache{ArrayLike}->parameterize( @{ $_[0] } ) : $cache{ArrayLike};
  2         12  
397             } #/ sub ArrayLike (;@)
398              
399             if ( $] ge '5.014' ) {
400             &Scalar::Util::set_prototype( $_, ';$' ) for \&HashLike, \&ArrayLike;
401             }
402              
403             sub CodeLike () {
404 234 100   234 0 22812 return $cache{CodeLike} if $cache{CodeLike};
405 149         907 require Type::Tiny;
406             my %common = (
407             name => "CodeLike",
408             constraint => sub {
409 58 100 100 58   547 ref( $_ ) eq q[CODE]
410             or blessed( $_ ) && _check_overload( $_, q[&{}] );
411             },
412             inlined => sub {
413 58     58   232 qq/ref($_[1]) eq q[CODE] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\&{}])/;
  58         147  
414             },
415 1     1   16 type_default => sub { return sub {} },
416 149         1869 library => __PACKAGE__,
417             );
418 149         351 if ( __XS ) {
419 149         632 my $xsub = Type::Tiny::XS::get_coderef_for( 'CodeLike' );
420 149         2101 my $xsubname = Type::Tiny::XS::get_subname_for( 'CodeLike' );
421 149         1175 my $inlined = $common{inlined};
422             $cache{CodeLike} = "Type::Tiny"->new(
423             %common,
424             compiled_type_constraint => $xsub,
425             inlined => sub {
426            
427             # uncoverable subroutine
428 266 100 66 266   2511 ( $Type::Tiny::AvoidCallbacks or not $xsubname )
429             ? goto( $inlined )
430             : qq/$xsubname($_[1])/ # uncoverable statement
431             },
432 149         1478 );
433 149         742 _reinstall_subs $cache{CodeLike};
434             } #/ if ( __XS )
435             else {
436             $cache{CodeLike} = "Type::Tiny"->new( %common );
437             }
438             } #/ sub CodeLike
439              
440             sub BoolLike () {
441 222 100   222 0 20528 return $cache{BoolLike} if $cache{BoolLike};
442 141         820 require Type::Tiny;
443             $cache{BoolLike} = "Type::Tiny"->new(
444             name => "BoolLike",
445             constraint => sub {
446             !defined( $_ )
447             or !ref( $_ ) && ( $_ eq '' || $_ eq '0' || $_ eq '1' )
448             or blessed( $_ ) && _check_overload( $_, q[bool] )
449 52 100 100 52   742 or blessed( $_ ) && _check_overload( $_, q[0+] ) && do { my $n = sprintf('%d', $_); $n==0 or $n==1 };
  2 100 66     12  
  2   100     21  
      100        
      100        
      100        
      100        
450             },
451             inlined => sub {
452 140     140   544 qq/do {
453             local \$_ = $_;
454             !defined()
455             or !ref() && ( \$_ eq '' || \$_ eq '0' || \$_ eq '1' )
456 140         379 or Scalar::Util::blessed(\$_) && ${\ +_get_check_overload_sub() }(\$_, q[bool])
457 140         288 or Scalar::Util::blessed(\$_) && ${\ +_get_check_overload_sub() }(\$_, q[0+]) && do { my \$n = sprintf('%d', $_); \$n==0 or \$n==1 }
458             }/;
459             },
460 1     1   4 type_default => sub { return !!0 },
461 141         1982 library => __PACKAGE__,
462             );
463             } #/ sub BoolLike
464              
465             sub TypeTiny () {
466 127662 100   127662 0 568134 return $cache{TypeTiny} if defined $cache{TypeTiny};
467 293         1801 require Type::Tiny;
468             $cache{TypeTiny} = "Type::Tiny"->new(
469             name => "TypeTiny",
470 72 100   72   629 constraint => sub { blessed( $_ ) && $_->isa( q[Type::Tiny] ) },
471             inlined => sub {
472 470     470   1438 my $var = $_[1];
473 470         2638 "Scalar::Util::blessed($var) && $var\->isa(q[Type::Tiny])";
474             },
475 1     1   646 type_default => sub { require Types::Standard; return Types::Standard::Any() },
  1         10  
476             library => __PACKAGE__,
477             _build_coercion => sub {
478 21     21   79 my $c = shift;
479 21         129 $c->add_type_coercions( _ForeignTypeConstraint(), \&to_TypeTiny );
480 21         109 $c->freeze;
481             },
482 293         5071 );
483             } #/ sub TypeTiny
484              
485             sub _ForeignTypeConstraint () {
486 255 100   255   22214 return $cache{_ForeignTypeConstraint} if defined $cache{_ForeignTypeConstraint};
487 141         797 require Type::Tiny;
488             $cache{_ForeignTypeConstraint} = "Type::Tiny"->new(
489             name => "_ForeignTypeConstraint",
490             constraint => \&_is_ForeignTypeConstraint,
491             inlined => sub {
492 192     192   903 qq/ref($_[1]) && do { require Types::TypeTiny; Types::TypeTiny::_is_ForeignTypeConstraint($_[1]) }/;
493             },
494 141         1225 library => __PACKAGE__,
495             );
496             } #/ sub _ForeignTypeConstraint
497              
498             my %ttt_cache;
499              
500             sub _is_ForeignTypeConstraint {
501 272 50   272   2201 my $t = @_ ? $_[0] : $_;
502 272 100       799 return !!1 if ref $t eq 'CODE';
503 251 100       958 if ( my $class = blessed $t ) {
504 137 100       771 return !!0 if $class->isa( "Type::Tiny" );
505 107 100       438 return !!1 if $class->isa( "Moose::Meta::TypeConstraint" );
506 97 100       333 return !!1 if $class->isa( "MooseX::Types::TypeDecorator" );
507 96 50       391 return !!1 if $class->isa( "Validation::Class::Simple" );
508 96 50       302 return !!1 if $class->isa( "Validation::Class" );
509 96 100       442 return !!1 if $t->can( "check" );
510             }
511 199         1141 !!0;
512             } #/ sub _is_ForeignTypeConstraint
513              
514             sub to_TypeTiny {
515 147414 50   147414 1 362597 my $t = @_ ? $_[0] : $_;
516            
517 147414 100       326001 return $t unless ( my $ref = ref $t );
518 146267 100       526193 return $t if $ref =~ /^Type::Tiny\b/;
519            
520 40298 100       145515 return $ttt_cache{ refaddr( $t ) } if $ttt_cache{ refaddr( $t ) };
521            
522             #<<<
523 40269 100       101465 if ( my $class = blessed $t) {
524 224 50       1509 return $t if $class->isa( "Type::Tiny" );
525 224 100       838 return _TypeTinyFromMoose( $t ) if $class eq "MooseX::Types::TypeDecorator"; # needed before MooseX::Types 0.35.
526 208 100       1041 return _TypeTinyFromMoose( $t ) if $class->isa( "Moose::Meta::TypeConstraint" );
527 89 50       388 return _TypeTinyFromMoose( $t ) if $class->isa( "MooseX::Types::TypeDecorator" );
528 89 100       464 return _TypeTinyFromMouse( $t ) if $class->isa( "Mouse::Meta::TypeConstraint" );
529 52 50       291 return _TypeTinyFromValidationClass( $t ) if $class->isa( "Validation::Class::Simple" );
530 52 50       251 return _TypeTinyFromValidationClass( $t ) if $class->isa( "Validation::Class" );
531 52 100 66     694 return $t->to_TypeTiny if $t->can( "DOES" ) && $t->DOES( "Type::Library::Compiler::TypeConstraint" ) && $t->can( "to_TypeTiny" );
      66        
532 46 100       300 return _TypeTinyFromGeneric( $t ) if $t->can( "check" ); # i.e. Type::API::Constraint
533             } #/ if ( my $class = blessed...)
534             #>>>
535            
536 40088 100       111385 return _TypeTinyFromCodeRef( $t ) if $ref eq q(CODE);
537            
538 66         313 $t;
539             } #/ sub to_TypeTiny
540              
541             sub _TypeTinyFromMoose {
542 142     142   16049 my $t = $_[0];
543            
544 142 100       862 if ( ref $t->{"Types::TypeTiny::to_TypeTiny"} ) {
545 31         160 return $t->{"Types::TypeTiny::to_TypeTiny"};
546             }
547            
548 111 50       2947 if ( $t->name ne '__ANON__' ) {
549 111         15178 require Types::Standard;
550 111         2687 my $ts = 'Types::Standard'->get_type( $t->name );
551 111 100       744 return $ts if $ts->{_is_core};
552             }
553            
554             #<<<
555 52 100       1273 my ( $tt_class, $tt_opts ) =
    100          
    100          
    100          
    100          
    100          
556             $t->can( 'parameterize' ) ? _TypeTinyFromMoose_parameterizable( $t ) :
557             $t->isa( 'Moose::Meta::TypeConstraint::Enum' ) ? _TypeTinyFromMoose_enum( $t ) :
558             $t->isa( 'Moose::Meta::TypeConstraint::Class' ) ? _TypeTinyFromMoose_class( $t ) :
559             $t->isa( 'Moose::Meta::TypeConstraint::Role' ) ? _TypeTinyFromMoose_role( $t ) :
560             $t->isa( 'Moose::Meta::TypeConstraint::Union' ) ? _TypeTinyFromMoose_union( $t ) :
561             $t->isa( 'Moose::Meta::TypeConstraint::DuckType' ) ? _TypeTinyFromMoose_ducktype( $t ) :
562             _TypeTinyFromMoose_baseclass( $t );
563             #>>>
564            
565             # Standard stuff to do with all type constraints from Moose,
566             # regardless of variety.
567 52         197 $tt_opts->{moose_type} = $t;
568 52         1477 $tt_opts->{display_name} = $t->name;
569 1     1   7 $tt_opts->{message} = sub { $t->get_message( $_ ) }
570 52 100       3824 if $t->has_message;
571            
572 52         2495 my $new = $tt_class->new( %$tt_opts );
573 52         238 $ttt_cache{ refaddr( $t ) } = $new;
574 52         201 weaken( $ttt_cache{ refaddr( $t ) } );
575            
576 52 100       1963 $new->{coercion} = do {
577 5         2460 require Type::Coercion::FromMoose;
578 5         219 'Type::Coercion::FromMoose'->new(
579             type_constraint => $new,
580             moose_coercion => $t->coercion,
581             );
582             } if $t->has_coercion;
583            
584 52         3909 return $new;
585             } #/ sub _TypeTinyFromMoose
586              
587             sub _TypeTinyFromMoose_baseclass {
588 46     46   10111 my $t = shift;
589 46         70 my %opts;
590 46 100       1574 $opts{parent} = to_TypeTiny( $t->parent ) if $t->has_parent;
591 46         1343 $opts{constraint} = $t->constraint;
592 112     112   181 $opts{inlined} = sub { shift; $t->_inline_check( @_ ) }
  112         392  
593 46 100 66     2448 if $t->can( "can_be_inlined" ) && $t->can_be_inlined;
594            
595             # Cowardly refuse to inline types that need to close over stuff
596 46 100       10880 if ( $opts{inlined} ) {
597 41 50       68 my %env = %{ $t->inline_environment || {} };
  41         131  
598 41 50       8935 delete( $opts{inlined} ) if keys %env;
599             }
600            
601 46         215 require Type::Tiny;
602 46         179 return 'Type::Tiny' => \%opts;
603             } #/ sub _TypeTinyFromMoose_baseclass
604              
605             sub _TypeTinyFromMoose_union {
606 2     2   7 my $t = shift;
607 2         6 my @mapped = map _TypeTinyFromMoose( $_ ), @{ $t->type_constraints };
  2         109  
608 2         621 require Type::Tiny::Union;
609 2         15 return 'Type::Tiny::Union' => { type_constraints => \@mapped };
610             }
611              
612             sub _TypeTinyFromMoose_enum {
613 1     1   3 my $t = shift;
614 1         749 require Type::Tiny::Enum;
615 1         4 return 'Type::Tiny::Enum' => { values => [ @{ $t->values } ] };
  1         43  
616             }
617              
618             sub _TypeTinyFromMoose_class {
619 1     1   4 my $t = shift;
620 1         650 require Type::Tiny::Class;
621 1         45 return 'Type::Tiny::Class' => { class => $t->class };
622             }
623              
624             sub _TypeTinyFromMoose_role {
625 1     1   3 my $t = shift;
626 1         453 require Type::Tiny::Role;
627 1         45 return 'Type::Tiny::Role' => { role => $t->role };
628             }
629              
630             sub _TypeTinyFromMoose_ducktype {
631 1     1   4 my $t = shift;
632 1         515 require Type::Tiny::Duck;
633 1         4 return 'Type::Tiny::Duck' => { methods => [ @{ $t->methods } ] };
  1         47  
634             }
635              
636             sub _TypeTinyFromMoose_parameterizable {
637 3     3   9 my $t = shift;
638 3         11 my ( $class, $opts ) = _TypeTinyFromMoose_baseclass( $t );
639             $opts->{constraint_generator} = sub {
640            
641             # convert args into Moose native types; not strictly necessary
642 3 50   3   13 my @args = map { is_TypeTiny( $_ ) ? $_->moose_type : $_ } @_;
  3         60  
643 3         44 _TypeTinyFromMoose( $t->parameterize( @args ) );
644 3         26 };
645 3         14 return ( $class, $opts );
646             } #/ sub _TypeTinyFromMoose_parameterizable
647              
648             sub _TypeTinyFromValidationClass {
649 0     0   0 my $t = $_[0];
650            
651 0         0 require Type::Tiny;
652 0         0 require Types::Standard;
653            
654 0         0 my %opts = (
655             parent => Types::Standard::HashRef(),
656             _validation_class => $t,
657             );
658            
659 0 0       0 if ( $t->VERSION >= "7.900048" ) {
660             $opts{constraint} = sub {
661 0     0   0 $t->params->clear;
662 0         0 $t->params->add( %$_ );
663 0         0 my $f = $t->filtering;
664 0         0 $t->filtering( 'off' );
665 0         0 my $r = eval { $t->validate };
  0         0  
666 0   0     0 $t->filtering( $f || 'pre' );
667 0         0 return $r;
668 0         0 };
669             $opts{message} = sub {
670 0     0   0 $t->params->clear;
671 0         0 $t->params->add( %$_ );
672 0         0 my $f = $t->filtering;
673 0         0 $t->filtering( 'off' );
674 0 0       0 my $r = ( eval { $t->validate } ? "OK" : $t->errors_to_string );
  0         0  
675 0   0     0 $t->filtering( $f || 'pre' );
676 0         0 return $r;
677 0         0 };
678             } #/ if ( $t->VERSION >= "7.900048")
679             else # need to use hackish method
680             {
681             $opts{constraint} = sub {
682 0     0   0 $t->params->clear;
683 0         0 $t->params->add( %$_ );
684 317     317   3224 no warnings "redefine";
  317         806  
  317         45028  
685 0         0 local *Validation::Class::Directive::Filters::execute_filtering = sub { $_[0] };
  0         0  
686 0         0 eval { $t->validate };
  0         0  
687 0         0 };
688             $opts{message} = sub {
689 0     0   0 $t->params->clear;
690 0         0 $t->params->add( %$_ );
691 317     317   2755 no warnings "redefine";
  317         915  
  317         379584  
692 0         0 local *Validation::Class::Directive::Filters::execute_filtering = sub { $_[0] };
  0         0  
693 0 0       0 eval { $t->validate } ? "OK" : $t->errors_to_string;
  0         0  
694 0         0 };
695             } #/ else [ if ( $t->VERSION >= "7.900048")]
696            
697 0         0 require Type::Tiny;
698 0         0 my $new = "Type::Tiny"->new( %opts );
699            
700             $new->coercion->add_type_coercions(
701             Types::Standard::HashRef() => sub {
702 0     0   0 my %params = %$_;
703 0 0       0 for my $k ( keys %params ) { delete $params{$_} unless $t->get_fields( $k ) }
  0         0  
704 0         0 $t->params->clear;
705 0         0 $t->params->add( %params );
706 0         0 eval { $t->validate };
  0         0  
707 0         0 $t->get_hash;
708             },
709 0         0 );
710            
711 0         0 $ttt_cache{ refaddr( $t ) } = $new;
712 0         0 weaken( $ttt_cache{ refaddr( $t ) } );
713 0         0 return $new;
714             } #/ sub _TypeTinyFromValidationClass
715              
716             sub _TypeTinyFromGeneric {
717 3     3   9 my $t = $_[0];
718            
719             my %opts = (
720 30 50   30   86 constraint => sub { $t->check( @_ ? @_ : $_ ) },
721 3         22 );
722            
723 2 50   2   12 $opts{message} = sub { $t->get_message( @_ ? @_ : $_ ) }
724 3 50       18 if $t->can( "get_message" );
725            
726 3 50       14 $opts{display_name} = $t->name if $t->can( "name" );
727            
728 1 50   1   75 $opts{coercion} = sub { $t->coerce( @_ ? @_ : $_ ) }
729 3 50 66     20 if $t->can( "has_coercion" )
      66        
730             && $t->has_coercion
731             && $t->can( "coerce" );
732            
733 3 0 33     24 if ( $t->can( 'can_be_inlined' )
      33        
734             && $t->can_be_inlined
735             && $t->can( 'inline_check' ) )
736             {
737 0     0   0 $opts{inlined} = sub { $t->inline_check( $_[1] ) };
  0         0  
738             }
739            
740 3         17 require Type::Tiny;
741 3         17 my $new = "Type::Tiny"->new( %opts );
742 3         12 $ttt_cache{ refaddr( $t ) } = $new;
743 3         11 weaken( $ttt_cache{ refaddr( $t ) } );
744 3         19 return $new;
745             } #/ sub _TypeTinyFromGeneric
746              
747             sub _TypeTinyFromMouse {
748 38     38   161 my $t = $_[0];
749            
750             my %opts = (
751 172 50   172   1178 constraint => sub { $t->check( @_ ? @_ : $_ ) },
752 1 50   1   12 message => sub { $t->get_message( @_ ? @_ : $_ ) },
753 38         306 );
754            
755 38 50       345 $opts{display_name} = $t->name if $t->can( "name" );
756            
757 1 50   1   13 $opts{coercion} = sub { $t->coerce( @_ ? @_ : $_ ) }
758 38 100 66     351 if $t->can( "has_coercion" )
      66        
759             && $t->has_coercion
760             && $t->can( "coerce" );
761            
762 38 100       173 if ( $t->{'constraint_generator'} ) {
763             $opts{constraint_generator} = sub {
764            
765             # convert args into Moose native types; not strictly necessary
766 1 50   1   4 my @args = map { is_TypeTiny( $_ ) ? $_->mouse_type : $_ } @_;
  1         22  
767 1         4 _TypeTinyFromMouse( $t->parameterize( @args ) );
768 6         32 };
769             }
770            
771 38         198 require Type::Tiny;
772 38         194 my $new = "Type::Tiny"->new( %opts );
773 38         177 $ttt_cache{ refaddr( $t ) } = $new;
774 38         168 weaken( $ttt_cache{ refaddr( $t ) } );
775 38         181 return $new;
776             } #/ sub _TypeTinyFromMouse
777              
778             my $QFS;
779              
780             sub _TypeTinyFromCodeRef {
781 40022     40022   67413 my $t = $_[0];
782            
783             my %opts = (
784             constraint => sub {
785 108     108   167 return !!eval { $t->( $_ ) };
  108         250  
786             },
787             message => sub {
788 3     3   6 local $@;
789 3 50       6 eval { $t->( $_ ); 1 } or do { chomp $@; return $@ if $@ };
  3 100       10  
  1         5  
  2         22  
  2         28  
790 1         4 return sprintf( '%s did not pass type constraint', Type::Tiny::_dd( $_ ) );
791             },
792 40022         216094 );
793            
794 40022 100 100     251634 if ( $QFS ||= "Sub::Quote"->can( "quoted_from_sub" ) ) {
795 4 100       11 my ( undef, $perlstring, $captures ) = @{ $QFS->( $t ) || [] };
  4         16  
796 4 100       182 if ( $perlstring ) {
797 2         8 $perlstring = "!!eval{ $perlstring }";
798             $opts{inlined} = sub {
799 17     17   30 my $var = $_[1];
800 17 50       85 Sub::Quote::inlinify(
801             $perlstring,
802             $var,
803             $var eq q($_) ? '' : "local \$_ = $var;",
804             1,
805             );
806             }
807 2 50 33     36 if $perlstring && !$captures;
808             } #/ if ( $perlstring )
809             } #/ if ( $QFS ||= "Sub::Quote"...)
810            
811 40022         173286 require Type::Tiny;
812 40022         152360 my $new = "Type::Tiny"->new( %opts );
813 40022         135813 $ttt_cache{ refaddr( $t ) } = $new;
814 40022         112549 weaken( $ttt_cache{ refaddr( $t ) } );
815 40022         159535 return $new;
816             } #/ sub _TypeTinyFromCodeRef
817              
818             1;
819              
820             __END__
821              
822             =pod
823              
824             =encoding utf-8
825              
826             =for stopwords arrayfication hashification
827              
828             =head1 NAME
829              
830             Types::TypeTiny - type constraints used internally by Type::Tiny
831              
832             =head1 STATUS
833              
834             This module is covered by the
835             L<Type-Tiny stability policy|Type::Tiny::Manual::Policies/"STABILITY">.
836              
837             =head1 DESCRIPTION
838              
839             Dogfooding.
840              
841             This isn't a real Type::Library-based type library; that would involve
842             too much circularity. But it exports some type constraints which, while
843             designed for use within Type::Tiny, may be more generally useful.
844              
845             =head2 Types
846              
847             =over
848              
849             =item *
850              
851             B<< StringLike >>
852              
853             Accepts strings and objects overloading stringification.
854              
855             =item *
856              
857             B<< BoolLike >>
858              
859             Accepts undef, "", 0, 1; accepts any blessed object overloading "bool";
860             accepts any blessed object overloading "0+" to return 0 or 1. (Needs to
861             actually call the overloaded operation to check that.)
862              
863             Warning: an object which overloads "0+" without also turning on overload
864             fallbacks may actually be useless as a practical boolean. But some common
865             objects such as JSON::PP's booleans overload "0+" instead of overloading
866             "bool" (thankfully with fallbacks enabled!) so we do need to support this.
867              
868             =item *
869              
870             B<< HashLike[`a] >>
871              
872             Accepts hashrefs and objects overloading hashification.
873              
874             Since Types::TypeTiny 1.012, may be parameterized with another type
875             constraint like B<< HashLike[Int] >>.
876              
877             =item *
878              
879             B<< ArrayLike[`a] >>
880              
881             Accepts arrayrefs and objects overloading arrayfication.
882              
883             Since Types::TypeTiny 1.012, may be parameterized with another type
884             constraint like B<< ArrayLike[Int] >>.
885              
886             =item *
887              
888             B<< CodeLike >>
889              
890             Accepts coderefs and objects overloading codification.
891              
892             =item *
893              
894             B<< TypeTiny >>
895              
896             Accepts blessed L<Type::Tiny> objects.
897              
898             =item *
899              
900             B<< _ForeignTypeConstraint >>
901              
902             Any reference which to_TypeTiny recognizes as something that can be coerced
903             to a Type::Tiny object.
904              
905             Yes, the underscore is included.
906              
907             =back
908              
909             =head2 Coercion Functions
910              
911             =over
912              
913             =item C<< to_TypeTiny($constraint) >>
914              
915             Promotes (or "demotes" if you prefer) a "foreign" type constraint to a
916             Type::Tiny object. Can handle:
917              
918             =over
919              
920             =item *
921              
922             Moose types (including L<Moose::Meta::TypeConstraint> objects and
923             L<MooseX::Types::TypeDecorator> objects).
924              
925             =item *
926              
927             Mouse types (including L<Mouse::Meta::TypeConstraint> objects).
928              
929             =item *
930              
931             L<Validation::Class> and L<Validation::Class::Simple> objects.
932              
933             =item *
934              
935             Types built using L<Type::Library::Compiler>.
936              
937             =item *
938              
939             Any object which provides C<check> and C<get_message> methods.
940             (This includes L<Specio> and L<Type::Nano> types.) If the object
941             provides C<has_coercion> and L<coerce> methods, these will
942             be used to handle quoting. If the object provides C<can_be_inlined>
943             and C<inline_check> methods, these will be used to handling inlining.
944             If the object provides a C<name> method, this will be assumed to
945             return the type name.
946              
947             =item *
948              
949             Coderefs (but not blessed coderefs or objects overloading C<< &{} >>
950             unless they provide the methods described above!) Coderefs are expected
951             to return true iff C<< $_ >> passes the constraint. If C<< $_ >> fails
952             the type constraint, they may either return false, or die with a helpful
953             error message.
954              
955             =item *
956              
957             L<Sub::Quote>-enabled coderefs. These are handled the same way as above,
958             but Type::Tiny will consult Sub::Quote to determine if they can be inlined.
959              
960             =back
961              
962             =back
963              
964             =head2 Methods
965              
966             These are implemented so that C<< Types::TypeTiny->meta->get_type($foo) >>
967             works, for rough compatibility with a real L<Type::Library> type library.
968              
969             =over
970              
971             =item C<< meta >>
972              
973             =item C<< type_names >>
974              
975             =item C<< get_type($name) >>
976              
977             =item C<< has_type($name) >>
978              
979             =item C<< coercion_names >>
980              
981             =item C<< get_coercion($name) >>
982              
983             =item C<< has_coercion($name) >>
984              
985             =back
986              
987             =head1 BUGS
988              
989             Please report any bugs to
990             L<https://github.com/tobyink/p5-type-tiny/issues>.
991              
992             =head1 SEE ALSO
993              
994             L<Type::Tiny>.
995              
996             =head1 AUTHOR
997              
998             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
999              
1000             =head1 COPYRIGHT AND LICENCE
1001              
1002             This software is copyright (c) 2013-2014, 2017-2023 by Toby Inkster.
1003              
1004             This is free software; you can redistribute it and/or modify it under
1005             the same terms as the Perl 5 programming language system itself.
1006              
1007             =head1 DISCLAIMER OF WARRANTIES
1008              
1009             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1010             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1011             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.