【问题标题】:Applying Roles at Runtime from Method Modifier从方法修改器在运行时应用角色
【发布时间】:2013-10-22 23:15:36
【问题描述】:

我有一个提供方法修饰符的角色,如下所示:

package MyApp::Role::MenuExtensionRed;

use Moose::Role;
requires 'BuildMenu';

after 'BuildMenu' => sub {...};

由于其他地方的要求,我需要在运行时应用多个角色,如下所示:

package MyApp::MainMenu

before 'BuildMenu' => sub {
    my ( $self, $args ) = @_;

    my $roles  = $args->{menu_extensions};
    apply_all_roles($self,@$roles);
};

sub BuildMenu {...}

然而,'after' 方法修饰符永远不会被调用。显然我违反了一些规则,但我真的很想了解为什么这不起作用!

如果不是在“BuildMenu”之前应用角色,而是在 BUILD 方法中应用它们,它就可以工作。但不幸的是,当时我的 menu_extension 角色列表不可用,所以我必须等待。

任何替代解决方案将不胜感激!

EDIT 有趣的是,after 'BuildMenu' 被调用,但仅在随后调用 BuildMenu 时调用。所以一个方法的修饰符不能从它自己的另一个修饰符中改变。这是预期的行为吗?有没有办法在运行时添加到修饰符的“列表”中?

【问题讨论】:

  • 只是一个猜测,但它可能会在进入 sub 时检查之前/之后的包装器。

标签: perl moose


【解决方案1】:

这是其实施方式的副作用。

当你使用方法修饰符时,它们基本上用新方法替换现有方法,新方法包含对旧方法的引用。

所以当你看到

before foo => sub {
}

角色组合时发生的情况是:

my $orig = *package::foo;
*package::foo = sub {
     $beforetrigger->( @args );
     return $orig->( @args );
}

或多或少。

所以想象一下,你有 2 个 subs,“A”,在应用角色之前被调用的 BuildMenu 版本,以及“B”,在应用角色之后被调用的 BuildMenu 版本 应用角色。

那么会发生什么,你的调用顺序是这样的:

First Call ->
   A ->  
    before ->
         apply roles ->
           replace A with B
    <-- return from before
    A body   ->
    <-- return from A Body
Subsequent Call 
   B -> something

等等,所以,我认为您需要做的是让您的包装代码确认这一点,并在应用程序后传递控制权。

 around foo => sub { 
    my ( $orig, $self , @args ) = @_;
    # apply role to $self here
    # this gets the sub that will be resolved *after* the role is applied
    my $wrapped_sub = $self->can('foo');
    my $rval = $wrapped_sub->( $self, @args );      
    return $wrapped_sub->( $self, @args );
 }

请注意,该代码可能会有一个有趣的东西,其中 $wrapped_sub 是我刚刚编写的用于应用角色的子,......我还没有确切地知道那里会发生什么,但你可能需要设置一些条件以防止发生自调用子死循环。

但问题的要点基本上归结为这样一个事实,即您不能用新的子程序从子程序本身替换正在执行的子程序,并期望它自动菊花链,因为被替换的子程序是本质上并没有意识到它被替换了,并且因为“方法修饰符”相当于用链接到旧的新的替换 subs =)

【讨论】:

  • 感谢您的精彩回答!有道理!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-12
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多