Динамическое изменение методов в Moo с использованием опубликованного API Moo - PullRequest
0 голосов
/ 27 января 2019

Я пытаюсь придерживаться опубликованного API для динамического изменения методов в Moo и не нашел общего решения.

Прежде всего, немного кода:

package R1 {
    use Moo::Role;
    sub r1 { say __PACKAGE__ }
}

package C1 {
    use Moo;
    sub c1 { say __PACKAGE__ }
}

use Scalar::Util qw[ blessed ];
use Moo::Role ();

my $c = C1->new;
Moo::Role->apply_roles_to_object( $c, 'R1' );

Ролевое приложение иллюстрирует сбой в одном подходе.

Я пробовал два подхода.

Первый использует Class :: Method:: Модификаторы :

use Class::Method::Modifiers qw[ install_modifier ];
install_modifier( blessed( $c ), 
                  before => r1 =>
                  sub { say "BEFORE r1" }
                );
$c->r1;

и отлично работает:

% perl test.pl
BEFORE r1
R1

Код для внутренней Moo подпрограммы _install_modifier очень похож, но также выполняет дополнительные Moo специальные действия, так что этот подход не совсем эквивалентен.

Следующим подходом, который я попробовал, было непосредственное использование модификатора before, доступного для $c, и, таким образом, получение дополнительногоMoo специальный соус:

$c->can('before')->( r1 => sub { say "BEFORE r1" } );
$c->r1;

Но ...

% perl test.pl
The method 'r1' is not found in the inheritance hierarchy for class C1 at [...]/lib/site_perl/5.28.0/Class/Method/Modifiers.pm line 42.
        Class::Method::Modifiers::install_modifier("C1", "before", "r1") called at /[...]/lib/site_perl/5.28.0/Moo/_Utils.pm line 44
        Moo::_Utils::_install_modifier("C1", "before", "r1", CODE(0x5590bb800360)) called at [...]/lib/site_perl/5.28.0/Moo.pm line 84
        Moo::before("r1", CODE(0x5590bb800360)) called at test.pl line 25

Кажется, что модификаторы были сгенерированы для исходного класса C1 и не обновляются при R1Роль была применена.Следующий вопиющий хак «исправляет» это:

use Import::Into;
Moo->import::into( blessed $c );

$c->can('before')->( r1 => sub { say "BEFORE r1" } );
$c->r1;

, что приводит к:

% perl test.pl
BEFORE r1
R1

Итак, есть ли средства для достижения моей цели, используя только опубликованный Moo API?

Спасибо!

1 Ответ

0 голосов
/ 28 января 2019

Вы можете изменить методы, просто применив другую роль (это даже не обязательно Moo :: Role, если вы не имеете дело с атрибутами):

use Role::Tiny;
before r1 => sub { say "BEFORE r1" };

Просто убедитесь, что вы применили эту роль послетот, который составляет метод r1, или включает в роль фиктивный sub r1 {} (если он уже существует, он будет проигнорирован).

...