Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Trouble coercing array elements

by docdurdee (Beadle)
on Jul 28, 2011 at 20:13 UTC ( #917344=perlquestion: print w/ replies, xml ) Need Help??
docdurdee has asked for the wisdom of the Perl Monks concerning the following question:

My second post today! inspired by the first. I would like to set up an attribute that is an array of arrayrefs with coercion of nonarrayrefs to array refs. eg.

[ 0, [ 0, 0, 0 ], [1,2,3] ] into [ [0], [ 0, 0, 0 ], [1,2,3] ]

also, I'd like to be able to push or set elements to the AoA with coercion as well. Here is my attempt:

{ package MyArray; use namespace::autoclean; use Moose::Util::TypeConstraints; use Moose; subtype 'myarray' => as 'ArrayRef[Num|Str|Int]'; coerce 'myarray' => from 'Num|Str|Int' => via {[$_]}; has 'myarray' => ( traits => ['Array'], is => 'rw', isa => 'myarray', default => sub { [] }, handles => { push => 'push', get => 'get', set => 'set', elements => 'elements', count => 'count', }, coerce => 1, ); __PACKAGE__->meta->make_immutable; } use Modern::Perl; my $a0 = MyArray->new( myarray => [ 0, [ 0, 0, 0 ], [1,2,3] ] ) ; use Data::Dumper; print Dumper $a0; $a0->set(1,'cat'); print Dumper $a0; $a0->push(2.0); print Dumper $a0;

Comment on Trouble coercing array elements
Select or Download Code
Re: Trouble coercing array elements
by ikegami (Pope) on Jul 28, 2011 at 21:46 UTC

    [ The parent was crossposted on StackOverflow. ]

    Building on my StackOverflow answer (where I didn't handle the trait), here's one that does:

    { package MyArray; use namespace::autoclean; use Moose; use Moose::Util::TypeConstraints; subtype 'MyArray::Ents::Level2' => as 'ArrayRef[Str|Num|Int]'; coerce 'MyArray::Ents::Level2' => from 'Str|Num|Int' => via { [ $_ ] }; my $level2_constraint = Moose::Util::TypeConstraints::find_type_constraint( 'MyArray::Ents::Level2'); # Doesn't work if I remove this?!? subtype 'MyArray::Ents' => as 'ArrayRef[MyArray::Ents::Level2]'; coerce 'ArrayRef[MyArray::Ents::Level2]' => from 'ArrayRef[MyArray::Ents::Level2|Str|Num|Int]' => via { [ map $level2_constraint->coerce($_), @$_ ] }; no Moose::Util::TypeConstraints; has 'myarray' => ( traits => ['Array'], is => 'rw', isa => 'ArrayRef[MyArray::Ents::Level2]', default => sub { [] }, handles => { push => 'push', get => 'get', set => 'set', elements => 'elements', count => 'count', }, coerce => 1, ); no Moose; __PACKAGE__->meta->make_immutable; } use Modern::Perl; use Data::Dumper qw( Dumper ); sub dump_it { local $Data::Dumper::Useqq = 1; local $Data::Dumper::Terse = 1; local $Data::Dumper::Indent = 0; print(Dumper($_[0]), "\n"); } my $a0 = MyArray->new( myarray => [ 0, [ 0, 0, 0 ], [1,2,3] ] ) ; dump_it($a0); $a0->set(1, 'cat'); dump_it($a0); $a0->push(2.0); dump_it($a0);
    bless( {"myarray" => [[0],[0,0,0],[1,2,3]]}, 'MyArray' ) bless( {"myarray" => [[0],["cat"],[1,2,3]]}, 'MyArray' ) bless( {"myarray" => [[0],["cat"],[1,2,3],[2]]}, 'MyArray' )

    Unfortunately, the following is not compatible with the trait:

    subtype 'MyArray::Ents::Level2' => as 'ArrayRef[Str|Num|Int]'; coerce 'MyArray::Ents::Level2' => from 'Str|Num|Int' => via { [ $_ ] }; my $level2_constraint = Moose::Util::TypeConstraints::find_type_constraint( 'MyArray::Ents::Level2'); subtype 'MyArray::Ents' => as 'ArrayRef[MyArray::Ents::Level2]'; coerce 'MyArray::Ents' => from 'ArrayRef[MyArray::Ents::Level2|Str|Num|Int]' => via { [ map $level2_constraint->coerce($_), @$_ ] }; ... isa => 'MyArray::Ents'

    It results in:

    Can't call method "is_a_type_of" on an undefined value at .../Moose/Me +ta/Attribute/Native/Trait.pm line 98

    I don't like adding coercions to global types, although ArrayRef[MyArray::Ents::Level2] is not as global as others.

Re: Trouble coercing array elements
by docdurdee (Beadle) on Jul 29, 2011 at 13:17 UTC

    Thanks ikegami! Playing around with your code helped me learn this cool stuff. I soon realized that I wanted to leave both ArrayRef and Objects alone. Starting from ikegami's code, I added this, cleaned it up (I hope) and am posting it here for reference. Perl rocks! Moose rocks!

    { package MyArray; use namespace::autoclean; use Moose; use Moose::Util::TypeConstraints; subtype 'ValueOrObject' => as 'Value|Object'; subtype 'Inside::MyArray::Ents' => as 'ArrayRef[Value]|Object'; coerce 'Inside::MyArray::Ents' => from 'Value' => via { return [ $_ ] }; my $level2_constraint = Moose::Util::TypeConstraints::find_type_constraint( 'Inside::MyArray::Ents'); subtype 'MyArray::Ents' => as 'ArrayRef[Inside::MyArray::Ents]'; coerce 'MyArray::Ents' => from 'ArrayRef[Inside::MyArray::Ents|ValueOrObject]' => via { [ map $level2_constraint->coerce($_), @$_ ] }; has 'myarray' => ( traits => ['Array'], is => 'rw', isa => 'MyArray::Ents', default => sub { [] }, handles => { push => 'push', pop => 'pop', get => 'get', set => 'set', elements => 'elements', count => 'count', }, coerce => 1, ); __PACKAGE__->meta->make_immutable; } use Modern::Perl; use Math::VectorReal; my $a0 = MyArray->new( myarray => [ 0, [ 0, 0, 0 ], [1,2,3] ] ) ; use Data::Dumper; print Dumper $a0; $a0->set(1,'cat'); print Dumper $a0; $a0->push('dog'); print Dumper $a0; $a0->push('1.0'); print Dumper $a0; my $vec1 = vector(1,2,3); $a0->push($vec1); print Dumper $a0; my $vec3 = $a0->get(5); my $vec2 = $a0->pop; print Dumper $vec2; print Dumper $vec3; say $vec1-$vec2; 1;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://917344]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (13)
As of 2014-08-28 14:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (263 votes), past polls