_Comment made by: stu_
Why try to guess what someone wants to do with the locals (or any other context, for that matter) when you can specify a callback (see below). This would have been useful last week when I had an assertion that failed only on the CI box, where no debugger is available.
Rich, at the risk of beating a dead horse, I still think this is a good idea. Debuggers are not always available, and this is an example of where a Lisp is intrinsically capable of providing better information than can be had in other environments. If you want a patch for the code below please mark waiting on me, otherwise please decline this ticket so I stop looking at it. :-)
(def ^:dynamic *assert-handler* nil)
(defn ^{:private true} local-bindings
"Produces a map of the names of local bindings to their values."
[env]
(let [symbols (map key env)]
(zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))
(defmacro assert
[x]
(when *assert*
(let [bindings (local-bindings &env)]
`(when-not ~x
(let [sep# (System/getProperty "line.separator")
form# '~x]
(if *assert-handler*
(*assert-handler* form# ~bindings)
(throw (AssertionError. (apply str "Assert failed: " (pr-str form#) sep#
(map (fn [[k# v#]]
(when (some #{k#} (flatten form#))
(str "\t" k# " : " v# sep#)))
~bindings))))))))))