Preamble
Two thoughts:
Namespaces are not tied to files; they can be created and removed as desired. However, both idiomatically and through clojure.core
, they are typically tied to files, being specified at the top of a file that shares the same name: src/noahtheduke/splint/rules.clj
holds a single namespace noahtheduke.splint.rules
, which is declared before all other forms. This is enforced in require
and use
calls: (require '[noahtheduke.foo.bar :as fb])
will find a file at src/noahtheduke/bar.clj
and then once the file is loaded will attempt to find the namespace noahtheduke.bar
and raise an error if it does not exist.
In the compiler, DefExpr
will add to the created var's metadata location data in the form of :line
, :column
, and :file
. The first two come from the seq and latter from *file*
. This allows for introspection and analysis from tooling, and for better error handling in exceptions and messages.
Desired functionality
I have a collection of namespaces. I want to slurp the corresponding files (if they exist) to analyze and modify with rewrite-clj.
Discussion
Right now, I use metadata on vars to find relevant objects in code and then find the file that way:
(defn get-path-from-var [var']
(let [f (:file (meta var'))
path (or (some-> f
(#(.. (Thread/currentThread)
(getContextClassLoader)
(getResource %)))
(io/file)
(str))
f)]
{:path path
:file (when (and path (.exists (io/file path)))
(slurp path))}))
However, that requires users to use the defcram
macro I've written, which limits the potential for inline-usage of my primary macro compare-output
(such as in a deftest
).
I want to be able to use *ns*
in compare-output
to potentially find where the macro is being called, so I can perform the analysis and desired diffing. This would most easily be done by having location metadata on namespaces.
But more importantly than just my library, I think having location metadata on namespaces would be a genuine help for many tools (such as eastwood, tools.namespace, CIDER, kibit, splint, etc).
Solutions
I'm only going to discuss one solution because this is an Ask, not a jira ticket lol.
I think adding the location metadata in the ns
macro is the best place to put it. The ns
macro is the preferred way to create a new namespace. Creating namespaces with in-ns
or create-ns
requires additional steps to make the namespace usable, and neither is a macro to hold &form
metadata, increasing the work of adding location metadata.