开发者

clojure - eval code in different namespace

开发者 https://www.devze.com 2023-04-11 22:27 出处:网络
I\'m coding something like REPL Server. Request from users evaluates in such function: (defn execute [request]

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号