Search code examples
perlmoose

In Moose, how do I modify an attribute any time it is set?


If you have an attribute that needs to be modified any time it is set, is there a slick way of doing this short of writing the accessor yourself and mucking around directly with the content of $self, as done in this example?

package Foo;
use Moose;

has 'bar' => (
    isa => 'Str',
    reader => 'get_bar',
);

sub set_bar {
    my ($self, $bar) = @_;
    $self->{bar} = "modified: $bar";
}

I considered trigger, but it seemed to require the same approach.

Is working directly with the hash reference in $self considered bad practice in Moose, or am I worrying about a non-issue?


Solution

  • I'm not sure what kind of modification you need, but you might be able to achieve what you need by using type coercion:

    package Foo;
    use Moose;
    
    use Moose::Util::TypeConstraints;
    
    subtype 'ModStr' 
        => as 'Str'
        => where { /^modified: /};
    
    coerce 'ModStr'
        => from 'Str'
        => via { "modified: $_" };
    
    has 'bar' => ( 
        isa => 'ModStr', 
        is  => 'rw', 
        coerce => 1,
    );
    

    If you use this approach, not all values will be modified. Anything that passes validation as a ModStr will be used directly:

    my $f = Foo->new();
    $f->bar('modified: bar');  # Set without modification
    

    This weakness could be OK or it could make this approach unusable. In the right circumstances, it might even be an advantage.