2011-10-07 50 views
9

我编码的东西像REPL服务器。来自用户的请求评估中这样的功能:clojure - 在不同命名空间的eval代码

(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:如何使偏移的代码片断开始上线的?

+1

如果您的问题已被某人的答案解决,请将该答案标记为正确。如果您自己想出了这个答案,请在答案部分(不是问题的一部分)将答案写下来,并将其标记为正确。关于代码块的格式,只需将它们作为单独的段落缩进四个空格(我编辑了您的问题以修复格式)。欢迎来到Stackoverflow! –

+0

官方政策是你应该在这种情况下发布你的问题的答案。但是,有些人不喜欢这种做法,并且OP会减少答案。因此,正式的正确行动是有风险的。 – Mars

回答

15

解决:

(binding [*ns* user-ns] (eval (read-string request))) 
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 
+0

它在REPL中起作用,但它在运行时不起作用:'不能使用set'更改/建立* ns *的根绑定。 –

0

你可以写一个宏模仿

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

它更好地工作,因为符号s的解析发生在调用my-eval的上下文中。感谢@Matthias Benkard的澄清。

1

(符号(STR “客户机”(数学/ ABS(.nextInt随机)))

我只是想补充一点,这可能是与

(gensym "client-") 

实现(我想评论,但它变成我们不能:))