Created
February 7, 2012 05:27
-
-
Save jafingerhut/1757414 to your computer and use it in GitHub Desktop.
apropos2 and unresolve
This file contains 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
;; Example use of unresolve: | |
;; user=> (unresolve #'replace) | |
;; (replace clojure.core/replace) | |
;; user=> (use 'clojure.string) | |
;; WARNING: replace already refers to: #'clojure.core/replace in namespace: user, being replaced by: #'clojure.string/replace | |
;; WARNING: reverse already refers to: #'clojure.core/reverse in namespace: user, being replaced by: #'clojure.string/reverse | |
;; nil | |
;; user=> (unresolve #'replace) | |
;; (replace clojure.string/replace) | |
;; user=> (unresolve #'clojure.core/replace) | |
;; (clojure.core/replace) | |
(defn unresolve | |
"Given a var, return a sequence of all symbols that resolve to the | |
var from the current namespace *ns*." | |
[var] | |
(when-not (instance? clojure.lang.Var var) | |
(throw (Exception. (format "unresolve: first arg must be Var")))) | |
(let [home-ns (.ns var) | |
sym-name-str (second (re-find #"/(.*)$" (str var)))] | |
(sort-by | |
#(count (str %)) | |
(concat | |
;; The symbols in the current namespace that map to the var, if | |
;; any | |
(->> (ns-map *ns*) | |
(filter (fn [[k v]] (= var v))) | |
(map first)) | |
;; This is the "canonical" symbol that resolves to the var, with | |
;; full namespace/symbol-name | |
(list (symbol (str home-ns) sym-name-str)) | |
;; There might be one or more aliases for the symbol's home | |
;; namespace defined in the current namespace. | |
(->> (ns-aliases *ns*) | |
(filter (fn [[ns-alias ns]] (= ns home-ns))) | |
(map first) | |
(map (fn [ns-alias-symbol] | |
(symbol (str ns-alias-symbol) sym-name-str)))))))) | |
;; Example use of apropos2: | |
;; user=> (apropos "replace") | |
;; (postwalk-replace prewalk-replace replace) | |
;; user=> (doc postwalk-replace) | |
;; nil | |
;; user=> (apropos2 "replace") | |
;; (clojure.walk/prewalk-replace replace clojure.walk/postwalk-replace) | |
;; user=> (use 'clojure.walk) | |
;; nil | |
;; user=> (apropos2 "replace") | |
;; (prewalk-replace replace postwalk-replace) | |
(defn apropos2 | |
"Given a regular expression or stringable thing, calculate a | |
sequence of all symbols in all currently-loaded namespaces such that | |
it matches the str-or-pattern, with at most one such symbol per Var. | |
The sequence returned contains symbols that map to those Vars, and are | |
the shortest symbols that map to the Var, when qualified with the | |
namespace name or alias, if that qualification is necessary to name | |
the Var. Note that it is possible the symbol returned does not match | |
the str-or-pattern itself, e.g. if the symbol-to-var mapping was | |
created with :rename. | |
Searches through all non-Java symbols in the current namespace, but | |
only public symbols of other namespaces." | |
[str-or-pattern & opts] | |
(let [matches? (if (instance? java.util.regex.Pattern str-or-pattern) | |
#(re-find str-or-pattern (str %)) | |
#(.contains (str %) (str str-or-pattern)))] | |
(map #(first (unresolve %)) | |
(set | |
(mapcat (fn [ns] | |
(map second | |
(filter (fn [[s v]] (matches? s)) | |
(if (= ns *ns*) | |
(concat (ns-interns ns) (ns-refers ns)) | |
(ns-publics ns))))) | |
(all-ns)))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment