In the follwoing code I tried to define a trigger for an attribute within a
parameterized role.
#!/usr/bin/env perl
package WordSizeRoleParameterized;
use MooseX::Role::Parameterized;
# a parameterized role with a trigger for an attribute
# does not work
role {
has 'word' => ( is => 'rw', trigger => \&_trigger_word_size,);
has 'word_size' => ( is => 'ro', writer => '_set_word_size', );
method '_trigger_word_size' => sub {
my $self = shift;
my $size;
if ( $self->word ) { $size = split //, $self->word; }
else { $size = 0; }
print "WordsizeRoleParameterized::_trigger_word_size() called : size = $size \n";
$self->_set_word_size($size);
};
};
1;
package WordSizeRole;
use Moose::Role;
# a plain role with a trigger for an attribute
# works as expected
has 'word' => ( is => 'rw', trigger => \&_trigger_word_size,);
has 'word_size' => ( is => 'ro', writer => '_set_word_size', );
sub _trigger_word_size {
my $self = shift;
my $size;
if ( $self->word ) { $size = split //, $self->word;}
else { $size = 0;}
$self->_set_word_size($size);
}
1;
package ClassWordSizeParameterized;
use Moose;
with 'WordSizeRoleParameterized';
1;
package ClassWordSize;
use Moose;
with 'WordSizeRole';
1;
#------------
package main;
#------------
use strict;
use warnings;
# no error
my $wordy = ClassWordSize->new({'word' => 'goodie'});
print "word : '", $wordy->word, "', size: ", $wordy->word_size, "\n";
# but using the paramaeterized role ...
my $wordy_parameterized = ClassWordSizeParameterized->new();
# will cause an error if calling $wordy_parameterized->word('Superdubadubaduuuh'));
#
# Undefined subroutine &WordSizeRoleParameterized::_trigger_word_size called at accessor
# ClassWordSizeParameterized::word (defined at roleTrigger.pl line 8) line 7.
$wordy_parameterized->word('Superdubadubaduuuh');
print "word : '", $wordy_parameterized->word, "', size: ", $wordy_parameterized->word_size, "\n";
Calling $wordy_parameterized->word(‘Superdubadubaduuuh’), which should fire the trigger
routine results in the error :
Undefined subroutine &WordSizeRoleParameterized::_trigger_word_size called
Interstingly the method WordSizeRoleParameterized::_trigger_word_size exists (you can call $wordy_parameterized->_trigger_word_size();), but it is not fired as trigger routine for the attribute. The documentation of MooseX::Role::Parameterized does not say anything about it.
Is it not allowed or simgply impossible by some implementation details of MooseX::Role::Parameterized ?
It’s more or less an implementation detail of
MooseX::Role::Parameterized. When you use themethodkeyword, it does not create a method in theWordSizeRoleParameterizedpackage. Similarly,hasand other keywords you use in therole {}block do not affect the package which usesMooseX::Role::Parameterized. Such declarations affect only the anonymous role that therole {}block generates behind the scenes, and then the classes (or other roles) which consume that anonymous role.The problem here is that
\&_trigger_word_sizeis bound to the wrong package (WordSizeRoleParameterizedwhen it should be bound to the anonymous role’s package). Changing\&_trigger_word_sizetosub { shift->_trigger_word_size(@_) }does the trick because it uses normal method resolution, so the method will be found in the right package (ClassWordSizeParameterized).You’re seeing
$wordy_parameterized->_trigger_word_sizebecause the method is copied into the class by way of the anonymous role, not by way ofWordSizeRoleParameterized.