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.cljexample, theprintlnis 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 fileexample.cljcould have:Then from the REPL or anywhere,
(foo 42)would print:Note that it doesn’t matter which file
source-fileis defined in, only where it was expanded, that is the file wherefoois defined. This works because it’s whenfoois compiled thatsource-fileis run, and the return value ofsource-filewhich is just a string is then included in the compiled version offoo. The string is then of course available every timefooexecutes.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.