I'm coding something like REPL Server. Request from users evaluates in such function:
(defn execute [request]
(str (try
(eval (read-string request))
(catch Exception e (.getLocalizedMessage e)))))
Each client in separate thread. But they have the same namespace. How can I run code in dynamic created namespace ? So when new client connected, I want to create new namespace and to run client handling loop code there. Or maybe it's possible to run (eval ..)
in other namespace ?
Thanks.
upd.
Solved!Execute function:
(defn execute
"evaluates s-forms"
([request] (execute request *ns*))
([request user-ns]
(str
(try
(binding [*ns* user-ns] (eval (read-string request)))
(catch Excepti开发者_StackOverflow中文版on e (.getLocalizedMessage e))))))
Each client gets it's own namespace by:
(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: How to make offsets in code snippets on begin of line ?
Solved:
(binding [*ns* user-ns] (eval (read-string request)))
(symbol (str "client-" (Math/abs (.nextInt random)))
I just wanted to add, that this could be achieved with
(gensym "client-")
(I wanted to comment, but it turns our that I can't :))
Changing namespace means that you will have to reinitialize all the aliases, or refer to even clojure.core
stuff with a fully qualified name:
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
You can write a macro that mimics
(defmacro my-eval [s] `~(read-string s))
It works better that eval because the symbol resolution of s occurs in the context that calls my-eval
. Thanks to @Matthias Benkard for the clarifications.
精彩评论