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