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~

Reply via email to