Moosites,
I'm working on adding type checking to Method::Signatures, and I want
it to be able to handle roles. So, if I say:
method foo (Blargy $bar)
and Blargy is a role, I want it to verify that $bar is an object whose
class composes the Blargy role. I believe that's as simple as
checking that
$bar->DOES('Blargy')
right? But I've run into a couple of surprises, and I was hoping that
the Moose masters here could shed some light. :)
First thing is that I note that Moose::Util::TypeConstraint::Role
doesn't actually do that. Rather, it does this:
Moose::Util::does_role($_[0], $role)
Is that different from just calling DOES?
Second thing was that, since I have to account for the type being
_either_ a class or a role (or a basic type such as Int, etc, but
let's assume I already called find_or_parse_type_constraint earlier),
I tried something like this:
if
(Moose::Util::TypeConstraint::find_type_constraint->("ClassName")->check($type))
{
$constr = Moose::Util::TypeConstraint::class_type($type);
}
elsif
(Moose::Util::TypeConstraint::find_type_constraint->("RoleName")->check($type))
{
$constr = Moose::Util::TypeConstraint::role_type($type);
}
You can probably see right off that I have a bug there. I can't check
to see if it's a classname first, because every role _is_ a class. I
need to check for roles first. That wasn't the surprising part. The
surprising part was that _it still works this way_. ANAICT, role_type
never gets called, and all my role constraints end up being created by
class_type, and when I dump them out they are indeed
Moose::Meta::TypeConstraint::Class objects and not
Moose::Meta::TypeConstraint::Role objects, but still when I get to the
end and do:
$constr->check($val);
it passes. Now, I reversed the order anyway, just to make myself feel
better (and to avoid running into some super-subtle bug one day that I
might kill myself over not being able to track down), but I'm mightily
curious as to why it actually works.
My real problem, though, it that I want this to work with all possible
roles, regardless of where they come from. Now, assuming I go back
and invoke the proper Any::Moose incantations (which I have), then
when Moose is loaded this works with Moose roles but not Mouse roles,
and when Mouse is loaded it works with Mouse roles but not Moose
roles, which I think _might_ be good enough. Or is it? I suppose
there's always a chance that you could be including some modules which
use Moose and some which use Mouse ... but that seems so unlikely that
I'm not sure it's worth worrying about. I'd be interested in hearing
what others think.
And of course no matter which one I have loaded, it doesn't work with
Role::Basic roles. Because the RoleName type constraint doesn't
consider them to be roles, and, even if it did, it wouldn't DTRT (see
first surprise). So I'll have to check for that separately (seems
easy enough) and create my own type constraint for it, which I _think_
should just do the DOES check. Something like so:
type "RoleBasic$type" => where { $_->DOES($type) };
Right? Or should I make them all subtypes of a common type (I can't
see any advantage in that ATM, but perhaps I'm missing something)?
Am I on the right track here, or does anyone smarter than I see any
pitfalls? TIA!
-- Buddy