Search code examples
perlrolesmoose

Checking a Moose role against a non Moose class


let's say you've got a Moose class that requires an attribute that does a Role:

package MyMooseClass;
use Moose;

has 'a' => ( does => 'MyRole' );

Now, I'd like to build an instance of MyMooseClass like this:

my $instance = MyMooseClass->new( { a => $a_non_moose_stuff } );

Where $a_non_moose_stuff is an instance of a non-moose class, but that implements the required role methods.

Is there a way to have Moose to check that my $a_non_moose_stuff complies with the role, even though it's not implemented using Moose?


Solution

  • The easiest thing is to use a duck_type instead of a role to validate your interface. A duck_type is a looser restriction, basically the duck_type is just a list of methods the object is expected to have. For example:

    package MyMooseClass;
    use Moose;
    use Moose::Util::TypeConstraints qw/duck_type/;
    
    has 'a' => (
      isa => duck_type(qw/method1 method1 some_other_method/),
    );
    

    See Moose::Util::TypeConstraints and scroll down a bit til you see the entry for duck_type. This constraint was added specifically to deal with this kind of issue.

    If you are going to reuse this constraint a lot, you might want to look at creating it in a type library class, which will promote reuse. Check out MooseX::Types.

    BTW, although using a Hash Reference in the constructor is supported, and for a long time prior to Moose considered a best practice, most Moose authors I know skip it and just supply a list of constructor parameters. Its a bit less typing and looks cleaner, in my opinion:

    my $instance = MyClass->new(param1=>'val1', param2=>'val2');
    

    The main point of the Hash Reference approach was to help solve some ambiguities that really don't happen when you are using Moose to construct your Perl object. Since Moose deals with all that boilerplate and ceremony for you, it is unnecessary in my opinion, although styles do vary. My two cents.

    Take it easy,

    John