Re: Subclassing non moose classes

[email protected] (Jesse Luehrs)
Newsgroups perl.moose
Message-ID <[email protected]>
On Wed, Mar 02, 2011 at 11:36:07AM -0600, Mark A. Stratman wrote:
> On Mar 2, 2011, at 9:23 AM, matthew couchman (JIC) wrote:
> > I'd like to subclass a non moose class Math::VectorReal so that I can do this
> 
> > But its not working, I guess because of the first caveat on the manual page that says that references must be the same between the moose class and the non-moose class.  I'm a bit lost to be honest, could someone point me in the right direction? > 
> The problem is that Math::VectorReal uses an arrayref for its internal structure. It does a bless([] ...), but MooseX::NonMoose likes hashrefs.
> I think MooseX::NonMoose::InsideOut should take care of it. Something like this:

Yes, MooseX::NonMoose::InsideOut is the right answer here.

> package BetterVector;
> use Moose;
> use MooseX::NonMoose::InsideOut;  # NOTE - different module
> use namespace::autoclean;
> extends 'Math::VectorReal';
> 
> has [qw(x y z)] => (
>     isa => 'Num',
>     is => 'ro',  # NOTE - 'ro', not 'rw'.... more on this below
> );
> 
> sub FOREIGNBUILDARGS {
>     my ($class, %vals) = @_;
>     return map { $vals{$_} } qw(x y z); # NOTE - Math::VR requires args in a specific order, but WE shouldn't.
> }
> 
> no Moose;
> 
> package main;
> use Modern::Perl;
> my $v = BetterVector->new(x => 1, y => 2, z => 0.5);
> say $v->length;

But you don't want to do it this way, really... overriding the
attributes that already exist in Math::VectorReal isn't useful, and will
cause issues (as mentioned). Something like this should be sufficient:

    package BetterVector;
    use Moose;
    use MooseX::NonMoose::InsideOut;
    use namespace::autoclean;
    extends 'Math::VectorReal';

    # don't declare x, y, and z as moose attrs
    # (but you can declare other attrs if you want)

    # and make sure moose doesn't see them when they come into the
    # constructor
    around BUILDARGS => sub {
        my $orig = shift;
        my $class = shift;
        my $args = $class->$orig(@_);
        delete $args->{$_} for qw(x y z);
        $args;
    };

    # and then this is the same
    sub FOREIGNBUILDARGS {
        my $class = shift;
        my %vals = @_;
        return map { $vals{$_} } qw(x y z);
    }

    no Moose;
    1;

This way, Math::VectorReal is still handling the things it knows about
on its own, and you can add new attributes beyond those if you want in a
way that doesn't interfere with anything it's doing.

-doy
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.