2014-10-17 11 views
2

我正在研究一個需要能夠從shell命令行讀取Clojure代碼的Clojure應用程序。該應用程序具有一個-main函數,該函數讀取在包含單個Clojure表單的命令行上傳遞的字符串,並將該字符串傳遞給Clojure函數load-string,該函數解析字符串並執行代碼。這使用lein run和使用uberjar成功運行。如何在初始編譯時間後使命名空間別名可用?

我發現如果名稱空間爲required位於包含-main的文件頂部,則在命令行傳遞的代碼可以包含完全限定的名稱空間名稱。例如,如果源文件與

(ns popco.core.popco 
    (:require [popco.core.reporters :as rpt])) 

開始然後我通過在命令行上的字符串可以通過popco.core.reporters/ticker引用我的功能ticker。但是,我不能使用別名rpt。如果我通過rpt/ticker提及ticker,我會發現一個例外:java.lang.RuntimeException: No such namespace: rpt

我猜這是因爲別名只在編譯時可用,只有一個編譯時間。由於load-file編譯代碼字符串的時間是源文件編譯完成後的時間,因此rpt不再可用作別名。

允許我使用命名空間別名的解決方案是在-main內複製文件頂部的require s(我希望在repl中運行時使用)。然而,我可能需要包含幾個名稱空間,當然,重複代碼是不可取的。

有沒有另一種解決方案?某種方法可以定義一次別名,在repl中運行時以及從命令行運行代碼時都可以使用別名? (編輯:上面編譯時間的分析不能完全正確 - 也許我不懂Clojure彙編(嗯,其實我不懂Clojure彙編!)解決方案在上面兩段中提到的使用require語句在-main中的原始源代碼中,不僅使用傳遞給load-file的字符串,所以require在編譯-main時得到編譯,我想,這將在與我假設源文件的頂部,但是如果代碼被輸入到-main的定義中,-main中的代碼在文件頂部的別名範圍內,但如果通過load-file引入代碼,則代碼不在其範圍內。通過load-file(require '[popco.core.reporters :as rpt])字面上是在-main的源代碼中的別名範圍內。爲什麼?)

回答

1

alias功能,這是該機制需要採用VIA :as鍵創建命名空間的別名,變異的當前命名空間。即,運行alias時的當前名稱空間。

這就是爲什麼require嵌入到您定義的-main中會以您期望的方式創建別名:它會突變您的運行時名稱空間以包含給定的別名。顯然,這並不一定會改變popco.core.popco命名空間!實際上,在調用-main時(這將在編譯時間,因此,如在ns宏中,會突變所定義的ns),運行時不太可能成爲工作命名空間。

這裏的關鍵是要認識到ns在運行時並不總是它定義了-main功能ns,如果你想在運行時發生變異的評價環境中,你需要或者切換到正在變異的命名空間,或者改變你所在的命名空間。

+1

感謝您的詳細解釋。非常有趣,也很有幫助。 – Mars 2014-10-19 02:27:55