1
votes

How can I search for a function in namespaces not 'required' or 'used' in a Clojure source file? Basically what I'd like to do is have source files:

main.clj,
a.clj,
b.clj,
c.clj

all compiled together but not directly import / require / use a, b, or c in main. Instead I have main take a command line parameter that would then search for the right function (perhaps even just a fully qualified symbol).

I looked at ns-publics but it requires a namespace symbol. I tried bultitude to get all the namespaces from with the src/ dir and I get back the lib.a, lib.b, lib.c, lib.main etc, but since main doesn't use or require or otherwise refer to the other namespaces I get an error using ns-publics. No namespace lib.a found as per the try in the-ns source code.

How can I look at the public interface of code included in the project but not directly referred to by a specific file, or even a dependency of a reference?

2

2 Answers

0
votes

Here's a simple workaround which might help until a better solution comes up. It returns a list of all public symbols defined in a file. Let's read the file and look for all def sexps. Ignore private ones, i.e. ones like defn-.

(let [file (with-in-str (str "(" (slurp filename) ")") (read))
      defs (filter #(.matches (str (first %)) "^def.*[^-]$") file)
      symbols (map second defs)]
  symbols)

Caveats:

  • Well, it's simply naïve.
  • It doesn't get rid of all private definitions. Ones defined with ^{:private true} or ^:private are not filtered out.
  • Definitions can be generated using macros.

The last point is especially troubling. The only reasonable way to detect definitions generated with macros is to evaluate the file with the reader, at least partially.

0
votes

Parsing isn't going to work because clojure is very dynamic.

So, something like this might work...

(load-file "file_with_stuff.clj")
(ns-publics (find-ns 'file-with-stuff))
(remove-ns 'file-with-stuff)

If you want to do everything dynamically, then you can generate the symbols using symbol -- should still work. Removing the ns is optional. It won't do any harm, but it does put you back where you started.