我可能用了错误的方法,希望您原谅我的天真:
为了学习Clojure,我已经开始将我的Python OAuth客户端库移植到Clojure。我通过在Clojure中包装clj-http来完成这个过程,就像在Python库中包装Python请求一样。到目前为止,这似乎运作得很好,我非常喜欢看到实现在Clojure中生动起来。
然而,我遇到了一个问题:我计划支持OAuth 1.0和2.0,并将各自的函数分成两个文件:oauth1.clj和oauth2.clj。现在,每个文件应该理想地公开一组与HTTP动词对应的函数。
这些功能在oauth1.clj和oauth2.clj文件中基本上是相同的,事实上它们目前完全相同。我的第一反应是将这些功能移动到core.clj中,并在各自的OAuth命名空间(oauth1、oauth2)中引用它们,以避免重复编写代码。
只要我在文件中使用了所需函数,即oauth1.clj或oauth2.clj,这种方式就可以了。但是,假设我们想要像我打算的那样在REPL(或者说您的程序)中使用该库,大概是这样的:
为了学习Clojure,我已经开始将我的Python OAuth客户端库移植到Clojure。我通过在Clojure中包装clj-http来完成这个过程,就像在Python库中包装Python请求一样。到目前为止,这似乎运作得很好,我非常喜欢看到实现在Clojure中生动起来。
然而,我遇到了一个问题:我计划支持OAuth 1.0和2.0,并将各自的函数分成两个文件:oauth1.clj和oauth2.clj。现在,每个文件应该理想地公开一组与HTTP动词对应的函数。
(ns accord.oauth2)
...
(defn get
[serv uri & [req]]
((:request serv) serv (merge req {:method :get :url uri})))
这些功能在oauth1.clj和oauth2.clj文件中基本上是相同的,事实上它们目前完全相同。我的第一反应是将这些功能移动到core.clj中,并在各自的OAuth命名空间(oauth1、oauth2)中引用它们,以避免重复编写代码。
只要我在文件中使用了所需函数,即oauth1.clj或oauth2.clj,这种方式就可以了。但是,假设我们想要像我打算的那样在REPL(或者说您的程序)中使用该库,大概是这样的:
=> (require '[accord.oauth2 :as oauth2]) ;; require the library's oauth2 namespace
...
=> (oauth2/get my-service "http://example.com/endpoint") ;; use the HTTP functions
oauth2/get
变量未找到,因为仅在oauth2.clj
中将其引入命名空间似乎并没有将其公开,就好像它实际上在该命名空间中。我不想用更多的函数包装它们,因为那基本上会打败目的;这些函数非常简单(它们只是包装一个request
函数),如果我这样做,我将在三个地方编写它们。
我确定我没有正确理解Clojure中的命名空间,而且也许对于抽象问题和代码共享的通用思考方式存在误解。
所以我想知道这个问题的惯用解决方案是什么?我是完全错误的吗?
编辑:
这里是问题的简化:https://gist.github.com/maxcountryman/5228259
请注意,目标是一次编写HTTP动词函数。它们不需要特殊的分派类型或类似的东西。它们已经很好了。问题在于它们没有从accord.oauth1
或accord.oauth2
公开,即当您的程序需要accord.oauth2
时。
如果这是Python,我们可以像这样导入函数:from accord.core import get, post, put, ...
到accord.oauth1
和accord.oauth2
,然后当我们使用accord.oauth1
模块时,我们将访问所有这些导入的函数,例如import accord.oauth2 as oauth2
...oauth2.get(...)
。
在Clojure中我们如何做到这一点或者我们应该以惯用方式提供这种DRY抽象?
=> (oauth2/get foo "http://example.com/") 编译器异常 java.lang.RuntimeException: 没有这个变量:oauth2/get,编译中:(NO_SOURCE_PATH:1)
- maxcountrymanaccord.oauth-common
,并导入它来获取常见的函数;或者2)只需使用def
来重新绑定每个命名空间中想要的函数(而不是完全重新声明它们),例如(def get oauth1/get)
。我个人会选择第一种选项。 - DaoWenbar.clj
中只需写(ns testing.bar (:use [test core baz]))
。 - DaoWen(require '[testing.bar :as bar])
...(bar/qux "test")
会显示"No such var: bar/qux"。但是在bar.clj中:(def qux baz/qux)
将会行得通。明白我试图做什么吗? - maxcountryman