Вопрос

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

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::ComposeBehavior но его POD говорит (конечно, на момент написания статьи), что его API «не совсем стабилен», а также что «текущая реализация является чем-то вроде хака и должна быть заменена более надежной».Поэтому я исследую, можно ли этого добиться, не полагаясь на такой «взлом».

Предупреждение: если вы будете читать это в будущем, пожалуйста, проверьте POD MooseX::ComposeBehavior (текущая версия: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::ComposeBehavior «нестабилен», и заменил его буквальным текстом, взятым из его POD.


Обновлять: Я написал MooseX::Собрать модуль, который допускает следующий синтаксис:

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

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

sub do_something {
    my $self = shift;
    my @items = $self->items;
    ...
}
Это было полезно?

Решение

Вам нужно использовать 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, и ожидать, что мое решение окажется лучше.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top