diff --git a/lib/Method/Signatures.pm b/lib/Method/Signatures.pm index 42fcdce..e0fd06a 100644 --- a/lib/Method/Signatures.pm +++ b/lib/Method/Signatures.pm @@ -71,7 +71,7 @@ shift>. Also allows signatures, very similar to Perl 6 signatures. -Also does type checking, understanding all the types that Moose (or Mouse) would understand. +Also does type checking, understanding all the types that Type::Tiny would understand. And it does all this with B. @@ -307,13 +307,12 @@ Any variable that has a default is considered optional. Parameters can also be given type constraints. If they are, the value passed in will be validated against the type constraint provided. -Types are provided by L which will load L if -L is not already loaded. +Types are provided by L. Type constraints can be a type, a role or a class. Each will be checked in turn until one of them passes. - * First, is the $value of that type declared in Moose (or Mouse)? + * First, is the $value of that type declared in Type::Tiny? * Then, does the $value have that role? $value->DOES($type); @@ -322,15 +321,15 @@ checked in turn until one of them passes. $value->isa($type); The set of default types that are understood can be found in -L (or L; -they are generally the same, but there may be small differences). +L. + # avoid "argument isn't numeric" warnings method add(Int $this = 23, Int $that = 42) { return $this + $that; } -L and L also understand some parameterized types; see +L also understand some parameterized types; see their documentation for more details. method add(Int $this = 23, Maybe[Int] $that) { @@ -1154,10 +1153,15 @@ sub inject_for_type_check # This is an optimization to unroll typecheck which makes Mouse types about 40% faster. # It only happens when type_check() has not been overridden. if( $class->can("type_check") eq __PACKAGE__->can("type_check") ) { + + # we can't check if the type has an inline code here, we need to defer + # that to _make_constraint_with_check, because some Roles/Classes may + # have not been loaded yet. + my $check = sprintf q[($%s::mutc{cache}{'%s'} ||= %s->_make_constraint('%s'))->check(%s)], __PACKAGE__, $sig->type, $class, $sig->type, $sig->passed_in; - my $error = sprintf q[%s->type_error('%s', %s, '%s') ], - $class, $sig->type, $sig->passed_in, $sig->variable_name; + my $error = sprintf q[( %s->type_error('%s', %s, '%s') ) ], + $class, $sig->type, $sig->passed_in, $sig->variable_name; # $sig->type, $sig->passed_in, $sig->variable_name, my $code = "$error if "; $code .= "$check_exists && " if $check_exists; $code .= "!$check"; @@ -1200,9 +1204,8 @@ sub required_arg { # STUFF FOR TYPE CHECKING # This variable will hold all the bits we need. MUTC could stand for Moose::Util::TypeConstraint, -# or it could stand for Mouse::Util::TypeConstraint ... depends on which one you've got loaded (or -# Mouse if you have neither loaded). Because we use Any::Moose to allow the user to choose -# whichever they like, we'll need to figure out the exact method names to call. We'll also need a +# or it could stand for Mouse::Util::TypeConstraint ... But we use Type::Tiny now... +# We'll also need a # type constraint cache, where we stick our constraints once we find or create them. This insures # that we only have to run down any given constraint once, the first time it's seen, and then after # that it's simple enough to pluck back out. This is very similar to how MooseX::Params::Validate @@ -1212,20 +1215,22 @@ our %mutc; # This is a helper function to initialize our %mutc variable. sub _init_mutc { - require Any::Moose; - Any::Moose->import('::Util::TypeConstraints'); - - no strict 'refs'; - my $class = any_moose('::Util::TypeConstraints'); - $mutc{class} = $class; - - $mutc{findit} = \&{ $class . '::find_or_parse_type_constraint' }; - $mutc{pull} = \&{ $class . '::find_type_constraint' }; - $mutc{make_class} = \&{ $class . '::class_type' }; - $mutc{make_role} = \&{ $class . '::role_type' }; - - $mutc{isa_class} = $mutc{pull}->("ClassName"); - $mutc{isa_role} = $mutc{pull}->("RoleName"); + require Types::Standard; + require Type::Tiny::Class; + require Type::Tiny::Role; + require Type::Utils; + # This is supposed to really throw an exception, but + # _init_mutc is only ever called within an eval {...} + # block!!! + 'Type::Utils'->VERSION('0.016'); + + $mutc{class} = 'Type::Tiny'; + $mutc{findit} = sub { Type::Utils::dwim_type($_[0]) }; + $mutc{pull} = sub { Type::Utils::dwim_type($_[0]) }; + $mutc{make_class} = sub { 'Type::Tiny::Class'->new(class => $_[0]) }; + $mutc{make_role} = sub { 'Type::Tiny::Role'->new(role => $_[0]) }; + $mutc{isa_class} = Types::Standard::ClassName(); + $mutc{isa_role} = Types::Standard::RoleName(); } # This is a helper function to find (or create) the constraint we need for a given type. It would @@ -1239,10 +1244,8 @@ sub _make_constraint # Look for basic types (Int, Str, Bool, etc). This will also create a new constraint for any # parameterized types (e.g. ArrayRef[Int]) or any disjunctions (e.g. Int|ScalarRef[Int]). my $constr = eval { $mutc{findit}->($type) }; - if ($@) - { - $class->signature_error("the type $type is unrecognized (looks like it doesn't parse correctly)"); - } + # Stores the error, but don't die now, check role/classe types first + my $error = $@; return $constr if $constr; # Check for roles. Note that you *must* check for roles before you check for classes, because a @@ -1252,9 +1255,13 @@ sub _make_constraint # Now check for classes. return $mutc{make_class}->($type) if $mutc{isa_class}->check($type); + $error + and $class->signature_error("the type $type is unrecognized (looks like it doesn't parse correctly)"); + $class->signature_error("the type $type is unrecognized (perhaps you forgot to load it?)"); } + # This method does the actual type checking. It's what we inject into our user's method, to be # called directly by them. # diff --git a/lib/Method/Signatures/Parser.pm b/lib/Method/Signatures/Parser.pm index 92c591f..fc7448e 100644 --- a/lib/Method/Signatures/Parser.pm +++ b/lib/Method/Signatures/Parser.pm @@ -73,7 +73,7 @@ sub carp_location_for { local @CARP_NOT; push @CARP_NOT, 'Method::Signatures'; push @CARP_NOT, $class unless $class =~ /^${\__PACKAGE__}(::|$)/; - push @CARP_NOT, qw< Class::MOP Moose Mouse Devel::Declare >; + push @CARP_NOT, qw< Class::MOP Moose Mouse Devel::Declare Types::Standard Type::Registry Type::Parser Type::Tiny>; # Skip any package in the @CARP_NOT list or their sub packages. my $carp_not_list_re = join '|', @CARP_NOT; diff --git a/t/error_reporting.t b/t/error_reporting.t index 1558905..883539e 100644 --- a/t/error_reporting.t +++ b/t/error_reporting.t @@ -105,13 +105,15 @@ my %run_time_errors = ], test_name => 'no such named param reports correctly', }, + UnknownType => { method => 'bar', - error_gen => 'badtype_error', + error_gen => 'badval_error', error_args => [ 'InnerUnknownType', + 'bar', 'Foo::Bmoogle', - 'perhaps you forgot to load it?', + 42, 'foo', ], test_name => 'unrecognized type reports correctly', diff --git a/t/lib/InnerBadType.pm b/t/lib/InnerBadType.pm index 82acda1..0c9ec33 100644 --- a/t/lib/InnerBadType.pm +++ b/t/lib/InnerBadType.pm @@ -8,6 +8,7 @@ use Method::Signatures; sub new { bless {}, __PACKAGE__ } +#line 1133 method foo ( Int $bar ) {} diff --git a/t/role_check_moose.t b/t/role_check_moose.t index 2be47e5..611abb4 100644 --- a/t/role_check_moose.t +++ b/t/role_check_moose.t @@ -8,6 +8,7 @@ use GenErrorRegex qw< badval_error >; use Test::More; use Test::Exception; +plan skip_all => "We dont't use Moose anymore"; { package Foo::Bar; sub new { bless {}, __PACKAGE__; } } diff --git a/t/role_check_mouse.t b/t/role_check_mouse.t index 5a43643..2e3823c 100644 --- a/t/role_check_mouse.t +++ b/t/role_check_mouse.t @@ -8,6 +8,7 @@ use GenErrorRegex qw< badval_error >; use Test::More; use Test::Exception; +plan skip_all => "We dont't use Mouse anymore"; { package Foo::Bar; sub new { bless {}, __PACKAGE__; } } diff --git a/t/type_check.t b/t/type_check.t index 42dc6e6..5a68aba 100644 --- a/t/type_check.t +++ b/t/type_check.t @@ -133,14 +133,14 @@ our $tester; $method = 'unknown_type'; $type = 'Bmoogle'; warning_is { eval qq{ method $method ($type \$bar) {} } } undef, 'no warnings when weird type loaded'; - throws_ok { $tester->$method(42) } badtype_error($tester, $type, "perhaps you forgot to load it?", $method), + throws_ok { $tester->$method(42) } badval_error($tester, 'bar', 'Bmoogle', 42, $method), 'call with unrecognized type dies'; # this one is a bit specialer in that it involved an unrecognized parameterization $method = 'unknown_paramized_type'; $type = 'Bmoogle[Int]'; warning_is { eval qq{ method $method ($type \$bar) {} } } undef, 'no warnings when weird paramized type loaded'; - throws_ok { $tester->$method(42) } badtype_error($tester, $type, "looks like it doesn't parse correctly", $method), + throws_ok { $tester->$method(42) } badtype_error($tester, 'Bmoogle[Int]', "looks like it doesn't parse correctly", $method), 'call with unrecognized paramized type dies'; }