Yeah this is a common problem when you need to extend a set of
interdependent classes, the only good solution that I have found for
it is to use some kind of Inversion of Control pattern/framework.
However a full IOC framework like IOC.pm or Bread::Board tend to be a
heavyweight solution and most often not appropriate for small stuff.
Since this is CPAN module and you don't control the internals, one
possible solution might be to use an 'after' method modifier to
"upgrade" your Module::B instance to MooseX::Module::B. It is
hackish, but it will get the job done and (hopefully) keep the hack
isolated.
And remember that you can pass in more than one method name to
'after' as well so you can do:
after 'create_b', 'build_me_some_b', 'gotta_have_that_b' => sub {
my $self = shift;
$self->{b} = $self->upgrade_b_to_mxb($self->{b});
};
sub upgrade_b_to_mxb {
my ($self, $old_b) = @_;
return MooseX::Module::B->new(__instance__ => $old_b);
}
And you can put this 'after' modifier and the upgrader in a Role that
can be re-applied to many classes if need be. The goal here being
that you only have to write your ugly hack in one place. Hehe, ...
Moose helps you write better bad code too :)
The other (better) solution is to fix the upstream module so that it
uses methods to create the related objects and then you can easily
override those objects.
- Stevan
On Jul 2, 2008, at 11:28 PM, benh wrote:
I'm with Chris, this is more of a design issue. What is the common
part between A and B that could not be pulled out to a role?
On 7/2/08, Chris Prather <[EMAIL PROTECTED]> wrote:
On Wed, 2 Jul 2008 17:22:44 -0700, Christopher Brown wrote:
Hi All,
What is the best way to moosify an existing CPAN class and all
the classes
called by this class. I know that *extends* works:
package MooseX::Module::A;
use Moose;
extends 'Module::A';
package MooseX::Module::B;
use Moose;
extends 'Module::B';
sub my_b_extension {
...
}
But how do you extend both modules when Module::A relies on and
calls
Module::B? Such as.
package Module::A;.
sub create_b {
my $self = shift;
$self->{b} = Module::B->new();
}
...
Now in:
package main;
use MooseX::Module::A;
use MooseX::Module::B;
my $a = Moose::X::Module::A->new(); # Cool
$a->create_b; # Cool
$a->{b}->my_b_extension(); # FAIL!
In this scenario, I will not see *my_b_extension*. In normal,
non-Moose
Perl, I would:
package Module::AX;
use *base* 'Module::A';
...
package Module::BX;
use *base* 'Module::B';
...
Well base.pm and moose play fairly nice together ... but I'm not sure
even base.pm would solve this ...
$self->{b} = Module::B->new(); # you hardcode the module name
here ...
nothing can save you now
you'd need to override the create_b method in MX::Module::A ...
which
you'd have to do in any perl code because you've hardcoded the
classname in the method. This isn't a Moose problem, this is a
crappy
design decision problem.
If you want to be able to subclass Module::B ... then create_b
either
needs to make the classname for B configurable (via a parameter
to the
method, or an attribute in A or something...) or you need to
override
it in your subclass of A to call the class you need ... (or you
override it with something configurable).
-Chris
--
benh~