roadrider
roadrider

Reputation: 349

Perl Moose exception when invoking a reference to an attribute's writer method

I am trying to pass a reference to an attribute's writer method to another class method. The setter method is apparently invoked since the print statement is executed. However, the following error results:

Attribute (dir) is required, so cannot be set to undef at Test.pm line 51
Test::_validateDir('Test=HASH(0x2270be0)', 'CODE(0x22a90f8)') called at test.pm line 37
Test::BUILD('test_moose=HASH(0x2270be0)', 'HASH(0x1879728)') called at generated method (unknown origin) line 50
Test:new('Test', dir=>'my_bin') called at ./test_moose.pl line 26

Is there a reason why a reference to the generated writer method cannot be taken or is there a different or better way to do this in Moose?

Here's the code:

package Test;
use Moose;
use File::Spec;

has 'dir' => (is => 'ro', isa => 'Str', required => 1, writer '_set_dir',);

sub BUILD {
    my ($self, $hr) = @_;
    $self->_validateDir(\&_set_dir);
}

sub _validate_dir {
    my ($self, $setter) = @_;
    my $dir = File::Spec->rel2abs($self->dir, '/home/me');
    if (! -e $dir) {
       print "creating directory\n";
       #create directory
    }
    &$setter($dir);
}

Upvotes: 2

Views: 160

Answers (2)

cjm
cjm

Reputation: 62109

In Perl, a reference to a method does not include the associated object. When you call the reference, you must supply the object (or class, if it's a class method) as the first parameter.

&$setter($self, $dir);

Or, (equivalent when $setter is a code reference but more idiomatic):

$self->$setter($dir);

The reason you get "Attribute (dir) is required, so cannot be set to undef" is that Perl thinks that $dir is the object and the value is missing (and thus undef), and it apparently does that check before it notices that $dir isn't an object.

Upvotes: 1

zoul
zoul

Reputation: 104065

Is it right to call the setter as a regular sub? Shouldn't you pass $self as a first argument?

Upvotes: 2

Related Questions