How do you organize function names when building clojure libraries for public consumption?

Viewed 1083

Let's say I want to build a large clojure library with several components. As a developer, I would like to keep many of the components in separate namespaces since many helper functions can have similar names. I don't necessarily want to make things private since they may have utility outside in extreme cases and the work-arounds behind private is not good. (In other words, I would like to suggest code usage, not completely prevent usage.)

However, I would like the users of the library to operate in a namespace with a union of a subset of many of the functions in each sub library. What is the idiomatic or best way to do this? One solution that comes to my mind is to write a macro that generates :requires and creates a new var mapping by def'ing a given list of var names (see first code example). Are there tradeoffs with this method such as what happens to extending types? Is there a better way (or builtin)?

Macro example (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])

Again, to clarify, the end goal would be to have some file in other projects created by users of mylib to be able to make something like (src/someproject/core.clj):

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

 (mylib/mapper 'foo 'bar)

@Jeremy Wall, note that your proposed solution does not fullfill my needs. Lets assume the following code exists.

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: (Assume classpaths are set correctly)

 (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

If you notice, "using" functions in mylib/public.clj DOES NOT allow public.clj to PROVIDE these vars to the user file somerandomproject/core.clj.

2 Answers
Related