Dường như MooseX::Role::Parameterized sẽ làm các trick:
vai trò thông thường có thể yêu cầu người tiêu dùng của mình có một danh sách cụ thể của tên phương pháp. Vì các vai trò được tham số hóa có quyền truy cập trực tiếp vào người tiêu dùng, bạn có thể kiểm tra và ném lỗi nếu người tiêu dùng không đáp ứng nhu cầu của bạn. (link)
Chi tiết về vai trò chuyên môn được lưu giữ trong lớp học được tăng cường; nó thậm chí không cần phải vượt qua bất kỳ tham số tất cả nó cần biết là những gì các thông số (danh sách các lĩnh vực để bọc) để vượt qua vai trò. Chìa khóa duy nhất là vai trò phải được sử dụng sau khi các thuộc tính có liên quan đã được xác định trên lớp.
Do đó, lớp tiêu thụ và vai trò trở thành định nghĩa như sau:
package My::Foo;
use Moose;
my @fields = qw(attr1 attr2);
has \@fields => (
is => 'rw', # ...
);
has 'fields' => (
is => 'bare', isa => 'ArrayRef[Str]',
default => sub { \@fields },
);
with 'My::Role::X' => {};
1;
package My::Role::X;
use MooseX::Role::Parameterized;
role {
my $p = shift;
my %args = @_;
# this should be a Moose::Meta::Class object
my $target_meta = $args{consumer};
# 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;
Phụ Lục: Tôi đã phát hiện ra rằng nếu một vai trò tham số tiêu thụ một vai trò tham số, sau đó $target_meta
trong vai trò lồng nhau sẽ thực sự là siêu lớp của vai trò cha mẹ (isa MooseX::Role::Parameterized::Meta::Role::Parameterized
), thay vì lớp meta của lớp tiêu thụ (isa Moose::Meta::Class
). Để có được lớp meta thích hợp, bạn cần phải chuyển nó thành một tham số. Tôi đã thêm này cho tất cả các vai trò tham số của tôi như là một "thực hành tốt nhất" mẫu:
package MyApp::Role::SomeRole;
use MooseX::Role::Parameterized;
# because we are used by an earlier role, meta is not actually the meta of the
# consumer, but of the higher-level parameterized role.
parameter metaclass => (
is => 'ro', isa => 'Moose::Meta::Class',
required => 1,
);
# ... other parameters here...
role {
my $params = shift;
my %args = @_;
# isa a Moose::Meta::Class
my $meta = $params->metaclass;
# class name of what is consuming us, om nom nom
my $consumer = $meta->name;
# ... code here...
}; # end role
no Moose::Role;
1;
Phụ Lục 2: Tôi đã phát hiện thêm rằng nếu vai trò đang được áp dụng cho một ví dụ đối tượng, như trái ngược với một lớp, sau đó $target_meta
trong vai trò thực sự sẽ là lớp của đối tượng làm tiêu thụ:
package main;
use My::Foo;
use Moose::Util;
my $foo = My::Foo->new;
Moose::Util::apply_all_roles($foo, MyApp::Role::SomeRole, { parameter => 'value' });
package MyApp::Role::SomeRole;
use MooseX::Role::Parameterized;
# ... use same code as above (in addendum 1):
role {
my $meta = $args{consumer};
my $consumer = $meta->name; # fail! My::Foo does not implement the 'name' method
Do đó, mã này là cần thiết khi giải nén meta-class khi bắt đầu vai trò được tham số hóa:
role {
my $params = shift;
my %args = @_;
# could be a Moose::Meta::Class, or the object consuming us
my $meta = $args{consumer};
$meta = $meta->meta if not $meta->isa('Moose::Meta::Class'); # <-- important!
Đây là một trong những điều mà mô-đun được viết. – perigrin
Lưu ý: Tôi không còn xem xét "thực hành tốt nhất" ở trên, và thực sự đã tái cấu trúc tất cả (ab) việc sử dụng MXRP này. IMHO nếu bạn cần truy cập '$ meta' từ bên trong vai trò, bạn có thứ gì đó bốc mùi trong thiết kế của mình. – Ether