Search code examples
perlattributesmoose

How to efficiently apply a regex substitution on a Moose attribute?


I have a

package Test;
use Moose;
has 'attr' => ( is => 'rw', isa => 'Str' );

Inside a method I'd like to apply a s/pattern/string/g on the attribute. For reasons documented in Moose (basically to properly support polymorphism) I do not want to access the $self->{attr} directly, so a simple:

$self->{attr} =~ s/pattern/string/g;

is not an option. How can I do this efficiently in speed and little but clear code with Moose?

Options I came up with are:

1) Use a temporary variable, and the usual getter/setter method:

my $dummy = $self->attr;
$dummy =~ s/pattern/string/g;
$self->attr($dummy);

2) Using the attr getter/setter on the left hand side:

$self->attr($dummy) =~ s/pattern/string/g;

But this obviously throws an error

Can't modify non-lvalue subroutine call at Test.pm line 58, line 29

Is there a way to use Moose accessors as lvalue subs?

3) Use the String traits

Redefine the attribute:

has 'attr' => ( is => 'rw', isa => 'Str', traits  => ['String'],
                handles => { replace_attr => 'replace'}  );

Then in the method use:

$self->replace_attr('pattern', 'string');

However the docs explicitly say, there's no way to specify the /g flag.

Any elegant, simple, somewhat efficient method available out of the box?


Solution

  • I have used this approach in the past and I think it seems suitable to me for general use in terms of efficiency and cleanliness. It also works with the /g modifier.

    $self->attr( $self->attr =~ s/pattern/string/gr );
    

    I suspect that under the hood this is the same as your first example with the temporary variable, it is just hidden from us.

    Please note that the to use the /r modifier, which returns the result of the substitution without modifying the original, requires Perl 5.14+.