Quello che ho capito dal discorso di Stuart è qualcosa di simile:
(ns state.core)
(defn create-user-module [] (atom []))
(defn add-user [module user]
(swap! module conj user))
(defn get-users [module]
@module)
Ora non c'è stato globale nel vostro "core", come le funzioni che manipolano lo Stato si aspettano di ottenere come parametro. Ciò consente un facile test in quanto è possibile creare una nuova istanza del "modulo utente" per ogni test. Inoltre, i client di questo modulo non dovrebbero preoccuparsi di ciò che ottengono nella funzione create-user-module, dovrebbero semplicemente passarlo in giro senza controllarlo, in questo modo è possibile modificare l'implementazione del modulo utente ogni volta che lo si desidera. Stuart parla anche della creazione di protocolli per quei moduli se avete intenzione di avere più di un'implementazione.
Cercando di rispondere alla tua domanda, un anello adattatore è solo una funzione di 1 param, e compojure è solo una libreria di routing, così si potrebbe creare una web-app utilizzando chiusure come:
(ns state.web
(:use compojure.core)
(:require [state.core :as core]))
(defn web-module [user-module]
(routes
(GET "/all" [] (core/get-users user-module))))
Ora può chiamare il modulo web per creare una webapp, passando come parametro le dipendenze necessarie. Naturalmente è ancora bisogno di qualcuno per creare la web app con l'utente-moduli corretti, in modo che solo bisogno di una funzione "principale" che fili tutto insieme:
(ns state.main
(:require state.core
state.web)
(:use ring.adapter.jetty))
(defn start []
(let [user-module (state.core/create-user-module)
web-module (state.web/web-module user-module)]
(run-jetty web-module {:port 3000 :join? false})))
(defn stop [app]
(.stop app))
start
saranno chiamati dal metodo di applicazione main
. Questo vuol dire che devi passare al plugin lein-run.
Ora, dato che stai chiedendo di init
(dal plugin lein ring presumo), suppongo che tu abbia intenzione di distribuire la tua webapp in un contenitore.Siccome il plugin anello Lein deve lavorare all'interno dei vincoli del Java Servlet fw e che il gestore finisce compilato per un servlet Java, il meglio che si può probabilmente fare è qualcosa di simile:
(ns state.web
(:use compojure.core)
(:require [state.core :as core]))
(def module-deps (atom {})
(defn init-app [] (swap! module-deps conj [:user-module (core/create-user-module)]))
(defroutes web-module []
(GET "/all" [] (core/get-users (:user-module @module-deps))))
Ciò significa ancora che il vostro core lo spazio dei nomi è facile da testare, ma hai ancora uno stato globale nel namespace web, ma penso che sia "correttamente" incapsulato e probabilmente è abbastanza buono se devi usare un contenitore java.
E questo è solo un altro argomento del motivo per cui le librerie sono "migliori" dei quadri :)
y! è un buon approccio. – hsestupin
@hsestupin: è una domanda o affermazione :) – Ankur
affermazione di c. Intendevo dire che ero totalmente d'accordo con quel tipo di approccio quando lo stato non poteva essere cambiato per riferimento diretto. – hsestupin