Re: Extends type questions
[email protected] (Stevan Little)
| Newsgroups | perl.moose |
|---|---|
| Message-ID | <[email protected]> |
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~