3

我试图坚持已发布的 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::Modifiers

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可用的修饰符 to $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来实现我的目标?

谢谢!

4

1 回答 1

1

您可以通过仅应用另一个角色来修改方法(它甚至不必是 Moo::Role,除非您正在处理属性):

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

只需确保在构成 r1 方法的角色之后应用此角色,或者sub r1 {}在角色中包含一个虚拟角色(如果已经存在,它将被忽略)。

于 2019-01-28T19:27:14.933 回答