diff options
author | Chouser <chouser@n01se.net> | 2010-10-22 07:57:10 -0400 |
---|---|---|
committer | Stuart Halloway <stu@thinkrelevance.com> | 2010-11-29 21:01:58 -0500 |
commit | 40da6266790a264ea6a13ee93ca38a0555718aa2 (patch) | |
tree | 7b14905b06d3f07effbed59f7259a3f111c6b6f9 | |
parent | c6e7e5765e4bd6624e87115819d384f4a755d700 (diff) |
Move doc and find-doc to repl, support docstrings for special ops. CLJ-454
Also add special ops and namespaces to what find-doc searches through.
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
-rw-r--r-- | src/clj/clojure/core.clj | 97 | ||||
-rw-r--r-- | src/clj/clojure/main.clj | 2 | ||||
-rw-r--r-- | src/clj/clojure/repl.clj | 115 |
3 files changed, 130 insertions, 84 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 1612e9ec..d27ba3fe 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3884,10 +3884,12 @@ (reduce1 process-entry [] bents)))) (defmacro let - "Evaluates the exprs in a lexical context in which the symbols in + "binding => binding-form init-expr + + Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein." - {:added "1.0"} + {:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]} [bindings & body] (assert-args let (vector? bindings) "a vector for its binding" @@ -3914,16 +3916,14 @@ ;redefine fn with destructuring and pre/post conditions (defmacro fn - "(fn name? [params* ] exprs*) - (fn name? ([params* ] exprs*)+) - - params => positional-params* , or positional-params* & next-param + "params => positional-params* , or positional-params* & next-param positional-param => binding-form next-param => binding-form name => symbol Defines a function" - {:added "1.0"} + {:added "1.0", :special-form true, + :forms '[(fn name? [params* ] exprs*) (fn name? ([params* ] exprs*)+)]} [& sigs] (let [name (if (symbol? (first sigs)) (first sigs) nil) sigs (if name (next sigs) sigs) @@ -3959,7 +3959,7 @@ "Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. Acts as a recur target." - {:added "1.0"} + {:added "1.0", :special-form true, :forms '[(loop [bindings*] exprs*)]} [bindings & body] (assert-args loop (vector? bindings) "a vector for its binding" @@ -4263,75 +4263,7 @@ [name & decls] (list* `defn (with-meta name (assoc (meta name) :private true)) decls)) -(defn print-doc [v] - (println "-------------------------") - (println (str (ns-name (:ns (meta v))) "/" (:name (meta v)))) - (prn (:arglists (meta v))) - (when (:macro (meta v)) - (println "Macro")) - (println " " (:doc (meta v)))) - -(defn find-doc - "Prints documentation for any var whose documentation or name - contains a match for re-string-or-pattern" - {:added "1.0"} - [re-string-or-pattern] - (let [re (re-pattern re-string-or-pattern)] - (doseq [ns (all-ns) - v (sort-by (comp :name meta) (vals (ns-interns ns))) - :when (and (:doc (meta v)) - (or (re-find (re-matcher re (:doc (meta v)))) - (re-find (re-matcher re (str (:name (meta v)))))))] - (print-doc v)))) - -(defn special-form-anchor - "Returns the anchor tag on http://clojure.org/special_forms for the - special form x, or nil" - {:added "1.0" - :static true} - [x] - (#{'. 'def 'do 'fn 'if 'let 'loop 'monitor-enter 'monitor-exit 'new - 'quote 'recur 'set! 'throw 'try 'var} x)) - -(defn syntax-symbol-anchor - "Returns the anchor tag on http://clojure.org/special_forms for the - special form that uses syntax symbol x, or nil" - {:added "1.0" - :static true} - [x] - ({'& 'fn 'catch 'try 'finally 'try} x)) - -(defn print-special-doc - [name type anchor] - (println "-------------------------") - (println name) - (println type) - (println (str " Please see http://clojure.org/special_forms#" anchor))) - -(defn print-namespace-doc - "Print the documentation string of a Namespace." - {:added "1.0"} - [nspace] - (println "-------------------------") - (println (str (ns-name nspace))) - (println " " (:doc (meta nspace)))) - -(defmacro doc - "Prints documentation for a var or special form given its name" - {:added "1.0"} - [name] - (cond - (special-form-anchor `~name) - `(print-special-doc '~name "Special Form" (special-form-anchor '~name)) - (syntax-symbol-anchor `~name) - `(print-special-doc '~name "Syntax Symbol" (syntax-symbol-anchor '~name)) - :else - (let [nspace (find-ns name)] - (if nspace - `(print-namespace-doc ~nspace) - `(print-doc (var ~name)))))) - - (defn tree-seq +(defn tree-seq "Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one @@ -5736,12 +5668,13 @@ (defmacro letfn - "Takes a vector of function specs and a body, and generates a set of - bindings of functions to their names. All of the names are available - in all of the definitions of the functions, as well as the body. + "fnspec ==> (fname [params*] exprs) or (fname ([params*] exprs)+) - fnspec ==> (fname [params*] exprs) or (fname ([params*] exprs)+)" - {:added "1.0"} + Takes a vector of function specs and a body, and generates a set of + bindings of functions to their names. All of the names are available + in all of the definitions of the functions, as well as the body." + {:added "1.0", :forms '[(letfn [fnspecs*] exprs*)], + :special-form true, :url nil} [fnspecs & body] `(letfn* ~(vec (interleave (map first fnspecs) (map #(cons `fn %) fnspecs))) diff --git a/src/clj/clojure/main.clj b/src/clj/clojure/main.clj index 96fa25b3..c21e20de 100644 --- a/src/clj/clojure/main.clj +++ b/src/clj/clojure/main.clj @@ -190,7 +190,7 @@ (catch Throwable e (caught e) (set! *e e))) - (use '[clojure.repl :only (source apropos dir pst)]) + (use '[clojure.repl :only (source apropos dir pst doc find-doc)]) (use '[clojure.java.javadoc :only (javadoc)]) (use '[clojure.pprint :only (pp pprint)]) (prompt) diff --git a/src/clj/clojure/repl.clj b/src/clj/clojure/repl.clj index 8b44d05b..b015ca2a 100644 --- a/src/clj/clojure/repl.clj +++ b/src/clj/clojure/repl.clj @@ -9,12 +9,125 @@ ; Utilities meant to be used interactively at the REPL (ns - #^{:author "Chris Houser, Christophe Grand, Stephen Gilardi, Michel Salim, Christophe Grande" + #^{:author "Chris Houser, Christophe Grand, Stephen Gilardi, Michel Salim" :doc "Utilities meant to be used interactively at the REPL"} clojure.repl (:import (java.io LineNumberReader InputStreamReader PushbackReader) (clojure.lang RT Reflector))) +(def ^:private special-doc-map + '{. {:url "java_interop#dot" + :forms [(.instanceMember instance args*) + (.instanceMember Classname args*) + (Classname/staticMethod args*) + Classname/staticField] + :doc "The instance member form works for both fields and methods. + They all expand into calls to the dot operator at macroexpansion time."} + def {:forms [(def symbol init?)] + :doc "Creates and interns a global var with the name + of symbol in the current namespace (*ns*) or locates such a var if + it already exists. If init is supplied, it is evaluated, and the + root binding of the var is set to the resulting value. If init is + not supplied, the root binding of the var is unaffected."} + do {:forms [(do exprs*)] + :doc "Evaluates the expressions in order and returns the value of + the last. If no expressions are supplied, returns nil."} + if {:forms [(if test then else?)] + :doc "Evaluates test. If not the singular values nil or false, + evaluates and yields then, otherwise, evaluates and yields else. If + else is not supplied it defaults to nil."} + monitor-enter {:forms [(monitor-enter x)] + :doc "Synchronization primitive that should be avoided + in user code. Use the 'locking' macro."} + monitor-exit {:forms [(monitor-exit x)] + :doc "Synchronization primitive that should be avoided + in user code. Use the 'locking' macro."} + new {:forms [(Classname. args*) (new Classname args*)] + :url "java_interop#new" + :doc "The args, if any, are evaluated from left to right, and + passed to the constructor of the class named by Classname. The + constructed object is returned."} + quote {:forms [(quote form)] + :doc "Yields the unevaluated form."} + recur {:forms [(recur exprs*)] + :doc "Evaluates the exprs in order, then, in parallel, rebinds + the bindings of the recursion point to the values of the exprs. + Execution then jumps back to the recursion point, a loop or fn method."} + set! {:forms[(set! var-symbol expr) + (set! (. instance-expr instanceFieldName-symbol) expr) + (set! (. Classname-symbol staticFieldName-symbol) expr)] + :url "vars#set" + :doc "Used to set thread-local-bound vars, Java object instance +fields, and Java class static fields."} + throw {:forms [(throw expr)] + :doc "The expr is evaluated and thrown, therefore it should + yield an instance of some derivee of Throwable."} + try {:forms [(try expr* catch-clause* finally-clause?)] + :doc "catch-clause => (catch classname name expr*) + finally-clause => (finally expr*) + + Catches and handles Java exceptions."} + var {:forms [(var symbol)] + :doc "The symbol must resolve to a var, and the Var object +itself (not its value) is returned. The reader macro #'x expands to (var x)."}}) + +(defn- special-doc [name-symbol] + (assoc (or (special-doc-map name-symbol) (meta (resolve name-symbol))) + :name name-symbol + :special-form true)) + +(defn- namespace-doc [nspace] + (assoc (meta nspace) :name (ns-name nspace))) + +(defn- print-doc [m] + (println "-------------------------") + (println (str (when-let [ns (:ns m)] (str (ns-name ns) "/")) (:name m))) + (cond + (:forms m) (doseq [f (:forms m)] + (print " ") + (prn f)) + (:arglists m) (prn (:arglists m))) + (if (:special-form m) + (do + (println "Special Form") + (println " " (:doc m)) + (if (contains? m :url) + (when (:url m) + (println (str "\n Please see http://clojure.org/" (:url m)))) + (println (str "\n Please see http://clojure.org/special_forms#" + (:name m))))) + (do + (when (:macro m) + (println "Macro")) + (println " " (:doc m))))) + +(defn find-doc + "Prints documentation for any var whose documentation or name + contains a match for re-string-or-pattern" + {:added "1.0"} + [re-string-or-pattern] + (let [re (re-pattern re-string-or-pattern) + ms (concat (mapcat #(sort-by :name (map meta (vals (ns-interns %)))) + (all-ns)) + (map namespace-doc (all-ns)) + (map special-doc (keys special-doc-map)))] + (doseq [m ms + :when (and (:doc m) + (or (re-find (re-matcher re (:doc m))) + (re-find (re-matcher re (str (:name m))))))] + (print-doc m)))) + +(defmacro doc + "Prints documentation for a var or special form given its name" + {:added "1.0"} + [name] + (if-let [special-name ('{& fn catch try finally try} name)] + (#'print-doc (#'special-doc special-name)) + (cond + (special-doc-map name) `(#'print-doc (#'special-doc '~name)) + (resolve name) `(#'print-doc (meta (var ~name))) + (find-ns name) `(#'print-doc (namespace-doc (find-ns '~name)))))) + ;; ---------------------------------------------------------------------- ;; Examine Clojure functions (Vars, really) |