2013-06-02 25 views
5

Clojure oferuje dobrą interakcję Java. Jednak naprawdę chcę mieć to:Punkty początkowe do regularnych serwletów kodujących moje DSL

(servlet IndexServlet 
    (service[parmas] ....) 
    (do-post[params] ....) 
    (do-get [params] ....)) 

(servlet-filter SecurityFilter 
    (do-filter [params] ....)) 

Przypuszczam, że to, co się nazywa DSL, w świecie Lispa odbywa się za pośrednictwem makr.

Nie wiem, jak/gdzie zacząć. refiy i extends form mają zdecydowanie ważną rolę tutaj, ale nie wiem, jak to by pasowało do makr.

Jak rozpocząć pracę z tym DSL?
Urywek, porady i wskazówki są naprawdę cenne.

Odpowiedz

3

Możesz zajrzeć do adaptera Ring's Jetty na przykładzie wdrożenia serwletu w Clojure. Źródło jest dostępne here (link do źródła wydania 1.1). W szczególności pierwsza funkcja zdefiniowana w tej przestrzeni nazw, proxy-handler zwraca procedurę obsługi na podstawie abstrakcyjnej klasy udostępnionej przez Jetty.

Jeśli zdecydujesz się wdrożyć podobne podejście (opierając serwlet na klasie Java zapewniającej pewną gotową metodę implikuje), musisz użyć proxy; jeśli potrzebujesz tylko implementować interfejsy (bez podklasy), prawdopodobnie będziesz potrzebował reify zamiast tego. To, czy makra będą użyteczne, zależy od tego, które części implementacji okażą się poprawne; Adapter Rdzeń pierścienia nie skorzystałby z użycia makr, ale możesz (na przykład, jeśli chcesz rozszerzyć klasę/interfejs na implementację do argumentu, co wydaje się wskazywać pytanie).

W każdym przypadku dowolna funkcja wybrana do wdrożenia będzie musiała być częścią interfejsu lub protokołu. Tak, wdrażanie javax.servlet.Servlet plus dodatkowe działanie foo może wyglądać następująco:

(import (javax.servlet Servlet ServletRequest ServletResponse)) 

(defprotocol PFoo 
    (foo [this x y z])) 

(reify 
    Servlet 
    (service [this ^ServletRequest req ^ServletResponse res] 
    ...) 
    ;; other Servlet methods here... 
    PFoo 
    (foo [this x y z] 
    ...)) 

Można następnie owinąć to w makro dostarczyć dowolny cukier syntaktyczny. Zauważ, że reify rzeczywistości nie dbają o sposób, w którym przeplatać interfejsu/nazwy i definicje protokołów metoda wewnątrz swojego ciała, więc można mieć makra emitować

(reify 
    Servlet PFoo ... ; other interfaces & protocols 
    (service [...] ...) 
    (foo [...] ...) 
    ;; other methods 
) 

jeśli jest to bardziej wygodne.

Szkic makro przy nazwę interfejsu serwletów wdrożyć (przypuszczalnie rozszerzenie javax.servlet.Servlet) oraz wtryskiwanie protokół z dodatkowymi sposobami:

(defprotocol PFancyServlet 
    (do-get [this ...]) 
    (do-post [this ...])) 

(defmacro servlet [servlet-iface & meths] 
    `(reify ~servlet-iface PFancyServlet 
     [email protected])) 

meths powinien zawierać do-get i do-post jak servlet-iface metody; możesz dodać argumentację, aby upewnić się, że tak właśnie jest. Przykładowa rozmowa:

(servlet SomeServletInterface 
    (service [this ...] ...) 
    ;; ... 
    (do-get [this ...] ...) 
    (do-post [this ...] ...)) 
+0

Awesome! Jak mogę mieć funkcje bez "tego" jako pierwszego parametru? (servlet IndexServlet (do-get [request response])) – Chiron

+0

Może zajść potrzeba użycia 'this' w ciałach metod (jeśli metody wywołują się nawzajem, powiedzmy). To powiedziawszy, twoje makro może wstępnie przetwarzać 'mets' w arbitralny sposób, w szczególności dodając' this' z powrotem, jeśli pominiesz go w składni na poziomie użytkownika: '(niech [[nazwa-meta-params & body] meth] \' (~ nazwa-mety ~ (vec (cons 'this params)) ~ @ body)) 'lub coś podobnego. To spowodowałoby rozszerzenie, w którym "ten" byłby dostępny jako "magiczny parametr" w każdej z ciał metod. Lub możesz użyć '(gensym" this __ ")' zamiast ''this' w rozszerzeniu, aby" ukryć "' this', jeśli tego chcesz. –

+0

Również 'proxy' czyni już' ten' niejawnym (zobacz '(doc proxy)'), podobnie jak 'definterface',' gen-interface' i 'gen-class'; 'reify',' deftype', 'defrecord',' defprotocol' nie. (Odp: 'klasa genów', to deklaracje metod w" klasie genów ", które pomijają" to ", funkcje implementujące muszą to wyraźnie zaznaczyć). –