Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only use Type::Tiny (no Mo*se) #85

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 37 additions & 30 deletions lib/Method/Signatures.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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<no source filters>.

Expand Down Expand Up @@ -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<Any::Moose> which will load L<Mouse> if
L<Moose> is not already loaded.
Types are provided by L<Type::Tiny>.

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);
Expand All @@ -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<Mouse::Util::TypeConstraints> (or L<Moose::Util::TypeConstraints>;
they are generally the same, but there may be small differences).
L<Types::Standard>.


# avoid "argument isn't numeric" warnings
method add(Int $this = 23, Int $that = 42) {
return $this + $that;
}

L<Mouse> and L<Moose> also understand some parameterized types; see
L<Type::Tiny> also understand some parameterized types; see
their documentation for more details.

method add(Int $this = 23, Maybe[Int] $that) {
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
#
Expand Down
2 changes: 1 addition & 1 deletion lib/Method/Signatures/Parser.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions t/error_reporting.t
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
1 change: 1 addition & 0 deletions t/lib/InnerBadType.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use Method::Signatures;

sub new { bless {}, __PACKAGE__ }

#line 1133
method foo ( Int $bar ) {}


Expand Down
1 change: 1 addition & 0 deletions t/role_check_moose.t
Original file line number Diff line number Diff line change
Expand Up @@ -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__; } }

Expand Down
1 change: 1 addition & 0 deletions t/role_check_mouse.t
Original file line number Diff line number Diff line change
Expand Up @@ -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__; } }

Expand Down
4 changes: 2 additions & 2 deletions t/type_check.t
Original file line number Diff line number Diff line change
Expand Up @@ -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';

}
Expand Down