http://qs1969.pair.com?node_id=1054745

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

Hi monks. Been programming Perl for several years but just stumbled upon Moose. Anyway, I have a script (wget.pl) that instantiates an object of a class (Wget.pm) that uses a role (Transfer.pm). The problem is when I pass a hash ref to Wget->new(), it's not being received correctly. Here is the relevant parts of the code.

wget.pl

use Module::Load; my $class = 'DTF::Wget'; load $class; my $adapter = $class->new( 'input_line' => $input_line, 'dl_base_dir' +=> $dl_base_dir, 'report_file' => $report_file );

Wget.pm

package DTF::Wget; use strict; use warnings; use Moose; with 'DTF::Transfer';

Transfer.pm

package DTF::Transfer; use strict; use warnings; use Moose::Role; sub BUILD {} after 'BUILD' => sub { my $self = shift; die scalar(keys %$self); }

If all worked, the die statement in the role would print 3, since I passed 3 key-value pairs to the constructor of the class that uses the role. However, it prints 0. $self has absolutely nothing. I tried several variations of this, including moving the BUILD to Wget.pm. The result is always the same - $self is empty. I'm probably missing something obvious. Would appreciate any pointers.

Replies are listed 'Best First'.
Re: Moose::Role not getting params passed via ->new()
by tobyink (Canon) on Sep 19, 2013 at 06:26 UTC

    As derby said, $self will only be populated with keys corresponding to any attributes which have beeen defined for the class (including those defined in any roles the class does).

    You could define your role like this:

    package DTF::Transfer; use strict; use warnings; use Moose::Role; has [qw/ input_line dl_base_dir report_file /] => ( is => 'ro', ); sub BUILD {} after 'BUILD' => sub { my $self = shift; die scalar(keys %$self); };

    More importantly, you're making the mistake of treating $self like it's a hashref. It's not. (Actually it is by default, but you're supposed to pretend it's not. Let's pretend it's not...) Because it's not a hashref, keys %$self is meaningless. Instead you should access attributes via the accessors Moose generates:

    after 'BUILD' => sub { my $self = shift; printf STDERR "%s: %s\n", $_, $self->$_ for qw( input_line dl_base_dir report_file ); die; };

    Lastly, have you noticed that BUILD gets passed not one argument, but two?

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      Thanks guys! It felt like I was missing some fundamentals. I'm glad you set me on the right path.
Re: Moose::Role not getting params passed via ->new()
by derby (Abbot) on Sep 19, 2013 at 01:16 UTC

    Moose will only set arguments passed in via new if the corresponding attributes are declared in the class. Since DTF::Wget has no attributes, after the BUILD, the class is pretty much empty.

    -derby