Состав атрибутов класса Perl?

Предположим, у меня есть несколько ролей, каждая из которых определяет набор элементов:

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 "не совсем стабилен", а также что "текущая реализация является чем-то вроде хака, и его следует заменить более надежным ". Таким образом, я расследую, можно ли это сделать, не полагаясь на такой "взлом".

Предупреждение: если вы читаете это в будущем, перейдите, чтобы проверить POD MooseX::ComposedBehavior (текущая версия: 0.003), потому что он мог измениться за это время. Вещи меняются быстро. Авторы CPAN выпускают новые версии. То, что "не совсем стабильно" в данный момент, может стать более стабильным в будущем. Там могут быть даже другие модули. Проверь себя.

В идеале должно быть что-то вроде: my @items = map $_->items, @ISA;Однако это не будет работать с лося. Есть ли более приятные и надежные решения?


Обновление: я закончил с этим решением с тремя линиями:

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;

    ...
}

Обновление: так как разные люди просили меня на IRC-канале #moose, я удалил свое предыдущее утверждение, что 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;
    ...
}

2 ответа

Решение

Вам нужно использовать 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 {}

Но в целом использование классов для представления данных - это неправильно, для этого нужныэкземпляры классов. Трудно дать дальнейшие советы, так как ваш пример настолько тривиален. Что ты на самом деле пытаешься сделать?

После того, как вы указали на MooseX::ComposedBehavior до IRC, я не совсем уверен, почему вы чувствуете, что не должны его использовать. В конце концов, это точно решит проблему, с которой вы столкнулись.

Да, он говорит, что его интерфейс может немного измениться в будущем. Тем не менее, сколько вам понадобится адаптироваться к этим небольшим изменениям? Для сравнения, как вы думаете, сколько времени вам понадобится, чтобы придумать альтернативное решение и реализовать его на самом деле? Как вы думаете, будет ли ваше решение сравниваться с MooseX::ComposedBehavior в таких вещах, как правильность и надежность? По крайней мере, я бы не стал доверять себе, изобретая колесо, изначально изобретенное RJBS, и ожидая, что мое решение получится лучше.

Кроме того, если вы действительно сильно беспокоитесь о модуле, предупреждающем вас о возможных будущих изменениях, поработайте с его автором и помогите ему придать ему форму, которой он доволен, объявив его стабильным. Напишите еще несколько тестов для вашего конкретного варианта использования. Поговори с Рикардо, он хороший парень.

Другие вопросы по тегам