Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run embedded code from a different namespace

I often want to run a small snippet of code in another namespace - perhaps a copy/pasted snippet of DSL code for example, and I'd like to avoid having to either:

  • Add a bunch of use clauses to my current namespace declaration. This makes the ns declaration messy, adds extra maintenance work and sometimes risks name clashes.
  • Add require clauses and be forced to add a namespace qualifier or alias to everything. Now my DSL code is much messier.

Ideally I'd prefer to be able to do something like:

(with-ns my.namespace
  (foo bar baz))

Where foo, bar might be symbols within my.namespace, but baz is a symbol in the current (enclosing) namespace. So the code is running in something like a "local" namespace that "uses" my-namespace within its scope but otherwise doesn't affect the surrounding namespace.

Is there a standard/better way to do this? Or is this a crazy thing to want to do?

like image 295
mikera Avatar asked Dec 06 '12 21:12

mikera


2 Answers

Try this one:

(defmacro with-ns [[namespace symbols] & body]
  `(do (use '[~namespace :only ~symbols])
       (let [result# (do ~@body)]
         (doseq [sym# (map #(:name (meta (val %)))
                           (filter #(= (name '~namespace)
                                       (str (:ns (meta (val %)))))
                                   (ns-refers *ns*)))]
           (ns-unmap *ns* sym#))
         result#)))

(with-ns [clojure.string [split upper-case]]
  (split (upper-case "it works!") #" "))
-> ["IT" "WORKS!"]

After work it removes used symbols from current ns.

like image 124
mobyte Avatar answered Sep 28 '22 02:09

mobyte


This can be achieved using a macro as shown below.

NOTE: It may break in certain cases as I just tried it with a simple example

;Some other ns
(ns hello)
(def h1 10) ;in hello
(def h2 11) ;in hello

;main ns in which executing code
(ns user)


(defmacro with-ns [target-ns body]
  (clojure.walk/postwalk
   (fn [val]
     (if (symbol? val)
       (if (resolve (symbol (str target-ns "/" val)))
         (symbol (str target-ns "/" val))
         val) val)) body))

(def u1 100) ;in user

(with-ns hello (do (+ h1 u1))) ;110
like image 27
Ankur Avatar answered Sep 28 '22 00:09

Ankur