Изменение префикса писателя, когда (is => "rwp")

Если я хочу изменить защищенный от записи атрибут т.е.

use Moops;

class foo {
  has attr => (is => "rwp");
}

нужно использовать _set_attr(),

Можно ли изменить это на _attr() без использования явного writer?

Пытался use MooseX::::AttributeShortcuts -writer_prefix => 'prefix'; но это не сработало.

1 ответ

Решение

Нет, вам нужно сделать это самостоятельно, установив writer,

TLDR: Внизу есть патч обезьяны, чтобы сделать это в любом случае.


Документы Moops говорят (подчеркивает мое):

Moops использует MooseX::MungeHas в ваших классах, так что ключевое слово has поддерживает некоторые специфичные для Moo функции, даже когда вы используете Moose или Mouse. В частности, он поддерживает is => 'rwp', is => 'lazy', builder => 1, clearer => 1, predicate => 1, а также trigger => 1,

Теперь давайте посмотрим на Му. в has В разделе документа написано (подчеркивает мой):

rwp расшифровывается как "защищено от чтения и записи" и генерирует читателя как ro, но также устанавливает писателя _set_${attribute_name} для атрибутов, которые предназначены для записи внутри класса, но только для чтения извне. Эта функция взята из MooseX::AttributeShortcuts.

Хорошо, перейдем к https://metacpan.org/pod/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, но я не знаю, как это заставить.


Вы действительно можете изменить это в Moo, подключившись к Method::Generate::Accessor Moo, используя Class::Method::Modifiers и добавив немного логики в around модификатор к generate_method, Это не работает, работает для Moops, пока в Moose не участвуют.

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.

Другие вопросы по тегам