Состав атрибутов класса Perl? - PullRequest
4 голосов
/ 31 января 2011

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

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; Однако это не сработает с 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;

    ...
}

Обновление: Поскольку разные люди просили меня на 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;
    ...
}

Ответы [ 2 ]

7 голосов
/ 31 января 2011

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

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

5 голосов
/ 31 января 2011

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

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

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

...