Created
April 17, 2010 23:18
-
-
Save tcrayford/369890 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(use 'clojure.contrib.seq-utils) | |
(use 'clojure.walk) | |
(import '(java.io File LineNumberReader InputStreamReader PushbackReader) | |
'(java.lang.reflect Modifier Method Constructor) | |
'(clojure.lang RT Compiler Compiler$C)) | |
;; Yoinked and modified from clojure.contrib.repl-utils. | |
;; Now takes a var instead of a sym in the current ns | |
(defn get-source-from-var | |
"Returns a string of the source code for the given symbol, if it can | |
find it. This requires that the symbol resolve to a Var defined in | |
a namespace for which the .clj is in the classpath. Returns nil if | |
it can't find the source. | |
Example: (get-source-from-var 'filter)" | |
[v] (when-let [filepath (:file (meta v))] | |
(when-let [strm (.getResourceAsStream (RT/baseLoader) filepath)] | |
(with-open [rdr (LineNumberReader. (InputStreamReader. strm))] | |
(dotimes [_ (dec (:line (meta v)))] (.readLine rdr)) | |
(let [text (StringBuilder.) | |
pbr (proxy [PushbackReader] [rdr] | |
(read [] (let [i (proxy-super read)] | |
(.append text (char i)) | |
i)))] | |
(read (PushbackReader. pbr)) | |
(str text)))))) | |
(defn recursive-contains? [coll obj] | |
"True if coll contains obj at some level of nesting" | |
(some #(= % true) | |
(flatten | |
(postwalk | |
(fn [node] | |
(if (= node obj) true node)) | |
coll)))) | |
(defn does-var-call-fn [var fn] | |
"Checks if a var calls a function named 'fn" | |
(if (get-source-from-var var) | |
(let [node (read-string (get-source-from-var var))] | |
(if (recursive-contains? node fn) | |
var | |
false)))) | |
;; This should check if the ns actually refers to the var | |
;; Currently it just looks for namespaces that refer to the correct | |
;; symbol, but not if that var is correct. | |
;; This is ok when there are low numbers of namespace conflicts | |
(defn does-ns-refer-to-var? [ns var] | |
(if (ns-resolve ns var) | |
true false)) | |
(defn who-calls [sym] | |
(filter | |
#(identity %) | |
(pmap #(does-var-call-fn % sym) | |
(flatten | |
(pmap vals | |
(pmap ns-interns | |
(filter #(does-ns-refer-to-var? % sym) | |
(all-ns)))))))) | |
(who-calls 'potential-ns) |
I'm embarrassed by this code now
recursive-contains is just
(defn recursive-contains? [coll obj]
(some #{obj} (tree-seq coll)))
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wow, that was quick. Great.
A few notes: (if pred true false) should be condensed to just pred. Also I feel like the (some #(= true %) [...] form could be cleaned up a bit. But if you want to submit it as a pull request or patch, I can clean up after I apply it. Could definitely be in its own namespace.
Thanks!