Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Assigning to a ArrayRef accessor type

by tomred (Acolyte)
on Sep 21, 2020 at 14:51 UTC ( [id://11122001]=perlquestion: print w/replies, xml ) Need Help??

tomred has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
I am struggling to understand how I can assign to an ArrayRef accessor. I am trying to use Moo and Types::Standard for my class attributes. My efforts always produce a extra ArrayRef that is one level deeper than I need.
As far as I can tell, you have to assign a reference to the attribute once it's marked as a 'Ref' but in doing so I end up with an array reference inside an array reference. Perhaps I want a list type but I don't see one.

Code

#!perl use v5.22; use warnings; use Test::Deep; use Test::More; BEGIN { package MockObj; use Moo; use Types::Standard qw(ArrayRef Str); use namespace::autoclean; has 'files' => ( # `rpw` would be better as, in practice, # this is only used inside the class is => 'rw', isa => ArrayRef[Str], ); 1; }; my $mock = MockObj->new; my @list = ('string one', 'Different string', 'With feeling'); note explain \@list; $mock->files( \@list ); my @strings = $mock->files; note explain \@strings; cmp_deeply(\@strings, bag(@list)); done_testing;

Result

# [ # 'string one', # 'Different string', # 'With feeling' # ] # [ # [ # 'string one', # 'Different string', # 'With feeling' # ] # ] not ok 1 # Failed test at t/test-case.t line 31. # Comparing $data as a Bag # Missing: 'Different string', 'With feeling', 'string one' # Extra: 1 reference
Your enlighenment is much appreciated,

Replies are listed 'Best First'.
Re: Assigning to an ArrayRef accessor type
by Athanasius (Archbishop) on Sep 21, 2020 at 15:15 UTC

    Hello tomred, and congratulations on your first post!

    MockObj::files is not an array, it’s an array reference. So instead of assigning to an array variable:

    my @strings = $mock->files;

    you should assign to a scalar:

    my $strings = $mock->files; note explain $strings; cmp_deeply($strings, bag(@list));

    which gives the desired test result:

    1:14 >perl 2056_SoPW.pl # [ # 'string one', # 'Different string', # 'With feeling' # ] # [ # 'string one', # 'Different string', # 'With feeling' # ] ok 1 1..1 1:14 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      An alternative to this:

      my $strings = $mock->files;

      Would be this:

      my @strings = @{ $mock->files };

      Or if you've got a very recent version of Perl:

      my @strings = $mock->files->@*;

      Moose also has an optional feature where it can detect if an accessor is called in a list context and return a list instead of a reference, but Moo didn't implement that because it can get confusing to work with.

        Arrrh.

        Thank you

        Thanks you both. I should have spotted that.
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11122001]
Approved by Fletch
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-04-25 10:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found