I'm reading in the API docs that the *file*
variable should have a value of "the path of the file being evaluated, as a String". However, this feature seems broken in certain cases.
When I execute a file using lein exec
, things work as expected:
$ cat test.clj
(println *file*)
$ lein exec test.clj
/path/to/test.clj
Yet when I run a test that contains a call to (println *file*)
, NO_SOURCE_PATH
is printed instead of the file containing that line.
Why am I seeing this behavior, and how can I reliably access the path and filename of the file being evaluated?
*file*
is set to the path of the file being compiled, so after your whole program is compiled it is no longer useful to look at the value of *file*
(assuming no use of eval).
In your test.clj
example, the println
is executed while the file is still being compiled. If the reference to *file*
is moved into a test or function, it will only be dereferenced at runtime after the value of *file*
is no longer useful.
One option is to write a macro that stores the value of *file*
when it is expanded, so that the result can be used later. For example, a file example.clj
could have:
(defmacro source-file []
*file*)
(defn foo [x]
(println "Foo was defined in" (source-file) "and called with" x))
Then from the REPL or anywhere, (foo 42)
would print:
Foo was defined in /home/chouser/example.clj and called with 42
Note that it doesn't matter which file source-file
is defined in, only where it was expanded, that is the file where foo
is defined. This works because it's when foo
is compiled that source-file
is run, and the return value of source-file
which is just a string is then included in the compiled version of foo
. The string is then of course available every time foo
executes.
If this behaviour is surprising, it may help to consider what would have to happen in order for *file*
to have a useful value inside every function at runtime. Its value would have to change for every function call and return, a substantial runtime overhead for a rarely-used feature.
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