Mouseで「あるメソッドを持ったオブジェクト」という制約をつくる

互いに継承関係がなくてもRoleを適用していなくても duck_type() を使えばOK!しかも自前で can() するより高速なスグレモノ*1

use strict;
use warnings;

package Foo {
    use Mouse;

    sub x { 1 }

    __PACKAGE__->meta->make_immutable();
}

package Bar {
    use Mouse;

    sub x { 2 }

    __PACKAGE__->meta->make_immutable();
}

package Baz {
    use Mouse;

    __PACKAGE__->meta->make_immutable();
}

package Main;
use Mouse;
use Mouse::Util::TypeConstraints;

duck_type 'MyApp.TypeWithFoo' => [qw(foo)]; # named type constraint

has obj => (
   is => 'rw',
   isa => duck_type([qw(x)]), # anonymous type constraint
);

my $m = Main->new();
$m->obj(Foo->new); # OK
$m->obj(Bar->new); # OK
$m->obj(Baz->new); # NG: Attribute (obj) does not pass the type constraint because: Baz is missing methods 'x'

Mooと違ってサブルーチンを直接isaに指定することは出来ないのですが*2、type constraintはそこそこ使いやすいので慣れれば問題にならないと思います。

*1:Mouse::Util::TypeConstraintsのpodには何も書いてなくてひどいなーと思いました!

*2:曖昧ではないので指定するようにもできるし、そのうちするかもしれませんが