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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With