如何访问我的 Moose 角色所应用的模块的元类?
我正在使用 Moose roles 在类中的某些访问器方法周围应用一些包装器行为。我想将此角色应用于多个模块,每个模块都有一组不同的属性,我想包装其访问器。有没有办法从角色内部访问正在应用的模块的元类?即像这样:
package My::Foo;
use Moose;
with 'My::Role::X';
has [ qw(attr1 attr2) ] => (
is => 'rw', # ...
);
has 'fields' => (
is => 'bare', isa => 'ArrayRef[Str]',
default => sub { [qw(attr1 attr2) ] },
);
1;
package My::Role::X;
use Moose::Role;
# this should be a Moose::Meta::Class object
my $target_meta = '????';
# get Class::MOP::Attribute object out of the metaclass
my $fields_attr = $target_meta->find_attribute_by_name('fields');
# extract the value of this attribute - should be a coderef
my $fields_to_modify = $fields_attr->default;
# evaluate the coderef to get the arrayref
$fields_to_modify = &$fields_to_modify if ref $fields_to_modify eq 'CODE';
around $_ => sub {
# ...
} for @$fields_to_modify;
1;
I'm using Moose roles to apply some wrapper behaviour around some accessor methods in a class. I want to apply this role to a number of modules, each of which have a different set of attributes whose accessors I want to wrap. Is there a way to access the meta class of the module being applied to, from within the role? i.e. something like this:
package My::Foo;
use Moose;
with 'My::Role::X';
has [ qw(attr1 attr2) ] => (
is => 'rw', # ...
);
has 'fields' => (
is => 'bare', isa => 'ArrayRef[Str]',
default => sub { [qw(attr1 attr2) ] },
);
1;
package My::Role::X;
use Moose::Role;
# this should be a Moose::Meta::Class object
my $target_meta = '????';
# get Class::MOP::Attribute object out of the metaclass
my $fields_attr = $target_meta->find_attribute_by_name('fields');
# extract the value of this attribute - should be a coderef
my $fields_to_modify = $fields_attr->default;
# evaluate the coderef to get the arrayref
$fields_to_modify = &$fields_to_modify if ref $fields_to_modify eq 'CODE';
around $_ => sub {
# ...
} for @$fields_to_modify;
1;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看起来 MooseX::Role::Parameterized 可以解决问题:
角色专业化的详细信息是避免班级被扩大;它甚至不需要传递任何参数,它只需要知道将哪些参数(要包装的字段列表)传递给角色即可。唯一的关键是角色必须在类上定义相关属性之后使用。
因此,所使用的类和角色的定义如下:
附录:我发现,如果一个参数化角色使用另一个参数化角色,则嵌套角色中的
$target_meta
将实际上是父角色的元类(isaMooseX::Role::Parameterized::Meta::Role::Parameterized
),而不是消费类的元类(isa <代码>Moose::Meta::Class)。为了派生正确的元类,您需要显式地将其作为参数传递。我已将此作为“最佳实践”模板添加到我的所有参数化角色中:附录 2:我进一步发现,如果将角色应用于对象实例,与类相反,那么角色中的
$target_meta
实际上将是执行消费的对象的类:因此,在参数化角色开始时提取元类时,此代码是必要的:
It looks like MooseX::Role::Parameterized will do the trick:
The details of the role specialization is kept from the class being augmented; it doesn't even need to pass any parameters all it needs to know is what parameters (the list of fields to wrap) to pass to the role. The only key is that the role must be used after the relevant attributes have been defined on the class.
Therefore, the consumed class and the role become defined like so:
Addendum: I have discovered that if a parameterized role consumes another parameterized role, then
$target_meta
in the nested role will actually be the meta-class of the parent role (isaMooseX::Role::Parameterized::Meta::Role::Parameterized
), rather than the meta-class of the consuming class (isaMoose::Meta::Class
). In order for the proper meta-class to be derived, you need to explicitly pass it as a parameter. I have added this to all my parameterized roles as a "best practice" template:Addendum 2: I have further discovered that if the role is being applied to an object instance, as opposed to a class, then
$target_meta
in the role will actually be the class of the object doing the consuming:Therefore, this code is necessary when extracting the meta-class at the start of the parameterized role: