2009-11-09 13 views
5

Używam Łosia i potrzebuję zawijać wywołania metod w moim projekcie. Ważne jest, aby mój kod zawijania był najbardziej zewnętrznym modyfikatorem. Co zrobiłem do tej pory kładzie się moja metoda modyfikatory w Moose Role, a następnie zastosować tę rolę pod koniec mojej klasy jak ten:Modyfikatory Metody Perl Moose: wywoływanie "w pobliżu" przed "przed" i "po"

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

To pozwala mi być pewnym, że modyfikatory mojego moja rola są zdefiniowane jako ostatnie, dlatego daje mi prawidłowe zachowanie dla "przed" i "po". ("Przed" i "po" w roli są nazywane bardzo pierwsze i ostatnie).

Początkowo sądziłem, że to będzie wystarczające, ale teraz naprawdę muszę owijać metody w podobny sposób z "dookoła". Klasa :: MOP, na której zbudowany jest Moose, stosuje najpierw modyfikatory "dookoła", dlatego są one nazywane po "przed" i przed "po".

Aby uzyskać więcej szczegółów, tutaj jest obecny porządek powołanie moich modyfikatorów:

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

naprawdę muszę coś takiego:

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

jakieś pomysły w jaki sposób dostać moje „wokół” modyfikator być stosowane/wywoływane tam, gdzie chcę? Wiem, że mogłem zrobić hakowanie tablic symboli (jak robi to już klasa :: MOP), ale wolałbym nie.

+1

Zgadzam się z poniższym pytaniem Eteru, dlaczego używasz 'Łoś :: Util :: apply_all_roles' zamiast' with'? – perigrin

+0

Chciałam, aby modyfikatory "przed" i "po" w mojej roli były uruchamiane jako pierwsze lub ostatnie w porównaniu do innych modyfikatorów, które mogą istnieć już w klasie. Zastosowanie roli ręcznie definiuje modyfikatory później, a następnie modyfikatory są uruchamiane jako pierwsze (dla wcześniejszych) i ostatnie (dla późniejszych). –

+0

@perigrin W końcu zrozumiałem twoje i Ether'a pytanie. Nie muszę stosować roli z apply_all_roles, tak jak myślałem.Wciąż jestem nowicjuszem w Moose i odkładam słuchawkę na myśl o konieczności zastosowania roli "ręcznie". Wszystko, co naprawdę musiałem zrobić, to zastosować go z "z" na końcu pliku (po innych modyfikatorach), a nie na początku. –

Odpowiedz

4

Najprostszym rozwiązaniem jest ustawienie ROLI WŁASNE dla zdefiniowania metody, która wywołuje główną metodę, a następnie ją zawija.

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

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

Problem masz to, że starasz się mieć rola CUSTOM wokół oblewania czymś inne niż metody. Nie jest to tym, do czego jest przeznaczony. Poza pisaniem podobnych hackerów symboli, jak zasugerowałeś (prawdopodobnie mógłbyś sprzeciwić się któremuś z ludzi z Łosia, aby ujawnić API w klasie :: MOP, aby pomóc Ci tam dotrzeć), jedyne inne rozwiązanie, jakie mogę wymyślić, to ten powyżej.

Jeśli nie chcesz dodatkowej ramki stosu wywołań że custom_role_base_wrapper doda, należy spojrzeć na Yuval na Sub::Call::Tail lub używając goto manipulować stos wywołań.

+0

Skończyłem z myślą o niestandardowym opakowaniu. Dało mi to elastyczność, której potrzebowałem, dzięki. –

3

Jestem całkiem nowy, łosie, ale dlaczego to zrobić:

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

zamiast po prostu jest?

with 'App:Roles::CustomRole'; 

chodzi o twoje pytanie, to bit hack, ale można podzielić metody around do before i after metod i zastosować rolę pod koniec swojej definicji klasy (tak to jest stosowane w odpowiedniej kolejności)? Można użyć atrybutów prywatnych, aby zapisać stan między tymi dwoma metodami, jeśli jest to absolutnie konieczne.

+1

Problem polega na tym, że ani 'before' ani' after 'nie pozwalają (czysto) zmienić semantyki powrotu w sposób 'around'. Jeśli ta semantyka jest ważna, jesteś spieprzony. Jeśli tak nie jest, dlaczego używasz "wokół" na początek? – perigrin

+0

Powodem, dla którego stosuję go ręcznie jest to, że modyfikatory są dodawane (a następnie uruchamiane) w kolejności, w jakiej zostały zdefiniowane. Generalnie nie dbasz o uruchamianie modyfikatorów zamówień. Ale w moim przypadku chciałem, aby modyfikatory mojej roli były pierwszymi przed i po ostatnim. Jeśli używasz składni "z" do zastosowania ról, to najpierw zdefiniowane są jej modyfikatory, więc będą one uruchamiane jako najbardziej wewnętrzne "przed" i "po". Stosując rolę ręcznie na końcu, są one definiowane jako ostatnie i dlatego są uruchamiane, gdy chcę, aby były. –

+0

@Matt: to naprawdę wydaje się być wadą łosia. Być może semantyka "after" powinna umożliwiać zmianę wartości zwracanej, tak jak w przypadku 'around', lub też uporządkowanie metod' before', 'around' i' after' powinno zostać zmodyfikowane, aby wszystkie były LIFO względem siebie, a raczej niż tylko dla siebie (jeśli ma to sens). – Ether