4

假设我有多个角色,每个角色定义一组项目:

package A;
use Moose::Role;
sub items () { qw/apple orange/ }

package B;
use Moose::Role;
with 'A';
sub items () { qw/watermelon/ }

package C;
use Moose::Role;
sub items () { qw/banana/ }

假设我在另一个类中使用它们并且我想收集所有这些项目:

package Foo;
use Moose;
with qw(B C);

sub do_something {
    my $self = shift;
    my @items = ???;   # How can I get apple, orange, watermelon, banana here?
    ....
}

一种可能的解决方案是采用MooseX::ComposedBehavior,但它的 POD 说(当然在撰写本文时)它的 API“不太稳定”并且“当前的实现有点像 hack,应该被替换由一个更强大的“。因此,我正在调查这是否可以在不依赖这种“黑客”的情况下完成。

警告:如果您将来阅读此内容,请检查MooseX::ComposedBehavior(当前版本:0.003)的 POD,因为它可能同时发生了变化。事情变化很快。CPAN 作者发布新版本。目前“不太稳定”的东西将来可能会变得更加稳定。甚至可能还有其他模块。自行检查。

理想情况下应该有类似的东西:my @items = map $_->items, @ISA; 但是这不适用于 Moose。有没有更好更可靠的解决方案?


更新:我最终得到了这个三行解决方案:

package A;
use Moose::Role;
sub items () { qw/apple orange/ }

package B;
use Moose::Role;
with 'A';
sub items () { qw/watermelon/ }

package C;
use Moose::Role;
sub items () { qw/banana/ }

package Foo;
use Moose;
with qw(B C);
sub items () {}

sub do_something {
    my $self = shift;

    my @items = map $_->execute, grep $_, 
        map $_->get_method('items'),
        $self->meta->calculate_all_roles_with_inheritance;

    ...
}

更新:由于许多人在#moose IRC 频道中向我提出要求,我删除了我之前关于 MooseX::ComposedBehavior “不稳定”的断言,并将其替换为从其 POD 中获取的文字文本。


更新:我写了一个MooseX::Collect模块,它允许以下语法:

package Foo;
use Moose;
use MooseX::Collect;

collect 'items';
with qw(B C);

sub do_something {
    my $self = shift;
    my @items = $self->items;
    ...
}
4

2 回答 2

7

您需要使用around

package A;
use Moose::Role;
requires 'items';
around items => sub {
    my ($orig, $self, @args) = @_;
    return ($self->$orig(@args), qw/apple orange/);
};

package B;
use Moose::Role;
requires 'items';
with 'A'; # not required, do it if you want it
around items => sub {
    my ($orig, $self, @args) = @_;
    return ($self->$orig(@args), qw/watermelon/);
};

package C;
use Moose::Role;
requires 'items';
around items => sub {
    my ($orig, $self, @args) = @_;
    return ($self->$orig(@args), qw/banana/);
};

package Class;
use Moose;
with qw/B C/;
sub items {}

但总的来说,使用类来表示数据是错误的,这就是 类实例的用途。由于您的示例非常琐碎,因此很难提供进一步的建议。你真正想做什么?

于 2011-01-31T11:58:29.250 回答
5

在你MooseX::ComposedBehavior之前在 IRC 上指出之后,我不完全确定你为什么觉得你不应该使用它。毕竟,它确实可以解决您遇到的问题。

是的,它确实说它的界面将来可能会略有变化。但是,要适应这些细微的变化,您需要做多少工作?相比之下,您认为您需要多长时间才能提出替代解决方案并实际实施?您认为您的解决方案与MooseX::ComposedBehavior正确性和稳健性等方面相比如何?至少我不会相信自己重新发明最初由 RJBS 发明的轮子并期望我的解决方案会变得更好。

另外,如果你真的非常担心一个模块会警告你未来可能发生的变化,那就去和它的作者一起工作,帮助他把它变成一个他很高兴宣布它稳定的形状。为您的特定用例编写更多测试。和里卡多谈谈,他是个好人。

于 2011-01-31T13:59:35.760 回答