0

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 ?

katastrophos
  • 521
  • 4
  • 17

1 Answers1

1

It's more or less an implementation detail of MooseX::Role::Parameterized. When you use the method keyword, it does not create a method in the WordSizeRoleParameterized package. Similarly, has and other keywords you use in the role {} block do not affect the package which uses MooseX::Role::Parameterized. Such declarations affect only the anonymous role that the role {} block generates behind the scenes, and then the classes (or other roles) which consume that anonymous role.

The problem here is that \&_trigger_word_size is bound to the wrong package (WordSizeRoleParameterized when it should be bound to the anonymous role's package). Changing \&_trigger_word_size to sub { shift->_trigger_word_size(@_) } does the trick because it uses normal method resolution, so the method will be found in the right package (ClassWordSizeParameterized).

word : 'goodie', size: 6
WordsizeRoleParameterized::_trigger_word_size() called : size = 18 
word : 'Superdubadubaduuuh', size: 18

You're seeing $wordy_parameterized->_trigger_word_size because the method is copied into the class by way of the anonymous role, not by way of WordSizeRoleParameterized.

sartak
  • 653
  • 4
  • 17
  • Thanks a lot for this clarifying answer. Great. Isn't it worth to mention such things in the documentation ? – katastrophos Jun 08 '12 at 19:28
  • It isn't in the documentation yet because you're the first person I've seen trying to use `\&function` in MXRP. :) – sartak Jun 08 '12 at 19:31
  • I should ask Shawn M. Moore for putting it into the documentation :-))). I often use MXRP and I always have the feeling of a magic black box which I do not understand. A little bit of information in the documentation would be helpful for people like me. – katastrophos Jun 08 '12 at 19:43