私は間違った方法でこれに取り組んでいる可能性が非常に高いので、私の素朴さを許してください:
Clojure を学ぶために、Python 用の OAuth クライアント ライブラリを Clojure に移植し始めました。これは、Python ライブラリで Python リクエストをラップするのとほぼ同じ方法で clj-http をラップすることによって行っています。これは今のところかなりうまくいっているようで、Clojure で実装が実現するのを見るのは本当に楽しいです。
ただし、問題が発生しました。OAuth 1.0 と 2.0 の両方をサポートする予定で、それぞれの関数を oauth1.clj と oauth2.clj の 2 つのファイルに分割しました。ここで、各ファイルは、理想的には 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) でそれらを要求して、同じコードを 2 回記述しないようにすることでした。
ファイルで参照されている関数、つまり 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
varoauth2/get
が見つからないのは、oauth2.clj の名前空間に引き込むだけでは、実際にその名前空間にあるかのように公開されないように見えるためです。基本的に目的を無効にするため、より多くの関数でそれらをラップしたくありません。関数は非常に単純です (関数をラップするだけrequest
です)。そうする場合、基本的に 3 つの場所に関数を記述します。
私は Clojure の名前空間を適切に理解していないと確信しています。さらに、抽象化の問題と慣用的なコード共有についての一般的な考え方についても理解していません。
それで、これに対する慣用的な解決策は何だろうと思っていますか?私はこれを完全に間違った方法で行っていますか?
編集:
問題の簡略化は次のとおりです: https://gist.github.com/maxcountryman/5228259
目標は、HTTP 動詞関数を 1 回記述することであることに注意してください。特別なディスパッチ タイプなどは必要ありません。彼らはもうそのままでいい。accord.oauth1
問題は、これらがまたはから公開されていないことです。たとえばaccord.oauth2
、プログラムで必要なaccord.oauth2
場合です。
これが Python の場合は、次のように関数をインポートするだけで済みます: andにモジュールを使用すると、from accord.core import get, post, put, ...
インポートされたすべての関数 (例: ... ) にアクセスできます。accord.oauth1
accord.oauth2
accord.oauth1
import accord.oauth2 as oauth2
oauth2.get(...)
Clojure でこれを行うにはどうすればよいでしょうか。また、この種の DRY 抽象化を慣用的に提供するにはどうすればよいでしょうか。