Skip to content

Instantly share code, notes, and snippets.

@tcrayford
Created April 17, 2010 23:18
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 tcrayford/369890 to your computer and use it in GitHub Desktop.
Save tcrayford/369890 to your computer and use it in GitHub Desktop.
(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)
@technomancy
Copy link

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!

@tcrayford
Copy link
Author

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