Perl class attribute composition?

Suppose I have several roles, each of which defines a set of elements:

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/ } 

Suppose I use them in another class and I want to collect all these elements:

 package Foo; use Moose; with qw(BC); sub do_something { my $self = shift; my @items = ???; # How can I get apple, orange, watermelon, banana here? .... } 

One possible solution is to take MooseX :: ComposedBehavior , but its POD says (at the time of writing, of course) that its API is "not completely stable" and that "the current implementation is a bit of a hack and needs to be replaced with a more reliable one " Thus, I am exploring whether this can be done without relying on such a โ€œhackโ€.

Warning: if you are reading this in the future, go to check POD MooseX :: ComposedBehavior (current version: 0.003) because it could be changed on average. Things are changing fast. CPAN authors release new versions. That which is "not entirely stable" at the moment may become more stable in the future. There may be other modules. Check yourself.

Ideally, it should be something like: my @items = map $_->items, @ISA; However, this is not with Mus. Are there any more reliable and reliable solutions?


Update: I finished this three-line solution:

 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(BC); sub items () {} sub do_something { my $self = shift; my @items = map $_->execute, grep $_, map $_->get_method('items'), $self->meta->calculate_all_roles_with_inheritance; ... } 

Update:. As various people asked me on the # moose IRC channel , I removed my previous statement that MooseX :: ComposedBehavior is โ€œunstableโ€ and replaced it with literal text taken from its POD.


Update: I wrote a MooseX :: Collect module that allows you to use the following syntax:

 package Foo; use Moose; use MooseX::Collect; collect 'items'; with qw(BC); sub do_something { my $self = shift; my @items = $self->items; ... } 
+4
source share
2 answers

You need to use 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/BC/; sub items {} 

But in general, using classes to represent data is not true as instances of classes. It is difficult to give further advice, since your example is so great. What are you really trying to do?

+7
source

After you pointed to MooseX::ComposedBehavior before the IRC, I'm not quite sure why you feel you shouldn't use it. In the end, this definitely solves the problem you are facing.

Yes, he says his interface may change a bit in the future. However, how much work will it take for you to adapt to these small changes? In comparison, how long do you think you will need an alternative solution and actually implement it? Do you think your decision will be compared with MooseX::ComposedBehavior in such things as correctness and reliability? At least I would not trust myself to reinvent the wheel originally invented by RJBS, and expected my solution to work out better.

In addition, if you are really worried about a module warning you of possible future changes, go with its author and help him get it in a form that he is happy with, to declare it stable. Write some more tests for your specific use. Talk to Ricardo, he's a good guy.

+5
source

Source: https://habr.com/ru/post/1337761/


All Articles