Perl类的属性组成?

Ale*_*dro 4 perl moose composition collect class-attributes

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

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/ }
Run Code Online (Sandbox Code Playgroud)

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

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?
    ....
}
Run Code Online (Sandbox Code Playgroud)

一种可能的解决方案是采用MooseX :: ComposedBehavior,但是它的POD说(当然在编写时)它的API"不太稳定",而且"当前的实现是一种破解,应该被替换通过更健壮的一个".因此,我正在调查这是否可以在不依赖于这种"黑客"的情况下完成.

警告:如果您将来阅读此内容,请查看MooseX :: ComposedBehavior的POD (当前版本:0.003),因为它可能在平均时间内发生了变化.事情变化很快.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;

    ...
}
Run Code Online (Sandbox Code Playgroud)

更新:由于各种人在#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;
    ...
}
Run Code Online (Sandbox Code Playgroud)

jro*_*way 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 {}
Run Code Online (Sandbox Code Playgroud)

但一般来说,使用类来表示数据是错误的,这就是类的 实例.很难提供进一步的建议,因为你的例子如此繁琐.你真的想做什么?


raf*_*afl 5

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

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

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

  • 我对它的POD中的MooseX :: ComposedBehavior警告有点害怕"当前的实现是一种破解"并且它的API"不太稳定,可能还会改变",所以我想仔细检查我的需求是否可以满意而不会再次出现"黑客".除此之外,我非常了解里卡多的模块,我不讨论他们的质量:-) (2认同)
  • 它还表示,如果您偏离了文档化的API,那么更改可能会出现在内部,并且可能会遇到问题.我没有看到其中任何一个会影响您的用例. (2认同)