问题
I know I can get the :line
and :file
from the metadata on a var; however, I'm building a system where the user can pass me raw maps and I will end up "linking" the data together at a later time. When this linkage fails, I'd like to report the file/line in which they specified the map. E.g.:
(defn generate-stuff []
(make-thing { :k (make-thing { :k v }) }))
(link (generate-stuff) (other-generator))
;; outputs file/line of the map containing the errant :k/v pair
I assume that writing a macro to associate file/line with the collection's metadata is almost certainly the way to go, but since there isn't any "var" to look at, I'm not sure where to get the line number. I see the definition of get-line-number, but it requires a reader, and while I can find all of the special readers and the *default-data-reader-fn*
data reader (which is nil), I cannot seem to figure out how to access the "code" reader.
回答1:
OK, it looks like using &form
in a macro is the answer. I wrote the following bit of generic test code, and it seems to work:
(defmacro make-thing [obj]
(let [f *file*]
(with-meta obj (assoc (meta &form) :file f))))
The &form
refers to the form that invoked the macro, and it has metadata for line/column. The special var file has the relative path of the source file. So, combining the two into the metadata onto the object results in the desired result.
来源:https://stackoverflow.com/questions/30812123/clojure-how-do-i-get-the-file-line-number-on-which-a-map-was-defined