Here is a sample class to be used to illustrate the possible solutions and show the specific issues of the problem:
use 5.10.1; use utf8; package C; # main class with user-facing API use Moose; use MooseX::Method::Signatures; method foo (Str $x) { say "Called original foo($x)."; } method build_c2 { return C::C2->new; } has c2 => ( is => 'rw', handles => [ 'bar' ], builder => 'build_c2', lazy => 1 ); method build_c3 { return C::C3->new; } has c3 => ( is => 'rw', handles => [ 'baz' ], builder => 'build_c3', lazy => 1 ); # ================== package C::C2; # a helper class use Moose; use MooseX::Method::Signatures; method bar (Str $x) { say "Called original bar($x)."; } # ================== package C::C3; # a helper class use Moose; use MooseX::Method::Signatures; method baz (Str $x) { say "Called original baz($x)."; } # ================== package main; my $c= C->new; $c->foo (1); $c->bar (2); $c->baz (3);
Now, lets say we have extensions to C. In order to work, an extension needs to hook the methods foo, bar, and baz. By "hook" I mean it can override or use before/after/around modifiers of some kind.
As you can see, the methods are spread out over three different classes (albeit in a simple way). I've also made the attributes "rw' for ease in solving the problem.
Approach 1: run-time patching (traits)
A call to install an extension can apply a run-time role to $c, and also apply roles to $c->c2 and $c->c3. But that is evil "run time" patching...
Approach 2: apply before creating
Using the proper pedigreed MooseX::Traits and calling $c= C->with_traits(qw/ext1 ext2/)->new will apply the role ext1 and ext2 to C, and then call new. But that only fixes foo. How does it make C-with-roles apply the roles to C2 and C3 as well? For a single extension, it can override the builders. That's why this example shows two roles: they have to play together. Only after all roles are applied can it know what to create.
How would you do that?
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |