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





Reply via email to