I'm looking at the implementation for the old contrib macro with-ns:
(defmacro with-ns
"Evaluates body in another namespace. ns is either a namespace
object or a symbol. This makes it possible to define functions in
namespaces other than the current one."
[ns & body]
`(binding [*ns* (the-ns ~ns)]
~@(map (fn [form] `(eval '~form)) body)))
What I don't understand is the need to eval the body. In other words, why doesn't this work in the case where I want to access elements in the target namespace within the body w/o the eval (example below).
user=> (defmacro wns [ns & body] `(binding [*ns* (the-ns ~ns)] ~@body))
#'user/wns
user=> (create-ns 'boofar)
#<Namespace boofar>
user=> (in-ns 'boofar)
#<Namespace boofar>
boofar=> (clojure.core/refer-clojure)
nil
boofar=> (defn xx [a b] (str a b))
#'boofar/xx
boofar=> (xx 5 6)
"56"
boofar=> (in-ns 'user)
#<Namespace user>
user=> (with-ns 'boofar (println *ns*) (xx 5 6))
#<Namespace boofar>
"56"
user=> (wns 'boofar (println *ns*) (xx 5 6))
CompilerException java.lang.RuntimeException:
Unable to resolve symbol: xx in this context,
compiling:(blardy/blardy/form-init3758076021118964250.clj:1:29)
user=> (wns 'boofar (println *ns*))
#<Namespace boofar>
nil
I'm OK with this. I really don't mind, but I'd like to understand what's going on here. xx clearly exists in the boofar namespace, and pushing the ns binding should put me there, yet I can't call it directly, however I can call something in clojure.core which has been referred. In case you're wondering, I tried re-writing the macro to use in-ns with the corresponding try/finally and the result is the same.
Thanks!
edit
Added example of the macro using in-ns. Results are the same as without.
user=> (defmacro wins [ns & body]
`(let [orig-ns# (ns-name *ns*)]
(try
(in-ns ~ns)
~@body
(finally (in-ns orig-ns#)))))
The expanded macro...
user=> (pprint (macroexpand-all '(wins 'boofar2 (xx 7 8))))
(let*
[orig-ns__4137__auto__ (clojure.core/ns-name clojure.core/*ns*)]
(try
(clojure.core/in-ns 'boofar2)
(xx 7 8)
(finally (clojure.core/in-ns orig-ns__4137__auto__))))
Using it...
user=> (defn xx [a b] (str "user/xx [" a " " b "]"))
user=> (in-ns 'boofar2)
boofar2=> (defn xx [a b] (str "boofar2/xx [" a " " b "]"))
boofar2=> (in-ns 'user)
user=> (wins 'boofar2 (xx 7 8))
"user/xx [7 8]"