5

別の名前空間でコードの小さなスニペットを実行したいことがよくあります。たとえば、DSL コードのコピー/貼り付けスニペットなどです。次のいずれかを行う必要はありません。

  • use現在の名前空間宣言に一連の句を追加します。これにより、ns 宣言が乱雑になり、余分なメンテナンス作業が追加され、名前の衝突のリスクが生じることがあります。
  • 句を追加requireし、すべてに名前空間修飾子またはエイリアスを追加することを余儀なくされます。今、私の DSL コードはずっと厄介です。

理想的には、次のようなことができるようにしたいと思います。

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

は、 内のシンボルfooであるbar可能性がありますmy.namespacebaz、現在の (囲んでいる) 名前空間のシンボルです。したがって、コードは、そのスコープ内で my-namespace を「使用」する「ローカル」名前空間のようなもので実行されますが、それ以外の場合は周囲の名前空間には影響しません。

これを行うための標準/より良い方法はありますか? それとも、これはクレイジーなことですか?

4

3 に答える 3

3

これは、以下に示すマクロを使用して実現できます。

注:簡単な例で試しただけなので、場合によっては壊れることがあります

;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
于 2012-12-07T04:32:47.597 に答える
0

私は最終的に、古い Clojure contrib で、この部分を非常にきちんと実行するマクロを見つけました。

(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)))
于 2012-12-10T05:17:40.580 に答える