On May 8, 2010, at 9:27 AM, Eric Veith1 wrote:
Hello folks!
I'd like to create a role that adds an "around" modifier to all
methods of
a concrete class that assumes the role. However, the modifier shall
*not*
include attributes, methods provided by the role itself or methods
inherited.
Currently, I have the following code, which at least seems to create
a list
containing the entries I want:
----%<----
package RLGC::Command;
use Moose::Role;
# [...]
sub BUILD {
my $self = shift;;
# Set up wrapper for all methods in the class that assumes with
role.
That
# is, every method gets an "around" handler that assumes the duty
of.
# forking if necessary, storing results in the datastore, and so
on..
my @own_attributes = $self->meta->get_attribute_list;
my @own_methods = $self->meta->get_method_list;
my @role_methods_and_attributes = (
RLGC::Command->meta->get_attribute_list,
RLGC::Command->meta->get_method_list);
my @complement = grep { !($_ ~~ @role_methods_and_attributes) }
(@own_attributes, @own_methods);
# Make sure we don't fork for attributes. :^)
@complement = grep { !($_ ~~ @own_attributes) } @complement;)
foreach(@complement) {
$self->meta->add_around_method_modifier('__execute');
}
}
---->%----
As you might have guessed from the snipped, the modifier's
subroutine is
called "__execute".
First, is there a more elegant way of building the method list?
Second, this code makes Perl spit out an error message:
----%<----
Can't use an undefined value as a subroutine reference
at /usr/lib/perl5/x86_64-linux-thread-multi/Class/MOP/Class.pm line
719.
---->%----
Thanks in advance for any hints!
You really don't want to do this in BUILD, that will result in the
modifiers being applied every time you build an instance.
As for how to be better approach this, personally I am not a fan of
such dynamism. For instance, what happens if you have to define some
special accessor for one of your attributes? That will then show up in
the method-list. You are also not accounting for any of the methods
which might be associated with attributes, such as builder or clearer
methods or any of the Moose::Meta::Attribute::Native delegators.
I suspect a better approach might be to use a parameterized role
(MooseX::Roles::Parameterized). You could force your class actually
specify the list of methods to be wrapped by the parameterized role.
This would still give you the genericity of the role based approach,
but it would impose the small "penalty" of making you being more
explicit about what methods to wrap (which IMO is a good thing).
- Stevan