2011-07-30 33 views
9

假設我想要構建一個包含多個組件的大型clojure庫。作爲一名開發人員,我想將許多組件保存在不同的名稱空間中,因爲許多助手函數可能具有相似的名稱。我不一定要把事情私人化,因爲他們在極端情況下可能具有外部效用,並且隱私背後的解決方案並不好。 (換句話說,我想建議代碼的使用,而不是完全阻止使用。)如何在構建公共消費的clojure庫時組織函數名稱?

但是,我希望庫的用戶在一個命名空間中操作的聯合的許多功能的子集每個子庫。什麼是地道或最好的方式來做到這一點?我想到的一個解決方案是編寫一個生成以下代碼的宏:通過定義給定的var名稱列表來請求並創建一個新的var映射(請參閱第一個代碼示例)。這種方法是否存在折衷,如擴展類型會發生什麼?有沒有更好的方法(或內置)?

宏示例中(src/MYLIB/public.clj):

(ns mylib.public 
    (:require [mylib.a :as a]) 
    (:require [mylib.b :as b])) 

(transfer-to-ns [+ a/+ 
        - b/- 
        cat b/cat 
        mapper a/mapper]) 

再次澄清,最終目標將是在由mylib中的用戶創建的其他項目的一些文件,能夠使像中(src/someproject/core.clj):

(ns someproject.core 
    (:require [mylib.public :as mylib])) 

(mylib/mapper 'foo 'bar) 

@Jeremy牆,請注意您提出的解決方案並不fullfill我的需要。讓我們假設存在以下代碼。

MYLIB/a.clj:

(ns mylib.a) 

(defn fa [] :a) 

MYLIB/b.clj:

(ns mylib.b) 

(defn fb [] :b) 

MYLIB/public.clj:

(ns mylib.public 
    (:use [mylib.a :only [fa]]) 
    (:use [mylib.b :only [fb]])) 

somerandomproject/core.clj:(假設類路徑設置正確)

(ns somerandomproject.core 
    (:require [mylib.public :as p]) 

;; somerandomproject.core=> (p/fa) 
;; CompilerException java.lang.RuntimeException: No such var: p/fa, compiling:  (NO_SOURCE_PATH:3) 
;; somerandomproject.core=> (mylib.a/fa) 
;; :a 

如果您注意到,mylib/public.clj中的「使用」函數不允許public.clj將這些變量提供給用戶文件somerandomproject/core.clj。

回答

9

你會覺得很有趣看像CompojureLamina庫如何組織其「公共」的API。

椎板有像lamina.api「公共」的命名空間用來別名(使用扎克進口-FN從他的波將金號庫)從像lamina.core.pipeline「內部」的命名空間功能。通過一些文檔,這可以清楚地描述面向公衆的ns從可能改變的內部。我發現這個策略的一個主要缺點是import-fn使得從函數的使用到執行(emacs)非常困難。或者例如,要知道使用clojure.repl/source的函數。

像Compojure這樣的圖書館使用私人變量來分隔公共/私人部分的功能(例如參見compojure.core)。 「私人」功能的主要缺點是您稍後可能會發現您想要公開它們或使測試更加複雜。如果你控制了代碼庫,我不認爲私有方面是一個大問題。測試問題很容易通過使用#'foo.core/my-function來引用私有函數。

一般來說,我傾向於使用比拉米娜更像Compojure的風格的東西,但它聽起來像你更喜歡更像拉米娜的東西。

+0

好的答案。我曾嘗試過compojure.core風格,但遇到了你提到的限制,所以我一直在尋找潛在的替代品,我會在接受之前調查葉片並瞭解它是如何工作的 – bmillare

+0

Cascalog按照類似的方式組織但不太嚴格 - 您需要的許多主要內容是在cascalog.api ns中或者是別名,但您也可以訪問底層ns的更高級功能。 –

2

我不完全確定你在這裏問什麼。我想也許你想知道從共享實用程序函數的命名空間導入公共的最佳做法是什麼?在這種情況下,參考功能是你在找什麼,我認爲:http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/refer

(refer mylib.a :only [+]) 
(refer mylib.b :only [-]) 

據進口大衆項目的命名空間到當前的命名空間。然而,首選方法是用一個做到這一點在你的命名空間聲明:使用指令

(ns (:use (mylib.a :only [+]) 
      (mylib.b :only [-]))) 
+0

這個想法是爲用戶建立一個命名空間來要求。這不是爲了開發這個clj文件,而是在他們需要或使用你創建的文件的地方開發其他clj文件。所以在我的例子中,你會在ns形式中,有類似於(:require [mylib.public:as mylib] – bmillare

+0

你提出的解決方案不滿足我的需求,請參閱澄清 – bmillare

相關問題