Skip to content

Instantly share code, notes, and snippets.

@hiredman
Created September 14, 2009 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hiredman/186432 to your computer and use it in GitHub Desktop.
Save hiredman/186432 to your computer and use it in GitHub Desktop.
(ns hiredman.deps)
(defn ffile [file]
(if (string? file)
(java.io.File. file)
file))
(defn read-ns [file]
(with-open [f (-> file ffile java.io.FileReader.
java.io.PushbackReader.)]
(binding [*in* f]
(read))))
(read-ns "ring/src/ring/example/hello_world.clj")
(def x *1)
(defn get-required [ns-form]
(set
(mapcat
(fn [x]
(if (list? x)
(map #(symbol (str (name (first x)) "." (name %))) (rest x))
(list x)))
(map #(if (vector? %) (first %) %) (mapcat rest (filter #(and (or (vector? %) (list? %)) (= :require (first %))) ns-form))))))
(defn get-used [ns-form]
(-> ns-form
((partial filter #(and (coll? %) (= :use (first %)))))
((partial map rest))
((partial apply concat))
((partial mapcat
(fn [x]
(if (coll? x)
(map #(symbol (str (name (first x)) "." (name %))) (rest x))
[x]))))))
(defn get-import [ns-form]
(-> ns-form
((partial filter #(and (coll? %) (= :import (first %)))))
((partial map rest))
((partial apply concat))
((partial mapcat
(fn [x]
(if (coll? x)
(map #(symbol (str (name (first x)) "." (name %))) (rest x))
[x]))))))
(get-import (read-ns "ring/src/ring/example/hello_world.clj"))
(get-import (read-ns "clojurebot/hiredman/clojurebot/core.clj"))
(defn parse [ns-form]
{:name (second ns-form)
:clojure-depends (concat (get-required ns-form)
(get-used ns-form))
:java-depends (get-import ns-form)})
(defn all-clojure-files [root]
(let [root (ffile root)]
(if (.isDirectory root)
(mapcat all-clojure-files (.listFiles root
(proxy [java.io.FilenameFilter] []
(accept [dir name]
(or (.endsWith name ".clj")
(.isDirectory (java.io.File. dir name)))))))
[root])))
(defn parse-directory [dir]
(reduce #(assoc % (:name %2) (dissoc %2 :name)) {} (map (comp parse read-ns) (all-clojure-files dir))))
(defn restructure [files]
(reduce
(fn [map- dep]
(-> map- (update-in [:java] #(into % (:java-depends (second dep))))
(update-in [:clojure] #(into % (:clojure-depends (second dep))))
(update-in [:edges]
#(into %
(map (partial vector (first dep))
(concat (:java-depends (second dep))
(:clojure-depends (second dep))))))))
{:java #{} :clojure #{} :edges #{}}
files))
(-> "clojurebot/" parse-directory
restructure
(safe-name-and-label :java)
(safe-name-and-label :clojure)
edges
dot
((fn [out]
(binding [*out* (-> "deps.dot" java.io.File. java.io.FileWriter.)]
(println out)))))
(defn dot [x]
(format "digraph simple_hierarchy {\n graph [rankdir = \"LR\"];\n %s subgraph cluster_clojure {\nlabel=\"clojure\";\ncolor=blue;\n%s} subgraph cluster_java {\nlabel=\"java\";\ncolor=red;\n%s}}" (:edges x) (:clojure x) (:java x)))
(defn safe-name-and-label [structure tag]
(update-in structure [tag]
#(reduce str (map
(fn [x]
(doto (str (safe-name x) "[label=\"" x "\"];\n") prn)) %))))
(defn safe-name [string]
(str (.replaceAll (str string) "(\\.|-|\\$)" "_")))
(defn edges [structure]
(update-in structure [:edges]
(fn [x]
(reduce str (map #(format "%s->%s;\n" (safe-name (first %)) (safe-name (second %))) x)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment