2009-11-09 89 views
5

我正在使用Moose,我需要在我的项目中包装方法调用。重要的是我的包装代码是最外面的修饰符。Perl Moose方法修饰符:在'之前'和'之后'调用'around'

use Moose::Util; 
Moose::Util::apply_all_roles(__PACKAGE__->meta, ('App:Roles::CustomRole')); 
__PACKAGE__->meta->make_immutable; 

这使我有理由相信我的我的角色的修饰符:我到目前为止所做的就是把我的方法修饰符在穆斯的角色,然后在我的课像这样结束时应用该角色最后定义,因此给我“之前”和“之后”的正确行为。 (角色中的“之前”和“之后”被称为非常先和非常后)。

我原本以为这样就足够了,但我现在真的需要用类似的方法来包装方法。 Class :: MOP是Moose的基础,它首先应用“around”修饰符,因此它们在“之前”之前和之后“之后”被调用。

更多的细节,这里是我的修饰符的当前调用顺序:

CUSTOM ROLE before 
    before 2 
     before 1 
      CUSTOM ROLE around 
       around 
        method 
       around 
      CUSTOM ROLE around 
     after 1 
    after 2 
CUSTOM ROLE AFTER 

我真正需要的是这样的:

CUSTOM ROLE before 
    CUSTOM ROLE around 
     before 2 
      before 1 
       around 
        method 
       around 
      after 1 
     after 2 
    CUSTOM ROLE around 
CUSTOM ROLE AFTER 

如何让我的“左右”修改任何想法在我想要的地方应用/调用?我知道我可以做一些符号表黑客行为(就像Class :: MOP已经在做的那样),但是我真的不想。

+1

我同意以下的Ether的问题,为什么你使用'Moose :: Util :: apply_all_roles'而不是'with'? – perigrin 2009-11-09 20:40:12

+0

我希望我的角色中的“之前”和“之后”修饰符与其他可能存在于该类中的修饰符相比,首先运行或最后运行。稍后应用角色定义修饰符,然后修饰符会先运行(用于之前)和最后(用于之后)。 – 2009-11-09 21:57:39

+0

@perigrin我终于明白了你和Ether的问题。我不需要像我想象的那样将apply_all_roles应用于角色。对于Moose,我还是一个新手,并且想到了需要“手动”应用这个角色的想法。我真正需要做的只是在文件末尾(在其他修饰符之后)使用“with”,而不是开头。 – 2009-11-10 15:40:22

回答

4

最简单的解决方案是让CUSTOM ROLE定义一个方法,该方法调用main方法然后将其包装。

role MyRole { 
    required 'wrapped_method'; 
    method custom_role_base_wrapper { $self->wrapped_method(@_) } 

    around custom_role_base_wrapper { ... } 
    before custom_role_base_wrapper { ... } 
} 

您遇到的问题是,你想拥有的绕到东西其他不是方法的自定义角色。这不是它设计的目的。除了像你所建议的那样编写类似的符号表hackery(可能你可能会争论Moose中的一个人将Class :: MOP中的API暴露出来以帮助实现此目标),但我能想到的唯一的其他解决方案就是上面的那个。

如果你不想要custom_role_base_wrapper将添加额外的调用堆栈帧,你应该看看Yuval的Sub::Call::Tail或使用goto来操纵调用堆栈。

+0

我结束了自定义包装的想法。它给了我需要的灵活性,谢谢。 – 2009-11-24 16:23:42

3

我是相当新的驼鹿,但是你为什么这样做:

use Moose::Util; 
Moose::Util::apply_all_roles(__PACKAGE__->meta, ('App:Roles::CustomRole')); 

而不是简单呢?

with 'App:Roles::CustomRole'; 

关于你的问题,这是一个黑客攻击的一位,但你可以分割你的around方法为beforeafter方法和类定义的末尾应用中的作用(故在您需要的顺序应用)?如果绝对必要,您可以使用私有属性来保存两种方法之间的状态。

+1

问题是''之前'和'之后'都不能让你(干净地)以'around'的方式改变返回语义。如果这些语义很重要,那就搞定了。如果他们不是,为什么你用'around'开始? – perigrin 2009-11-09 20:38:52

+0

我手动应用它的原因是修改器按照它们定义的顺序添加(然后运行)。一般来说,你不关心订单修饰符的运行。但是,就我而言,我希望我的角色的修饰成为之前和之后的第一个。 如果使用“with”语法来应用角色,则首先定义其修饰符,以便它们将作为“之前”和“之后”的最内层运行。通过在最后手动应用角色,它们是最后定义的,因此在我希望它们运行时运行。 – 2009-11-09 21:51:36

+0

@Matt:这确实似乎是Moose的一个缺点。也许'after'语义应该允许改变返回值为'around',或者'before','around'和'after'方法的顺序应该被修改,所以它们都是相对于彼此的LIFO,而是而不仅仅是对自己(如果这是有道理的)。 – Ether 2009-11-10 00:34:50

相关问题