0

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.

4

1 回答 1

4

,您需要自己通过设置writer.

TLDR:无论如何,底部是一个猴子补丁。


Moops文档说(强调我的):

Moops 在您的类中使用 MooseX::MungeHas,因此 has 关键字支持一些Moo 特定的功能,即使您使用的是 Moose 或 Mouse。具体来说,它支持is => 'rwp', is => 'lazy', builder => 1, clearer => 1, predicate => 1, 和trigger => 1.

现在让我们去看看Moo。在has文档的部分中,它说(强调我的):

rwp代表“读写保护”并生成类似的读取器ro,但还将 writer 设置为_set_${attribute_name}用于从类内部写入但从外部只读的属性。此功能来自 MooseX::AttributeShortcuts。

好的,继续MooseX::AttributeShortcuts

指定 is => 'rwp' 将导致设置以下选项:

is     => 'ro'
writer => "_set_$name"

然而,这正是它受到启发的地方。它实际上是在 Moo 中的Method::Generate::Accessor 1中实现的。

  } elsif ($is eq 'rwp') {
    $spec->{reader} = $name unless exists $spec->{reader};
    $spec->{writer} = "_set_${name}" unless exists $spec->{writer};
  } elsif ($is ne 'bare') {

更重要的是,这也不是在 Moops 中完成的。事实上,这发生在MooseX::MungeHas中,Moops 使用它,但前提是调用者不是 Moo:

            push @code, '  if ($_{is} eq q(rwp)) {';
            push @code, '    $_{is}     = "ro";';
            push @code, '    $_{writer} = "_set_$_" unless exists($_{writer});';
            push @code, '  }';

看起来很清楚。它在生成的代码中。如果仅使用 Moo,以下解决方案可能会起作用,但我不知道如何强制。


您确实可以通过使用 Class::Method::Modifiers 连接到 Moo 的 Method::Generate::Accessor 并在修饰符中添加一些逻辑来更改Moo中的. 只要没有涉及驼鹿的东西,这对 Moops不起作用。aroundgenerate_method

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;

输出

Foo  {
    Parents       Moo::Object
    public methods (2) : attr, new
    private methods (1) : _explicitly_set_attr
    internals: {
        attr   1
    }
}

1)我发现使用grep.cpan.me

于 2015-09-24T14:37:50.703 回答