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

Reply via email to