Допустим, у меня есть кодовая база с кучей классов на основе Moose -, и я хочу, чтобы все они использовали общий набор модулей расширения MooseX ::*. Но я не хочу, чтобы каждый класс, основанный на Moose -, начинался вот так :
package My::Class;
use Moose;
use MooseX::Aliases;
use MooseX::HasDefaults::RO;
use MooseX::StrictConstructor;
...
. Вместо этого я хочу, чтобы каждый класс начинался вот так:
package MyClass;
use My::Moose;
и был в точности эквивалентен приведенному выше.
Моя первая попытка реализовать это была основана на подходе, использованном Мэйсоном ::Мусом(источником):
package My::Moose;
use Moose;
use Moose::Exporter;
use MooseX::Aliases();
use MooseX::StrictConstructor();
use MooseX::HasDefaults::RO();
use Moose::Util::MetaRole;
Moose::Exporter->setup_import_methods(also => [ 'Moose' ]);
sub init_meta {
my $class = shift;
my %params = @_;
my $for_class = $params{for_class};
Moose->init_meta(@_);
MooseX::Aliases->init_meta(@_);
MooseX::StrictConstructor->init_meta(@_);
MooseX::HasDefaults::RO->init_meta(@_);
return $for_class->meta();
}
Но этот подход не рекомендуется людьми на #канале IRC moose в irc..perl.org, и это не всегда работает, в зависимости от набора модулей MooseX::*
. Например,попытка использовать класс My::Moose
выше, чтобы сделать My::Class
таким:
package My::Class;
use My::Moose;
has foo => (isa => 'Str');
Приводит к следующей ошибке при загрузке класса:
Attribute (foo) of class My::Class has no associated methods (did you mean to provide an "is" argument?)
at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose/Meta/Attribute.pm line 1020.
Moose::Meta::Attribute::_check_associated_methods('Moose::Meta::Class::__ANON__::SERIAL::2=HASH(0x100bd6f00)') called at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose/Meta/Class.pm line 573
Moose::Meta::Class::add_attribute('Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x100be2f10)', 'foo', 'isa', 'Str', 'definition_context', 'HASH(0x100bd2eb8)') called at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose.pm line 79
Moose::has('Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x100be2f10)', 'foo', 'isa', 'Str') called at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose/Exporter.pm line 370
Moose::has('foo', 'isa', 'Str') called at lib/My/Class.pm line 5
require My/Class.pm called at t.pl line 1
main::BEGIN() called at lib/My/Class.pm line 0
eval {...} called at lib/My/Class.pm line 0
Должен быть MooseX ::HasDefaults ::RO предотвращает эту ошибку, но, по-видимому, он не призван выполнять свою работу. Комментирование строки MooseX::Aliases->init_meta(@_);
«решает» проблему, но a )— это один из модулей, которые я хочу использовать, а b )еще больше подчеркивает ошибочность этого решения. (В частности, init_meta()
следует вызывать только один раз.)
Итак, я открыт для предложений, полностью игнорируя мою неудачную попытку реализовать это. Приветствуется любая стратегия, если она дает результаты, описанные в начале этого вопроса.
Основываясь на ответе @Ether, теперь у меня есть следующее (, которое также не работает):
package My::Moose;
use Moose();
use Moose::Exporter;
use MooseX::Aliases();
use MooseX::StrictConstructor();
use MooseX::HasDefaults::RO();
my %class_metaroles = (
class => [
'MooseX::StrictConstructor::Trait::Class',
],
attribute => [
'MooseX::Aliases::Meta::Trait::Attribute',
'MooseX::HasDefaults::Meta::IsRO',
],
);
my %role_metaroles = (
role =>
[ 'MooseX::Aliases::Meta::Trait::Role' ],
application_to_class =>
[ 'MooseX::Aliases::Meta::Trait::Role::ApplicationToClass' ],
application_to_role =>
[ 'MooseX::Aliases::Meta::Trait::Role::ApplicationToRole' ],
);
if (Moose->VERSION >= 1.9900) {
push(@{$class_metaroles{class}},
'MooseX::Aliases::Meta::Trait::Class');
push(@{$role_metaroles{applied_attribute}},
'MooseX::Aliases::Meta::Trait::Attribute',
'MooseX::HasDefaults::Meta::IsRO');
}
else {
push(@{$class_metaroles{constructor}},
'MooseX::StrictConstructor::Trait::Method::Constructor',
'MooseX::Aliases::Meta::Trait::Constructor');
}
*alias = \&MooseX::Aliases::alias;
Moose::Exporter->setup_import_methods(
also => [ 'Moose' ],
with_meta => ['alias'],
class_metaroles => \%class_metaroles,
role_metaroles => \%role_metaroles,
);
С таким классом-образцом:
package My::Class;
use My::Moose;
has foo => (isa => 'Str');
Я получаю эту ошибку:
Attribute (foo) of class My::Class has no associated methods (did you mean to provide an "is" argument?) at...
С таким классом-образцом:
package My::Class;
use My::Moose;
has foo => (isa => 'Str', alias => 'bar');
] Я получаю эту ошибку:
Found unknown argument(s) passed to 'foo' attribute constructor in 'Moose::Meta::Attribute': alias at...