2010-04-25 18 views
5

是否有可能重寫'require'命令,以便它會嘗試下載某個資源(如果它在本地計算機上未找到)。例如:在Clojure中重寫'require'?

(require 'examples.introduction) 
; if not found => download from the net 
; (url: http://media.pragprog.com/titles/shcloj/code/examples/introduction.clj) 

回答

4

您可以覆蓋require功能,當然還有被覆蓋的變種可以下載的東西,如果有人問了命名空間是不可用的類路徑上。覆蓋的方式:require(ns ...)工作的形式是AFAIK,由於處理ns的方式,現在不可能。

請注意,如果您想在類路徑(包括新罐子)上放置新路徑,那麼下載require將不會很有幫助,因爲classpath注入在Clojure中無法可靠地工作(由於JVM問題) 。有clojure.core/add-classpath ...但它被永久標記爲已棄用,強烈建議不要使用它的使用,也不保證它可以爲您工作,並且這種情況很可能不會很快改變。另一方面,如果你想把新的源文件放在類路徑中已經存在的目錄中,那麼應該可以正常工作。

如果你想玩弄壓倒一切的require,如果你有一個foo命名空間,你可以做

(ns foo 
    (:refer-clojure :exclude [require]) 
    ; other stuff; any :requires here will work as usual! 
) 

然後定義你自己的需要,使用clojure.core/require在適當的時候:

(defn require [ns-symbol] 
    (do-stuff-to-obtain-the-namespace)) 

clojure.contrib.find-namespaces命名空間可能有助於找出類路徑上可用的內容。 (或者你可以使用the-ns功能,看看它是否在通過clojure.core/require要求命名空間的初步嘗試後,會拋出異常。)

注意,binding的做法,可能會浮現在腦海中的第一((binding [require ...] ...))將行不通,因爲require通常會解析爲Var在clojure.core名稱空間中實現的,而來自名稱以clojure開頭的名稱空間的Vars當前由編譯器直接鏈接(這意味着在運行時不會執行實際的Var查找,因此重新綁定這些Vars對代碼沒有影響) 。

ns形式爲您的命名空間中的(:refer-clojure :exclude [require])防止require從解析爲clojure.core/require,並讓你免費在自己的名稱空間定義名稱的無功。如上所述,如果您鍵入完全限定的符號,則不會阻止可訪問Var。clojure.core/require Var。

+0

有趣。我在想,爲了避免使用命名空間解決方法,可能會更好地使用不同的函數名稱,如「enhanced-require」。 (我是一個總noob,所以糾正我,如果我說廢話:)) – StackedCrooked 2010-04-25 19:47:18

+0

相反,這似乎是一個更好的方式去做。不過,我必須指出,實際上,最好的方式是讓Leiningen/Maven獲得任何庫依賴關係,並且像源代碼隨書一樣,只需下載並手動下載...: - )並不是說它需要任何東西來寫出一個可以自己完成的時髦需求。 – 2010-04-25 19:53:05