2009-11-09 8 views
5

Estoy usando Moose y necesito envolver llamadas a métodos en mi proyecto. Es importante que mi código de envoltura sea el modificador más externo. Lo que he hecho hasta ahora es poner mi método modificadores en un papel de alces y luego aplicar ese papel al final de mi clase como esta:Modificadores del método Perl Moose: Llamar 'alrededor' antes de 'antes' y 'después'

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

Esto me permite estar razonablemente seguros de que los modificadores de mi mi papel son Definido por último, por lo tanto, me da el comportamiento correcto para "antes" y "después". (El "antes" y el "después" en el rol se llaman primero y el último.)

Originalmente pensé que esto sería suficiente, pero ahora realmente necesito ajustar los métodos de forma similar con "alrededor". Class :: MOP, en el que se basa Moose, aplica modificadores de "alrededor" primero, por lo tanto se llaman después de "antes" y antes de "después".

Para más detalles, aquí está el orden de llamada actual de mis modificadores:

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

que realmente necesitan algo como esto:

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

¿Alguna idea sobre cómo conseguir mi modificador "alrededor" para ser aplicado/llamado donde quiero? Sé que podría hacer algo de hacking de tablas de símbolos (como Class :: MOP ya está haciendo) pero preferiría no hacerlo.

+1

Acepto la siguiente pregunta de Ether, ¿por qué estás usando 'Moose :: Util :: apply_all_roles' en lugar de' with'? – perigrin

+0

Quería que los modificadores 'antes' y 'después' de mi función se ejecutaran primero o en el último lugar en comparación con otros modificadores que pudieran existir en la clase. Al aplicar el rol manualmente, se definen los modificadores más adelante y luego los modificadores se ejecutan primero (para antes) y último (para después). –

+0

@perigrin Finalmente entendí tu pregunta y la de Ether. No necesito aplicar el rol con apply_all_roles como pensaba.Todavía soy nuevo para Moose y me obsesioné con la idea de tener que aplicar el rol "manualmente". Todo lo que realmente necesitaba hacer era aplicarlo con "con" al final del archivo (después de los otros modificadores) en lugar de al principio. –

Respuesta

4

La solución más simple es hacer que CUSTOM ROLE defina un método que llame al método principal y luego ajuste eso.

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

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

El problema que tiene es que usted está tratando de tener la función personalizada en torno envoltura algo otra que un método. Que no es para lo que está diseñado. Aparte de escribir hackers de tablas de símbolos similares a los que sugirió (probablemente podría argumentar que una de las personas de Moose expone una API en Class :: MOP para ayudar a conseguirlo), la única otra solución en la que puedo pensar es la anterior.

Si no desea que el marco pila de llamadas adicional que se sumará custom_role_base_wrapper, usted debe buscar en Yuval del Sub::Call::Tailgoto o usar para manipular la pila de llamadas.

+0

Terminé yendo con la idea de envoltorio personalizado. Me dio la flexibilidad que necesitaba, gracias. –

3

Soy bastante nuevo a Moose, pero ¿por qué haces esto:

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

en lugar de simplemente esto?

with 'App:Roles::CustomRole'; 

cuanto a su pregunta, que es un poco de un truco, pero podría dividir su método around en before y after métodos y aplicar el papel al final de su definición de clase (por lo que se aplican en el orden que desee)? Puede usar atributos privados para guardar el estado entre los dos métodos si es absolutamente necesario.

+1

El problema es que ni 'before' ni' after' te permiten (limpiamente) alterar la semántica de retorno de la misma manera que 'around'. Si esta semántica es importante, estás jodido. Si no lo son, ¿por qué estás usando 'todo' para empezar? – perigrin

+0

La razón por la que lo aplico manualmente es porque los modificadores se agregan (y luego se ejecutan) en el orden en que se definen. Por lo general, no le importan los modificadores de pedido que se ejecutan. Pero, en mi caso, quería que los modificadores de mi rol fueran los primeros antes y el último después. Si usa la sintaxis "con" para aplicar los roles, sus modificadores se definen primero y por lo tanto se ejecutarán como el más interno "antes" y "después". Al aplicar la función manualmente al final, se definen al final y, por lo tanto, se ejecutan cuando yo quiero que lo sean. –

+0

@Matt: parece ser una deficiencia de Moose. Quizás la semántica 'después' debería permitir alterar el valor de retorno como' alrededor', o el orden de los métodos 'before',' around' y 'after' debería modificarse para que sean todos LIFO con respecto a cada uno, más bien que solo para ellos mismos (si eso tiene sentido). – Ether

Cuestiones relacionadas