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?
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+.
My Option (2) and this question provide the idea to use MooseX::LvalueAttributes:
package Test;
use Moose;
use MooseX::LvalueAttribute 'lvalue';
has 'attr' => ( is => 'rw', isa => 'Str', traits => [lvalue] );
This allows the straightforward syntax:
$self->attr($dummy) =~ s/pattern/string/g;
Internally this uses Variable::Magic and the perlsub lvalue feature, so there is a performance overhead to this approach which affects every access to the 'traited' attribute, not just the ones where it's used as a left hand side. Thanks to LeoNerd and ikegami for their correcting comments on my earlier statements.
Therefore, and confirmed by the module's documentation, Moose's type checking still works and triggers are fired.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With