2011-10-07 9 views
9

Sto codificando qualcosa come REPL Server. Richiesta dagli utenti valuta in tale funzione:clojure - codice di eval in diversi namespace

(defn execute [request] 
    (str (try 
      (eval (read-string request)) 
     (catch Exception e (.getLocalizedMessage e))))) 

Ogni client in thread separato. Ma hanno lo stesso spazio dei nomi. Come posso eseguire il codice nello spazio dei nomi dinamico creato? Quindi, quando un nuovo client è connesso, voglio creare un nuovo spazio dei nomi ed eseguire lì il codice del ciclo di gestione dei client. O forse è possibile eseguire (eval ..) in altri namespace?

Grazie.

upd.
Risolto!

eseguire la funzione:

(defn execute 
    "evaluates s-forms" 
    ([request] (execute request *ns*)) 
    ([request user-ns] 
    (str 
     (try 
     (binding [*ns* user-ns] (eval (read-string request))) 
     (catch Exception e (.getLocalizedMessage e)))))) 

Ogni cliente riceve il proprio spazio dei nomi:

(defn generate-ns 
    "generates ns for client connection" 
    [] (let [user-ns (create-ns (symbol (str "client-" (Math/abs (.nextInt random)))))] 
    (execute (str "(clojure.core/refer 'clojure.core)") user-ns) 
    user-ns))` 

(defn delete-ns 
    "deletes ns after client disconnected" 
    [user-ns] (remove-ns (symbol (ns-name user-ns)))) 

offtop: Come rendere gli offset in frammenti di codice su Begin della linea?

+1

Se il problema è stato risolto con la risposta di qualcuno, contrassegnare la risposta come corretta. Se ti è venuta in mente questa risposta, scrivila come risposta nella sezione delle risposte (non come parte della domanda) e contrassegnala come corretta. Per quanto riguarda la formattazione dei blocchi di codice, è sufficiente scriverli come paragrafi separati rientrati da quattro spazi (ho modificato la tua domanda per correggere la formattazione). Benvenuto su Stackoverflow! –

+0

La politica ufficiale è che dovresti pubblicare una risposta alla tua domanda in questa situazione. Tuttavia, ad alcune persone non piace questa pratica e le risposte negative di OP. Quindi l'azione ufficialmente corretta è rischiosa. – Mars

risposta

15

Risolto:

(binding [*ns* user-ns] (eval (read-string request))) 
1

Modifica dello spazio dei nomi significa che si dovrà reinizializzare tutti gli alias, o consultare anche clojure.core cose con un nome completo:

user=> (defn alien-eval [ns str] 
     (let [cur *ns*] 
      (try ; needed to prevent failures in the eval code from skipping ns rollback 
      (in-ns ns) 
      (eval (read-string str)) 
      (finally 
       (in-ns (ns-name cur)) 
       (remove-ns ns))))) ; cleanup, skip if you reuse the alien ns 
#'user/alien-eval 
user=> (alien-eval 'alien "(clojure.core/println clojure.core/*ns*)") ; note the FQN 
#<Namespace alien> ; the effect of println 
nil    ; the return value of alien-eval 
+0

funziona in REPL, ma non funziona in runtime: 'Impossibile cambiare/stabilire il binding root di: * ns * con set' –

0

È possibile scrivere una macro che simula

(defmacro my-eval [s] `~(read-string s)) 

Funziona meglio che eval perché il simbolo la risoluzione di s si verifica nel contesto che chiama my-eval. Grazie a @Matthias Benkard per i chiarimenti.

1

(simbolo (str "client-" (Matematica/abs (.nextInt casuale)))

volevo solo aggiungere che questo potrebbe essere realizzato con

(gensym "client-") 

(volevo commentare, ma diventa nostro che non posso :))

Problemi correlati