分析clojure程序的依赖关系

时间:2014-01-13 10:03:56

标签: clojure

我有多个(3k +)脚本用clojure编写(每个脚本不依赖于任何其他脚本)。 这些脚本是用Clojure 1.2编写的,我想用旧的contrib库来分析它们。到目前为止,我只是为了clojure.contrib\.[0-9a-z\.\-]*的出现而简单地使用文件,但是我还希望从我的脚本中使用这些contrib库中找到特定的函数。

有没有比正则表达式更好的方法呢?

任何允许我解析字符串(包含Clojure程序)并轻松提取依赖项的clojure库?

1 个答案:

答案 0 :(得分:1)

使用core.analyze您可能会越来越近。

这是我的一个老例子,它将为您提供每个项目文件的所有顶级功能/元素。

您应该能够轻松修改parse-clojure-file函数来分析函数树以检查调用。

使用leiningen.core.projectanalyze.core设置依赖关系:

(ns dependencies.project
  (:require
   [leiningen.core.project :as project]
   [analyze.core :as analyze]
   [clojure.java.io])
  (:import
   (java.io PushbackReader)))

从磁盘读取文件并处理

(defn parse-clojure-file
  "Reads a clojure source file from disk
   and returns a sequence of hashes of
   first level objects
     {:type defn :name parse-clojure-file}
     {:type ns :name clandombg.project}
     ..."
  [file]
  (let [forms (analyze.core/forms-seq
               (java.io.PushbackReader. (clojure.java.io/reader file)))]
    (reduce (fn [file-obj form]
              (conj file-obj {:type (first form) :name (second form)}))
        [] forms)))

所有项目文件的树,返回的哈希映射由相对路径索引:

(defn traverse-source-tree
  "Traverses a source directory recursively and returns
  a collection of files keyed by relative-path and content
  the file first level objects"
  [directory]
  (let [files (file-seq (clojure.java.io/file directory))
        clj-files (filter #(re-matches #".+\.clj$|.+\.cljs$" (.getName %)) files)]
    (reduce (fn [project file]
              (let [relative-path (clojure.string/replace (.getPath file) directory "")]
                (assoc project
                  relative-path
                  (merge
                   (parse-clojure-file file)
                   {:relative-path relative-path}))))
            {} clj-files)))

切入点:

(defn parse-project
  "Reads a project file from disk and parses its source
  files, returns a clojure encoded string"
  [project-path]
  (let [project (project/read project-path)]
    (reduce #(assoc %1 %2 (traverse-source-tree %2))
                          {}
                          (:source-paths project))))

调用:

(parse-project "path/to/project.clj")