我正在收集项目中的所有用户定义函数。作为测试成员身份的一种方式,我使用:
(defn get-var-namespace
[qualified-var]
{:pre [(var? qualified-var)]}
(-> qualified-var meta :ns))
(defn project-name
"returns a string representation of the root project name.
this is the same as the directory that the project is located in"
[]
(last (str/split (System/getProperty "user.dir") #"/")))
(defn get-project-namespaces
"return all namespaces defined within the project"
[]
(let [p-name (project-name)]
(filter (fn [x]
(let [n (first (str/split (str (ns-name x)) #"\."))]
(= n p-name))) (all-ns))))
(defn user-defined-var? [project-namespaces var]
(some #{(get-var-namespace var)} project-namespaces))
(defn namespace-deps
"returns a map whose keys are user defined functions and vals are sets of
user defined functions."
[project-namespaces ns]
(let [find-vars-in-expr
(fn [x] (let [nodes (ast/nodes x)
top-level (:var (first nodes))
non-recursive-deps (remove #{top-level}
(filter (partial var-has-user-ns project-namespaces)
(filter some? (map :var nodes))))]
{top-level (set non-recursive-deps)}))]
(dissoc (apply merge-with clojure.set/union
(map find-vars-in-expr (jvm/analyze-ns ns))) nil)))
作为例子
clj-smart-test.core> (clojure.pprint/pprint (namespace-deps (get-project-namespaces) *ns*))
{#'clj-smart-test.core/foo
#{#'clj-smart-test.baz/baz1 #'clj-smart-test.core/bar
#'clj-smart-test.foo/foo #'clj-smart-test.core/k},
#'clj-smart-test.core/get-project-namespaces
#{#'clj-smart-test.core/project-name},
#'clj-smart-test.core/project-name #{},
#'clj-smart-test.core/var-has-user-ns
#{#'clj-smart-test.core/get-var-namespace},
#'clj-smart-test.core/bar #{},
#'clj-smart-test.core/f #{},
#'clj-smart-test.core/get-var-namespace #{},
#'clj-smart-test.core/namespace-deps
#{#'clj-smart-test.core/var-has-user-ns},
#'clj-smart-test.core/k #{}}
nil
我是否需要了解任何角落案例?我知道用户可以在文件中创建一个任意名称空间,所以我不能总是假设创建项目的目录为例如lein new my-project
,它将my-project
作为根目录。此版本无法捕获defrecord
等。