summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChouser <chouser@n01se.net>2010-10-22 07:57:10 -0400
committerStuart Halloway <stu@thinkrelevance.com>2010-11-29 21:01:58 -0500
commit40da6266790a264ea6a13ee93ca38a0555718aa2 (patch)
tree7b14905b06d3f07effbed59f7259a3f111c6b6f9
parentc6e7e5765e4bd6624e87115819d384f4a755d700 (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.clj97
-rw-r--r--src/clj/clojure/main.clj2
-rw-r--r--src/clj/clojure/repl.clj115
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)