2011-10-07 13 views
9

Estoy codificando algo así como el servidor REPL. La solicitud de los usuarios se evalúa en dicha función:clojure - código de evaluación en el espacio de nombres diferente

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

Cada cliente en una secuencia separada. Pero tienen el mismo espacio de nombres. ¿Cómo puedo ejecutar el código en el espacio de nombres creado dinámico? Entonces, cuando un nuevo cliente se conecta, quiero crear un nuevo espacio de nombres y ejecutar allí el código del bucle de manejo del cliente. ¿O tal vez es posible ejecutar (eval ..) en otro espacio de nombres?

Gracias.

upd.
¡Resuelto!

ejecutar la función:

(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)))))) 

Cada cliente recibe su propio espacio de nombres por:

(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: ¿Cómo hacer compensaciones en fragmentos de código de comenzar de la línea?

+1

Si su problema fue resuelto por la respuesta de alguien, por favor marque esa respuesta como correcta. Si surgió esta respuesta usted mismo, por favor anótelo como una respuesta en la sección de respuestas (no como parte de la pregunta) y márquelo correctamente. Con respecto al formateo de bloques de código, simplemente escríbalos como párrafos separados con sangría por cuatro espacios (edité tu pregunta para arreglar el formateo). Bienvenido a Stackoverflow! –

+0

La política oficial es que debe publicar una respuesta a su pregunta en esta situación. Sin embargo, a algunas personas no les gusta esa práctica y rechazan las respuestas de OP. Entonces, la acción correcta oficialmente es arriesgada. – Mars

Respuesta

15

Resuelto:

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

Cambio de espacio de nombres significa que tendrá que reinicializar todos los alias, o consulte incluso clojure.core cosas con un nombre 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

funciona en REPL, pero no funciona en tiempo de ejecución: 'No se puede cambiar/establecer el enlace de la raíz de: * ns * con el conjunto ' –

0

Se puede escribir una macro que imita a

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

Funciona mejor que eval porque el símbolo la resolución de s ocurre en el contexto que llama al my-eval. Gracias a @Matthias Benkard por las aclaraciones.

1

(símbolo (str "cliente-" (Matemáticas/abs (.nextInt al azar)))

sólo quería añadir que esto podría lograrse con

(gensym "client-") 

(Quería comentar, pero resulta que no podemos :))

Cuestiones relacionadas