shader
shader

Reputation: 841

How do I get a list of public functions in a ClojureScript namespace?

I want to get a list of public functions from another namespace so they can be exposed as commands.

A similar question for Clojure seemed close, but does not seem to work on ClojureScript.

Another question has answers for Clojurescript, but they either only show how to print them to the REPL, or return all members instead of only the publicly exposed ones.

Upvotes: 3

Views: 434

Answers (1)

user2609980
user2609980

Reputation: 10474

ClojureScript does not have a resolve function. It is possible to mimic the behavior using hacks, e.g., this one:

(defn ->js [var-name]
  (-> var-name
      (clojure.string/replace #"/" ".")
      (clojure.string/replace #"-" "_")))

(defn invoke [function-name & args]
  (let [f (js/eval (->js function-name))]
    (apply f args)))

The second question you linked has an answer that refers to the clojure.repl/dir function which prints

a sorted directory of public vars in a namespace.

If you can print them, you can turn them into a string with with-out-str.

Now let's assume we have a namespace called demo.core with one public function called add:

(ns demo.core)

(defn add [a b]
  (println "hello from add")
  (+ a b))

We can retrieve the public fns from demo.core as strings as follows:

(defn public-fns
  "Returns coll of names of public fns in demo.core"
  []
  (as-> (with-out-str (clojure.repl/dir demo.core)) public-fns
    (clojure.string/split public-fns #"\n")
    (map (fn [s] (str "demo.core/" s)) public-fns)))

So with with-out-str we turn them into a list of strings, then split on newline, then prepend the names of public functions with "demo.core".

Then, using our earlier created invoke function, we can obtain add and invoke it with the arguments 1 and 2:

(invoke (first (public-fns)) 1 2)
;; "hello from add"
;; => 3

This is all very hacky, and it might break in advanced compilation, but it works.

Upvotes: 3

Related Questions