Mooseベースのクラスがたくさんあるコードベースがあり、それらすべてにMooseX::*拡張モジュールの共通セットを使用させたいとします。しかし、Moose ベースの各クラスを次のように開始する必要はありません。
package My::Class;
use Moose;
use MooseX::Aliases;
use MooseX::HasDefaults::RO;
use MooseX::StrictConstructor;
...
代わりに、各クラスを次のように開始します。
package MyClass;
use My::Moose;
上記とまったく同等にする必要があります。
これを実装する最初の試みは、 Mason::Moose ( source )で使用されるアプローチに基づいていました。
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.perl.org の #moose IRC チャネルの人々によって推奨されておらず、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) それは私が使用したいモジュールの 1 つであり、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 ...