2012-12-06 56 views
5

我經常想在另一個命名空間中運行一小段代碼 - 例如可能是複製/粘貼的DSL代碼片段,並且我想避免必須:運行來自不同命名空間的嵌入代碼

  • 將一堆use子句添加到我當前的名稱空間聲明中。這使得ns申報變得凌亂,增加了額外的維護工作,有時還會冒名稱衝突的風險。
  • 添加require子句並被迫爲所有內容添加名稱空間限定符或別名。現在我的DSL代碼更加混亂。

理想我寧願能夠做這樣的事情:

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

foobar可能是符號內my.namespace,但baz在當前(封閉)命名空間的象徵。所以代碼運行時會像「本地」命名空間那樣在其作用域內「使用」my-namespace,但不會影響周圍的命名空間。

有沒有一個標準/更好的方法來做到這一點?或者這是一個想要做的瘋狂事情?

+0

我使用負載文件排序得到這個,這是一個黑客: - /所以你不唯一的一個,它可能仍然是瘋狂的。 –

+0

@Arthur - 嗯,看看如何工作,但往往這段代碼不是在一個自包含的文件,也似乎是當我們不需要的時候濫用文件系統。很高興在Conj BTW見到你! – mikera

+0

這是限制,因爲DSL使用(在我的情況下網絡+虛擬機的定義需要爲每個文件一個,所以這不是一個好的答案。很高興見到你以及:) –

回答

4

試試這個:從當前納秒

(defmacro with-ns [[namespace symbols] & body] 
    `(do (use '[~namespace :only ~symbols]) 
     (let [result# (do [email protected])] 
     (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!"] 

下班後它會刪除所使用的符號。

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 
+0

我認爲這個解決方案的一個重大缺陷(在至少在目前的形式)是它會取代任何嵌套的'let'塊中綁定的符號。但仍然從我+1。 –

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)] 
    [email protected](map (fn [form] `(eval '~form)) body))) 
+0

這不是解決方案,因爲臨時名稱空間「ns」中沒有來自當前ns的符號(在您的示例中爲「baz」)。或者你的問題是關於臨時全名空間切換而不訪問當前ns的符號? – mobyte

+0

是的,你是對的 - 它並沒有解決所有的問題 – mikera

+0

你可以調整宏來引用其他名稱空間。 – Bill