clojure - eval код в другом пространстве имен - PullRequest
9 голосов
/ 07 октября 2011

Я кодирую что-то вроде сервера REPL.Запрос от пользователей оценивается в такой функции:

(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: Как сделать смещения в фрагментах кода в начале строки?

Ответы [ 4 ]

15 голосов
/ 08 октября 2011

Решено:

(binding [*ns* user-ns] (eval (read-string request)))
1 голос
/ 11 апреля 2013

(символ (str "client-" (Math / abs (.nextInt random)))

Я просто хотел добавить, что этого можно достичь с помощью

(gensym "client-")

(Я хотел бы прокомментировать, но получается, что я не могу :))

1 голос
/ 07 октября 2011

Изменение пространства имен означает, что вам придется повторно инициализировать все псевдонимы или ссылаться на даже 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 голосов
/ 07 февраля 2012

Вы можете написать макрос, который имитирует

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

Это работает лучше, чем eval, потому что разрешение символов s происходит в контексте, который вызывает my-eval. Спасибо @Matthias Benkard за разъяснения.

...