2009-11-09 9 views
5

Sto usando Moose e ho bisogno di racchiudere le chiamate di metodo nel mio progetto. È importante che il mio codice di wrapping sia il modificatore più esterno. Quello che ho fatto fino ad ora è messo il mio metodo modificatori in un ruolo di Moose e poi applicato quel ruolo alla fine della mia classe in questo modo:Modificatori del metodo Perl Moose: chiama "intorno" prima di "prima" e "dopo"

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

Questo mi permette di essere ragionevolmente sicuri che i modificatori di mio mio ruolo sono definito per ultimo, quindi dandomi il comportamento corretto per "prima" e "dopo". (Il "prima" e "dopo" nel ruolo sono chiamati molto prima e molto ultimo.)

Originariamente pensavo che sarebbe stato sufficiente, ma ora ho davvero bisogno di avvolgere i metodi in modo simile con "intorno". Class :: MOP, su cui Moose è costruito, applica i modificatori "intorno" molto prima, quindi vengono chiamati dopo "prima" e prima "dopo".

Per maggiori dettagli, qui è l'ordine di chiamata corrente dei miei modificatori:

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

ho davvero bisogno di qualcosa di simile:

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

Tutte le idee su come ottenere il mio modificatore "giro" da applicare/chiamato dove lo voglio? So che potrei fare un po 'di hacking sui tavoli dei simboli (come già accade in Class :: MOP), ma preferirei non farlo.

+1

Sono d'accordo con la seguente domanda di Ether, perché stai usando 'Moose :: Util :: apply_all_roles' piuttosto che' with'? – perigrin

+0

Volevo che i modificatori "prima" e "dopo" del mio ruolo venissero eseguiti molto prima o molto ultimi rispetto ad altri modificatori che potrebbero esistere già nella classe. Applicare il ruolo manualmente definisce i modificatori in seguito e quindi i modificatori vengono eseguiti prima (per prima) e ultimi (per dopo). –

+0

@perigrin Ho finalmente capito la tua e la domanda di Ether. Non ho bisogno di applicare il ruolo con apply_all_roles come pensavo.Sono ancora nuovo di Moose e sono rimasto bloccato dall'idea di dover applicare il ruolo "manualmente". Tutto quello che dovevo veramente fare era applicarlo con "con" alla fine del file (dopo gli altri modificatori) piuttosto che all'inizio. –

risposta

4

La soluzione più semplice consiste nell'avere che CUSTOM ROLE definisca un metodo che chiama il metodo principale e quindi lo avvolge.

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

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

Il problema che stai avendo è che si sta cercando di avere il ruolo personalizzato intorno involucro di qualcosa altro di un metodo. Quale non è quello che è stato progettato per fare. Oltre a scrivere hackery simile a una tabella di simboli come suggerito (probabilmente potresti obiettare a una delle persone di Moose di esporre un'API in Class :: MOP per ottenere l'accesso), l'unica altra soluzione che riesco a pensare è quella sopra.

Se non si desidera che il telaio in più stack di chiamate che custom_role_base_wrapper aggiungeranno, si dovrebbe guardare a Yuval del Sub::Call::Tail o utilizzando goto per manipolare lo stack di chiamate.

+0

Ho finito con l'idea del wrapper personalizzato. Mi ha dato la flessibilità di cui avevo bisogno, grazie. –

3

Sono abbastanza nuovo per Moose, ma perché lo fai:

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

piuttosto che semplicemente questo?

with 'App:Roles::CustomRole'; 

quanto riguarda la tua domanda, è un po 'di un hack, ma potrebbe dividere il metodo di around in before e after metodi e applicare il ruolo alla fine della definizione di classe (quindi è applicata nel vostro ordine desiderato)? È possibile utilizzare attributi privati ​​per salvare lo stato tra i due metodi se assolutamente necessario.

+1

Il problema è che né 'before' né' after' consentono di modificare (in modo pulito) la semantica di ritorno nel modo in cui 'around' lo farà. Se queste semantiche sono importanti, sei fregato. Se non lo sono, perché stai usando 'around' per cominciare? – perigrin

+0

Il motivo per cui lo applico manualmente è che i modificatori vengono aggiunti (e quindi eseguiti) nell'ordine in cui sono definiti. Generalmente non ti interessa che i modificatori degli ordini vengano eseguiti. Ma, nel mio caso, volevo che i modificatori del mio ruolo fossero i primissimi prima e molto dopo. Se si utilizza la sintassi "with" per applicare i ruoli, i relativi modificatori vengono definiti per primi e quindi verranno eseguiti come il più interno "prima" e "dopo". Applicando il ruolo manualmente alla fine sono definiti per ultimi e pertanto vengono eseguiti quando voglio che siano. –

+0

@Matt: sembra essere un difetto di Moose. Forse la semantica 'dopo' dovrebbe permettere di alterare il valore di ritorno come fa' around', o l'ordinamento dei metodi 'before',' around' e 'after' dovrebbero essere modificati in modo che siano tutti LIFO l'uno rispetto all'altro, piuttosto che solo a se stessi (se ciò ha senso). – Ether

Problemi correlati