無需宏:
(defn trace-ns
"ns should be a namespace object or a symbol."
[ns]
(doseq [s (keys (ns-interns ns))
:let [v (ns-resolve ns s)]
:when (and (ifn? @v) (-> v meta :macro not))]
(intern ns
(with-meta s {:traced true :untraced @v})
(let [f @v] (fn [& args]
(clojure.contrib.trace/trace (str "entering: " s))
(apply f args))))))
(defn untrace-ns [ns]
(doseq [s (keys (ns-interns ns))
:let [v (ns-resolve ns s)]
:when (:traced (meta v))]
(alter-meta! (intern ns s (:untraced (meta v)))
#(dissoc % :traced :untraced))))
...或者類似的東西。最有可能的額外要求是使用filter
,以便不在ifn?
s上調用trace
。 更新:在解決方案中編輯(也處理宏)。更新2:修復了一些重大錯誤。更新4:添加untrace功能。
更新3:這裏有一個例子從我REPL:
user> (ns foo)
nil
foo> (defn foo [x] x)
#'foo/foo
foo> (defmacro bar [x] x)
#'foo/bar
foo> (ns user)
nil
user> (trace-ns 'foo)
nil
user> (foo/foo :foo)
TRACE: "entering: foo"
:foo
user> (foo/bar :foo)
:foo
user> (untrace-ns 'foo)
nil
user> (foo/foo :foo)
:foo
你根本真棒!你能解釋ns解析部分嗎? – 2010-07-27 18:43:02
:-)'ns-resolve'需要一個命名空間或命名空間命名符號和一個符號,並試圖找到一個由(第二個)符號給出的名稱下的給定命名空間中的Var。這裏重要的一點是(1)可以改變Var的根綁定(有很多方法可以做到,但是intern在這裏特別方便,因爲它也處理額外的元數據; trace-ns (2)可以改變Var的元數據(所以'untraced-ns'是可能的)。 – 2010-07-27 18:51:24
請參閱http://gist.github.com/492764獲取上述最新版本(以更有用的文檔字符串爲特色!)。 – 2010-07-27 19:56:53