On May 8, 2010, at 12:26 PM, Eric Veith1 wrote:
Stevan Little <[email protected]> wrote on 05/08/2010 04:25:41
PM:
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.

Thanks for the insight. You're right, I'd of course want to avoid both
pitfalls.>

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).

I already have some method attibutes around via MooseX::MethodAttributes, so I could make use of them in this case, too. Doesn't look so different
for me, what do you think?

I have a serious allergy to method attributes, I don't ever use them so I couldn't comment.

But the thing is, I still need some kind of wrapper that is automatically called whenever one of these "specially marked" methods are being called. I
currently solve it solely by allowing access only through a public
"execute" method that takes the method's name and its parameters als
argument, does some checking, perhaps forking if needed, reads the method attributes, and so on. My goal is to replace this explicit call with an implicit one, because I more or less force myself to document the fact that the right way is to call "$foo->execute('real_method_name', @parameters)" for every class that assumes the role. Using the BUILDer of the Role and the "around" modifier was my solution to it. Could you please provide me
with a more elegant one? :-)

Well, I am going to stick with my MooseX::Role::Parameterized suggestion since I really don't like to use method attributes. Here is an quick example of what that might look like (untested). Here is the role:

package My::Wrapper::Role;
use MooseX::Role::Parameterized;

parameter 'methods_to_wrap' => (
    isa      => 'ArrayRef[Str]',
    required => 1,
);

sub __execute { ... }

role {
    my $p = shift;

    foreach my $method ( @{ $p->methods_to_wrap }) {
        around $method => \&__execute;
    }
};


The class would then look like this:


package My::Class;
use Moose;

with 'My::Wrapper::Role' => {
    methods_to_wrap => [qw[
        foo
        bar
    ]]
};

sub foo { ... }
sub bar { ... }

This pretty much does what your original example did, but at the right compiler phases.

If you want to specialize the wrapping a little more you can simply add more parameters to the role and be more specific in the class. Something like this:


with 'My::Wrapper::Role' => {
    methods_to_wrap => [qw[ foo bar   ]],
    methods_to_fork => [qw[ baz gorch ]],
};

- Stevan


















Reply via email to