Как мне составить существующую роль Moose в класс во время выполнения?
Скажем, я определяю абстрактные реализации My::Object и конкретной роли My::Object::TypeA и My::Object::TypeB. Из соображений удобства обслуживания я бы не хотел иметь жестко закодированную таблицу, которая бы смотрела на тип объекта и применяла роли. В качестве примера DWIMmy я ищу что-то вроде этого в My::Object:
has => 'id' (isa => 'Str', required => 1);
sub BUILD {
my $self = shift;
my $type = $self->lookup_type(); ## Returns 'TypeB'
{"My::Object::$type"}->meta->apply($self);
}
Позвольте мне получить My::Object с ролью My::Object:: TypeB, выполнив следующие действия:
my $obj = My::Object(id = 'foo')
Будет ли это делать то, что я хочу, или я на неправильном пути?
Изменить: я слишком упростил это; Я не хочу знать тип, когда я создаю экземпляр объекта, я хочу, чтобы объект определил его тип и применил правильные методы роли соответствующим образом. Я отредактировал свой вопрос, чтобы сделать это более понятным.
3 ответа
Ты это пробовал?
$perl -Moose -E'
sub BUILD { my ($self, $p) = @_; my $role = qq[Class::$$p{role}]; $role->meta->apply($self) };
package Class::A; use Moose::Role; has a => (is => q[ro], default => 1);
package main; say Class->new(role => q[A])->dump'
Урожайность:
$VAR1 = bless( {
'a' => 1
}, 'Class::MOP::Class::__ANON__::SERIAL::1' );
Похоже, это то, что вы хотите. Убран код в вызове oose.pm:
package Class;
use Moose;
sub BUILD {
my ($self, $p) = @_;
my $role = qq[Class::$$p{role}];
$role->meta->apply($self);
}
package Class::A;
use Moose::Role;
has a => ( is => 'ro', default => 1 );
package main;
Class->new(role => 'A');
Использование MooseX::Traits
, это превратит вашу роль в черту, которую можно применить во время выполнения, тогда вы просто позвоните:
# Where Class is a class that has `use MooseX::Traits`;
# And TypeB is a simple role
Class->new_with_traits( traits => [qw/TypeB/] )
# or even the new, and now preferred method.
Class->with_traits('TypeB')->new();
После обновления вопроса я дам еще один кряк: with()
это просто вызов функции.
package Class;
use Moose;
BEGIN {
with ( map "MyObject::$_", qw/TypeA TypeB/ );
}
Также вы можете ссылаться на текущий пакет с помощью константы perl __PACKAGE__
,