Perfect, thanks Stuart! That works great :)
I put it in a convenience macro:
; Stuart Sierra
(defmacro defn-with-doc
"Like defn but accepts a procedurally generated string."
[fun doc-str & body]
`(let [f# (defn ~fun ~...@body)]
(alter-meta! (var ~fun) assoc :doc ~doc-str)
f#))
Got me thinking on a different line....
Laurent once remarked that it would be nice to attach argument
descriptions as meta data:
(defmacro defn-with-args
"Like defn but takes non-literal string doc,
and a map of arguments instead of a vector.
args should be a map of argument names to descriptions."
[fun doc-str args & body]
`(let [f# (defn ~fun ~(vec (map symbol (keys args)))
~...@body)]
(alter-meta! (var ~fun) assoc :doc
~(str doc-str \newline " "
args))
(alter-meta! (var ~fun) assoc :argdescs
~(vec (vals args)))
f#))
(let [m {:one 1, :two 2}]
(defn-with-args foo1
"hi1"
{"in1" "must be a string", "in2" (str "must be one of: " (keys
m))}
(println in1 (m in2))
(m in2)))
-------------------------
test-extensions/foo1
([in1 in2])
hi1
{"in1" "must be a string", "in2" (str "must be one of: " (keys m))}
(println (:argdescs ^(var foo1)))
[must be a string must be one of: (:one :two)]
My code is almost but not quite, but you get the idea... I think this
might be quite useful with a bit of improvement. I imagine Laurent is
mostly interested in the arguments from an IDE perspective, but in
general its nice to know precisely what arguments are expected.
Also a few people have discussed the "by contract" style. Another
possible extension would be to store preconditions:
(def *debug* false)
(defmacro check-preconditions
"Ensure preconditions are met."
[m]
(if *debug*
`(assert (apply = true (map #((val %) (key %)) ~m)))))
(defmacro defn-by-contract
"Like defn but takes non-literal string doc,
and a map of arguments instead of a vector.
args should be a map of strings to preconditions."
[fun doc-str args & body]
`(let [f# (defn ~fun ~(vec (map symbol (keys args)))
(check-preconditions args)
~...@body)]
(alter-meta! (var ~fun) assoc :doc
~(str doc-str \newline " "
args))
(alter-meta! (var ~fun) assoc :argdescs
~(vec (vals args)))
f#))
Actually preconditions should be handled completely separately perhaps
as another metadata :argpreds, this code is just to illustrate a
possibility.
If anyone is interested in playing with this, feel free to use:
http://github.com/timothypratley/strive/blob/baf83e2bb26662f5f5049d165dec31e47b91e171/clj/timothypratley/extensions.clj
http://github.com/timothypratley/strive/blob/baf83e2bb26662f5f5049d165dec31e47b91e171/clj/timothypratley/test-extensions.clj
Regards,
Tim.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---