Permalink
Browse files

Add unused-deps metric.

  • Loading branch information...
1 parent 8f19597 commit 505c3d41bcada993776f457475f37f4fa095a105 @pjstadig committed Oct 29, 2010
Showing with 112 additions and 1 deletion.
  1. +7 −0 TODO.org
  2. +2 −1 project.clj
  3. +10 −0 src/procrustes/code.clj
  4. +73 −0 src/procrustes/unused_deps.clj
  5. +20 −0 test/procrustes/test/unused_deps.clj
View
@@ -0,0 +1,7 @@
+* Possible Reports
+** Lines per file
+** Counts
+** Cyclomatic complexity
+** Dependent and dependency namespaces
+** Coverage?
+** Churn
View
@@ -3,4 +3,5 @@
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]]
:dev-dependencies [[swank-clojure "1.2.1"]
- [lein-difftest "1.3.1-SNAPSHOT"]])
+ [lein-difftest "1.3.1-SNAPSHOT"]]
+ :hooks [leiningen.hooks.difftest])
View
@@ -2,6 +2,16 @@
(:use [clojure.java.io :only [reader]])
(:import [java.io PushbackReader]))
+(defn- search-code* [code pred matches]
+ (if (pred code)
+ (conj matches code)
+ (if (and (coll? code)
+ (not (empty? code)))
+ (mapcat #(search-code* % pred matches) code))))
+
+(defn search-code [code pred]
+ (search-code* code pred []))
+
(defn find-ns-form [code]
(first (for [x code :when (= 'ns (first x))]
x)))
@@ -0,0 +1,73 @@
+(ns procrustes.unused-deps
+ (:use [procrustes.code :only [search-code find-ns-form but-ns-form
+ find-ns-name read-code]]))
+
+(defn- use? [code]
+ (and (list? code) (= :use (first code))))
+
+(defn- find-uses [code]
+ (mapcat rest (search-code (find-ns-form code) use?)))
+
+(defn- find-use-onlys [code]
+ (reduce merge {}
+ (map (fn [[ k _ v]] (hash-map k v))
+ (filter #(= :only (second %)) (find-uses code)))))
+
+(defn- used? [code sym]
+ (not (empty? (search-code code (partial = sym)))))
+
+(defn- remove-used-use-only-syms [code uses]
+ (reduce (fn [m [ns syms]]
+ (merge m {ns (remove (partial used? code) syms)}))
+ {}
+ uses))
+
+(defn- unused-uses [code]
+ (let [but-ns-form (but-ns-form code)]
+ (->> code
+ (find-use-onlys)
+ (remove-used-use-only-syms but-ns-form)
+ (remove (fn [[ns syms]]
+ (empty? syms)))
+ (mapcat (fn [[ns syms]]
+ (map (fn [sym]
+ (symbol (str ns "/" sym)))
+ syms))))))
+
+(defn- require? [code]
+ (and (list? code) (= :require (first code))))
+
+(defn- find-requires [code]
+ (mapcat rest (search-code (find-ns-form code) require?)))
+
+(defn- find-require-ases [code]
+ (reduce merge {}
+ (map (fn [[ k _ v]] (hash-map k v))
+ (filter #(= :as (second %)) (find-requires code)))))
+
+(defn- require-as-used? [code name]
+ (not (empty? (search-code code (fn [code]
+ (and (symbol? code)
+ (.startsWith (str code)
+ (str name "/"))))))))
+
+(defn- remove-used-require-ases [code requires]
+ (remove (fn [[ns name]]
+ (require-as-used? code name))
+ requires))
+
+(defn- unused-requires [code]
+ (let [but-ns-form (but-ns-form code)]
+ (->> code
+ (find-require-ases)
+ (remove-used-require-ases but-ns-form)
+ (map first))))
+
+(defn unused-deps [files]
+ (->> files
+ (map read-code)
+ (map (fn [code]
+ {(find-ns-name code)
+ (concat (unused-uses code)
+ (unused-requires code))}))
+ (reduce merge {})))
@@ -0,0 +1,20 @@
+(ns procrustes.test.unused-deps
+ (:use [procrustes.unused-deps] :reload)
+ (:use [clojure.test]
+ [procrustes.code :only [read-code]]))
+
+(deftest test-unused-deps
+ (is (= '{procrustes.example [clojure.java.io/file
+ clojure.contrib.monads]}
+ (unused-deps [(.getBytes "(ns procrustes.example
+ (:require [clojure.contrib.monads :as monad]
+ [clojure.contrib.ns-utils :as utils])
+ (:use [clojure.contrib.io :only [to-byte-array]]
+ [clojure.java.io :only [file]])
+ (:use [clojure.contrib.mock]))
+
+ (defn foo [x]
+ (utils/docs procrustes.example)
+ (to-byte-array))
+
+ (def- bar (delay (println \"Hello, World!\")))")]))))

0 comments on commit 505c3d4

Please sign in to comment.