The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

MooseX::Collect - provides method modifier for collecting method calls from roles and superclasses

SYNOPSIS

    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;
    use MooseX::Collect;
    
    # easy syntax
    collect 'items';
    
    # ...or with explicit collection subroutine (allows you to process results)
    collect 'items' => sub {
        my $self = shift;
        return @_;
    };
    
    # ...or with explicit arguments for fine-grained configuration
    collect 'itemz' => (
        provider     => 'items',
        from         => [qw(self superclasses roles)],
        method_order => 'standard',
        context      => 'list',
        collector    => sub {
            my $self = shift;
            return @_;
        },
        superclass_recurse => 1,
    );
    
    # 'with' statements must be called after any 'collect'
    with qw(B C);

Then you can call your collector and get everything:

    my @items = $Foo->items;  # watermelon, apple, orange, banana

ABSTRACT

MooseX::Collect exports a "collect" method modifier that allows you to collect/compose the results of a method call dispatched to superclasses and/or roles of a given class. Its interface is designed to be easy and similar to standard Moose method modifiers: nothing special is required in the inherited classes, you just need to call the "collect" modifier in your final class in order to set up a method that will call all methods with the provided name in the inherited classes and return you the results.

Any arguments passed to the newly created accessor will be passed to each method call.

EXPORTED FUNCTIONS

collect $method_name
collect $method_name => sub {}
collect $method_name => ()

This will install a method of a given $method_name into the current class. You can pass a hash of options to the function. Available options are listed below. As a shortcut, you can pass a coderef: it will be used as a collector option (see below).

provider => $provider_method_name

This option sets the name of the method that will be searched in the inherited classes. This is useful if you want to use a different name for the local accessor. By default, the providers method name is the same of the accessor name (i.e. the $method_name you passed to collect). The provider methods are called as object methods (that is, with the current object in $_[0]).

from => 'self' | 'superclass' | 'roles' | ARRAYREF

This options accepts a string containing one of the above values or an arrayref containing one or more of them. Use it to specify the scope of your collection, i.e. which classes you want MooseX::Collect to search for provider methods. The order is relevant. The value self enables searching of the method inside the class of the current object too. The default value is self, superclass, roles.

method_order => 'standard' | 'reverse'
method_order => 'top_down' | 'bottom_up'

This option lets you reverse the default method resolution order, which is standard (aliased as top_down): derived classes will be called first. If you set this to reverse or bottom_up, base classes will be called first.

superclass_recurse => BOOL

By setting this options to false, MooseX::Collect will not recurse into parent classes but will only call the uppermost method available (i.e. the one that overrides any other with the same name implemented by parent classes). This option, which is false by default (allowing full recursion), does not affect searching in roles because they have no hierarchy.

context => 'scalar' | 'list'>

This arguments lets you set the Perl context to use when calling the provider methods. By default its value is list.

collector => CODEREF

If you want to customize or filter the collection results, you can provide a custom coderef. It will receive the results in @_ and it's expected to return a list. It will be called as an object method, so $_[0] will contain your object.

INHERITANCE

Not surprisingly, collector methods are inherited by your subclasses. As you would expect, a subclass can override an inherited collector by defining a method with the same name. If you want to collect things from your subclasses, you need to set the provider attribute (see above) to a different name than your collector name:

    package Foo;
    use Moose;
    use MooseX::Collect;
    sub items { qw/apple/ }
    collect 'get_items' => (
        provider => 'items',
    );
    
    package Bar;
    use Moose;
    extends 'Foo';
    sub items { qw/orange/ }

    package Baz;
    my @items = Bar->new->get_items;  # orange, apple

This is required also if you define your collector method in a role that you import.

Note that the self scope is relative to the object, and not to the class where the collector is defined. So, if you add a from => 'self' attribute in the above example, the call to get_items will return "orange". The element "apple" will be available in the superclasses scope.

CAVEATS

Don't use the collect method modifier to collect data from methods that are already defined as attribute accessors or extended by other method modifiers such as around, override etc. or by another collect modifier. In such cases, the behaviour of this module is undefined and unsupported. You should avoid such usage until a proper policy (and the related test suite) is defined.

As a general rule, collect declarations should be done before every with invocation that you use to import roles in your class. This is because Moose will throw an error when your roles provide methods with the same name unless your class defines such a method too. By calling collect before with, you install a method in your class and Moose will not complain. If you don't like this, you can populate the -excludes attribute of with (see Moose::Manual::Roles) with your provider method name:

    with 'B' => { -excludes => 'items' },
         'C' => { -excludes => 'items' };
    
    collect 'items';

Another workaround is to define a provider method in your class (whether you need it or not):

    # the order of these three lines is not relevant:
    with qw(B C);
    collect 'items';
    sub items () {}

SEE ALSO

Moose
Moose::Role
MooseX::ComposedBehavior

BUGS

Please report any bugs to bug-moosex-collect@rt.cpan.org, or through the web interface at https://rt.cpan.org/Public/Bug/Report.html?Queue=MooseX-Collect. The author will be happy to read your feedback.

AUTHOR

Alessandro Ranellucci <aar@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Alessandro Ranellucci.

This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.