If I want to change write protected attribute ie.
use Moops;
class foo {
has attr => (is => "rwp");
}
one have to use _set_attr()
.
Is it possible to change that to _attr()
without using explicit writer
?
Tried use MooseX::::AttributeShortcuts -writer_prefix => 'prefix';
but it did not work.
No, you need to do that yourself by setting the writer
.
TLDR: At the bottom is a monkey-patch to do it anyway.
The Moops docs say (emphasys mine):
Moops uses MooseX::MungeHas in your classes so that the has keyword supports some Moo-specific features, even when you're using Moose or Mouse. Specifically, it supports
is => 'rwp'
,is => 'lazy'
,builder => 1
,clearer => 1
,predicate => 1
, andtrigger => 1
.
Now let's go look at Moo. In the has
section of the doc, it says (emphasys mine):
rwp
stands for "read-write protected" and generates a reader likero
, but also sets writer to_set_${attribute_name}
for attributes that are designed to be written from inside of the class, but read-only from outside. This feature comes from MooseX::AttributeShortcuts.
Ok, on to MooseX::AttributeShortcuts:
Specifying is => 'rwp' will cause the following options to be set:
is => 'ro' writer => "_set_$name"
However, this is just where it was inspired. It is actually implemented in Moo in Method::Generate::Accessor1.
} elsif ($is eq 'rwp') { $spec->{reader} = $name unless exists $spec->{reader}; $spec->{writer} = "_set_${name}" unless exists $spec->{writer}; } elsif ($is ne 'bare') {
And even more actually, that is also not where it is done in Moops. In fact, that happens in MooseX::MungeHas, which Moops uses, but only if the caller is not Moo:
push @code, ' if ($_{is} eq q(rwp)) {'; push @code, ' $_{is} = "ro";'; push @code, ' $_{writer} = "_set_$_" unless exists($_{writer});'; push @code, ' }';
Looks pretty clear. It's in generated code. The below solution might work if it uses only Moo, but I don't know how to force that.
You are indeed able to change that in Moo by hooking into Moo's Method::Generate::Accessor using Class::Method::Modifiers and adding a bit of logic in an around
modifier to generate_method
. This does not work works for Moops as long as there is no Moose-stuff involved.
use Moops;
BEGIN {
require Method::Generate::Accessor; # so it's in %INC;
require Class::Method::Modifiers;
Class::Method::Modifiers::around( 'Method::Generate::Accessor::generate_method' => sub {
my $orig = shift;
# 0 1 2 3 4
# my ($self, $into, $name, $spec, $quote_opts) = @_;
if ($_[3]->{is} eq 'rwp') {
$_[3]->{writer} = "_explicitly_set_$_[2]" unless exists $_[3]->{reader};
}
$orig->(@_);
});
}
class Foo {
has attr => ( is => "rwp" );
}
use Data::Printer;
my $foo = Foo->new( attr => 1 );
p $foo;
Output:
Foo {
Parents Moo::Object
public methods (2) : attr, new
private methods (1) : _explicitly_set_attr
internals: {
attr 1
}
}
1) I found that using grep.cpan.me.