如何捕获" =已经引用:#' clojure.core / =在命名空间中:用户,被替换为:#' user / ="在Clojure?

时间:2017-08-30 07:58:09

标签: clojure

在我的应用程序中,我向用户提供了一些界面,他们可以提供代码和应用程​​序评估沙箱中的代码(因此eval不允许)。如果用户覆盖,我需要抓住的东西一些内置函数,例如=

任何想法如何抓住并阻止那件事?(想法是他们不应该这样做)

代码:

(defn =
  []
  //some code)

WARNING: = already refers to: #'clojure.core/= in namespace: user, being replaced by: #'user/=

一个解决方案可能是:

我试图将警告消息设为String,但with-out-str功能无效。

(with-out-str
 (defn = [])) 
;=> ""

还写道with-err-str(改为 with-out-str 一点点)也不起作用。

(defmacro with-err-str
  [& body]
  `(let [s# (new java.io.StringWriter)]
     (binding [*err* s#]
       ~@body
       (str s#))))

(with-err-str
 (defn = [])) 
;=> ""

需要:"WARNING: = already refers to: #'clojure.core/= in namespace: user, being replaced by: #'user/="

3 个答案:

答案 0 :(得分:2)

使用eval

时,它会起作用
user=> (with-err-str (eval '(defn - [] 11)))
"WARNING: - already refers to: #'clojure.core/- in namespace: user, being replaced by: #'user/-\n"
user=> (re-seq #"WARNING" (with-err-str (eval '(defn / [] 11))))
("WARNING")

或者您可以在用户代码中重新定义defn宏,但没有什么能阻止他们使用其他clojure工具重新定义var:

user=> (defmacro defn-safe
  #_=>   [nam & decls]
  #_=>   (if (resolve (symbol "clojure.core" (name nam)))
  #_=>     (print "Whoops")
  #_=>     (list* `defn (with-meta nam (assoc (meta nam) :private true)) decls)))
#'user/defn-safe
user=> (defn-safe foo [x] (+ x 2))
#'user/foo
user=> (foo 22)
24
user=> (defn-safe = [a b] (- a b))
Whoopsnil
user=> 

另一个选择,也许你最好的选择是使用 https://github.com/clojure/tools.analyzer

答案 1 :(得分:2)

clojail处理此问题(以及许多其他事情)。如果你正在寻找沙盒Clojure,我建议你去看看。

答案 2 :(得分:2)

一种解决方案可能是这样的:

(def before (set (vals (ns-map *ns*))))

(defn = [])

(def after (set (vals (ns-map *ns*))))

(clojure.set/difference before after)

;=> #{#'clojure.core/=}