2010-04-25 44 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