Why doesn't Moose role application with method modifiers work in my code?
I have a Role and several classes that mix-in the role. The Role class loads all of the impleme开发者_开发知识库nting classes so that anything that imports Blah can use them without typing a lot of 'use' lines.
package Blah;
use Moose::Role;
use Blah::A;
use Blah::B;
(etc...)
requires '...';
requires 'foo';
around 'foo' => sub { ... }
A typical Blah subclass:
package Blah::A;
use Moose;
with 'Blah';
sub foo { ... }
__PACKAGE__->meta->make_immutable;
Since every subclass 'foo' method starts with the same bits of code, the role also implements these via a method modifier.
Problem is: Moose doesn't apply the method modifier to any of the Blah::* classes. This happens even if I remove the make_immutable call for the classes. I thought role application was done entirely at runtime, and so even though the Blah::* classes are loaded before Blah, the modifier should still be applied?
I'm looking for a fix, or an alternate way of doing things. At the moment Blah is essentially an abstract base class except for the method modifier, which is why I used roles to begin with - but maybe a class hierarchy would be better? Thanks in advance.
Your call order is a little odd -- why are you use
ing Blah::A from within the role that is then applied to Blah::A?
I would suggest pulling out these use
lines and moving them to where they are actually needed (in the caller(s)). Get the code working first, and after that, if you have lots of use
lines cluttering things up everywhere, you could move them off into an Includes file.
But no, in answer to your assumption -- role application is not done at runtime, but at whatever time the with
line is encountered. If you use
a module at compile-time, then that file is compiled immediately, and the with
line executed (which then forces the role to be compiled, and then it is run). You can of course apply a role at runtime as well (e.g. see apply_all_roles in Moose::Util), but that is not what is happening here.
I think you simply misunderstand the difference between file-inclusion, and role composition.
Under the hood, use
statements simply call require
and then the inferred Package's import()
statement and wrap all of this in a BEGIN {}
block.
It doesn't install the functions as meta-class methods with Class::MOP (CMOP). I'm not sure what the difference is between a declared method and an imported one, or how CMOP tells the difference but this works only because of the call to add_method
. I'd ask for more information from irc.perl.org/#moose, but I'm banned. Hopefully this example will tell you what you need, or give you more information to formulate a better question.
package Class;
use Moose;
use Carp qw(carp);
### You have to add the method onto the class.
Class->meta->add_method( 'carp' => \&carp );
around 'carp' => sub { warn "this won't trigger" };
package main;
my $c = Class->new;
$c->carp('foo');
If possible I'd rewrite those packages your use
ing into Moose friendly Roles, then just have the current role call the new roles using the with
statement. Roles will handle method modifiers around other role-provided methods.
精彩评论