Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the namespace where a form is called

Tags:

clojure

I would like a macro this-ns such that it returns the namespace of the location where it is being called. For instance, if I have this code

(ns nstest.main
  (:require [nstest.core :as nstest]))

(defn ns-str [x]
  (-> x (.getName) name))

(defn -main [& args]
  (println "The ns according to *ns*:" (ns-str *ns*))
  (println "The actual ns:" (ns-str (nstest/this-ns))))

I would expect that calling lein run would produce this output:

The ns according to *ns*: user
The actual ns: nstest.main

What I came up with as implementation was the following code:

(ns nstest.core)

(defmacro this-ns []
  (let [s (gensym)]
    `(do (def ~s)
         (-> (var ~s)
             (.ns)))))

It does seem to work, but it feels very hacky. Notably, in the above example it will expand to def being invoked inside the -main function which does not feel very clean.

My question: Is there a better way to implement this-ns to obtain the namespace where this-ns is called?

like image 400
Rulle Avatar asked Jan 27 '23 08:01

Rulle


1 Answers

here is one more variant:

(defmacro this-ns []
  `(->> (fn []) str (re-find #"^.*?(?=\$|$)") symbol find-ns))

the thing is the anonymous function is compiled to a class named something like playground.core$_main$fn__181@27a0a5a2, so it starts with the name of the actual namespace the function gets compiled in.

Can't say it looks any less hacky, then your variant, still it avoids the side effect, introduced by def in your case.

like image 165
leetwinski Avatar answered Jan 28 '23 21:01

leetwinski