在Clojure中从命令行设置调试功能

时间:2014-02-28 12:03:58

标签: clojure

我有这样的命名空间:

(ns foo.core)

(def ^:dynamic *debug-fn*
  "A function taking arguments [bar baz]"
  nil)

(defn bar-info
  [bar _]
  (println bar))

(defn baz-info
  [_ baz]
  (println baz))

(defn do-stuff
  [bar baz]
  (when *debug-fn* (*debug-fn* bar baz)))

(defn -main
  [& {:keys [debug-fn]}]
  (binding [*debug-fn* (symbol debug-fn)]  ;; THIS WON'T WORK!
    (do-stuff 27 42)))

我想要做的是允许从命令行指定调试功能,如:lein run bar-infolein run baz-info

我不确定如何将指定的字符串作为命令行参数并将其转换为要绑定的名称空间限定函数。我需要一个宏来做这个吗?

3 个答案:

答案 0 :(得分:6)

使用ns-resolve,您需要指定定义函数的命名空间。

user=> (defn f [n] (* n n n))
#'user/f
user=> ((ns-resolve *ns* (symbol "f")) 10)
1000

答案 1 :(得分:2)

使用alter-var-root

user=> (doc alter-var-root)
-------------------------
clojure.core/alter-var-root
([v f & args])
  Atomically alters the root binding of var v by applying f to its
  current value plus any args
nil
user=> (alter-var-root #'*debug-fn* (fn [v] (fn [x] (println x) x)))
#<user$eval171$fn__172$fn__173 user$eval171$fn__172$fn__173@7c93d88e>
user=> (*debug-fn* 1)
1
1

答案 2 :(得分:0)

虽然我接受了Guillermo's answer above,但我认为添加我最终使用的解决方案可能也很有用:

(def debug-fns
  {:bar-info (fn [bar _] (println bar))
   :baz-info (fn [_ baz] (println baz))

(def active-debug-fns (atom []))

(defn activate-debug-fn!
  [fn-key]
  (let [f (debug-fns fn-key)]
    (if f
      (swap! active-debug-fns conj f)
      (warn (str "Debug function " fn-key " not found! Available functions are: "
                 (join " " (map name (keys debug-fns))))))))

(defn debug-fn-keys
  [args]
  (if (args "--debug")
    (split (or (args "--debug") "") #",")
    []))

(defn do-stuff
  [bar baz]
  (doseq [f @active-debug-fns]
    (f bar baz)))

(defn -main
  [& args]
  (let [args (apply hash-map args)]
    (doseq [f (debug-fn-keys args)]
      (activate-debug-fn! (keyword k)))
    (do-stuff 27 42)))

所以现在你可以说lein run --debug bar-info之类的东西来获取关于条形的信息,或lein run --debug bar,baz来获取关于条形和条纹的信息。

任何使这更加惯用的建议都会被愉快地接受和编辑。:)

相关问题