我正在编写像REPL Server这样的代码。用户的请求评估此功能:
(defn execute [request]
(str (try
(eval (read-string request))
(catch Exception e (.getLocalizedMessage e)))))
每个客户端都在单独的线程中。但它们具有相同的命名空间。如何在动态创建的命名空间中运行代码?因此,当新客户端连接时,我想创建新的命名空间并在那里运行客户端处理循环代码。或者也许可以在其他命名空间中运行(eval ..)
?
感谢。
UPD。
解决!
执行功能:
(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))))))
每个客户端都通过以下方式获取自己的命名空间:
(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:如何在行开头的代码片段中进行偏移?
答案 0 :(得分:15)
解决:
(binding [*ns* user-ns] (eval (read-string request)))
答案 1 :(得分:1)
更改名称空间意味着您必须重新初始化所有别名,或者使用完全限定名称引用clojure.core
内容:
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
答案 2 :(得分:1)
(符号(str“client-”(Math / abs(.nextInt random)))
我只想补充一点,这可以用
来实现(gensym "client-")
(我想发表评论,但它转变为我不能:))
答案 3 :(得分:0)
您可以编写一个模仿
的宏(defmacro my-eval [s] `~(read-string s))
它比eval效果更好,因为s的符号解析发生在调用my-eval
的上下文中。感谢@Matthias Benkard的澄清。