Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call a clojurescript function by string name

I'm searching for a way to call a function given its string name in clojureScript.

Something like:

(call "my-fun" args) 

Any help welcome

like image 292
szymanowski Avatar asked Apr 28 '14 15:04

szymanowski


2 Answers

A pretty hackish solution that should work:

(ns eval.core
  (:require [clojure.string :as str]))

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


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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Usage:

(ns example.core
  (:require [eval.core :as e]))

(defn ^:export my-fn [arg1 arg2]     ;; Note the export!
      (println arg1 arg2)
      arg2)

(e/invoke "example.core/my-fn" 5 6)                       ;=> 5 6
like image 68
Marcin Bilski Avatar answered Oct 15 '22 12:10

Marcin Bilski


I needed a way of calling a function whose ns/name is loaded dynamically. As noted, there is no supported way of doing so. However, that's what hacks are for. Here's what I ended up doing:

Calling cljs:

(js/proxy "my-ns/my-fun" args)

Proxy.js:

function proxy() {
  var args = Array.prototype.slice.call(arguments);
  var nsFunc = args[0].replace(/-/g, "_").replace(/\//g, ".");
  eval(nsFunc).apply(null, args.slice(1));
}

Dynamically resolved cljs:

(ns my-ns)
(defn ^:export my-fun [args] ...)

The export metadata tells the closure compiler not to munge the name, so this works even with advanced mode compilation. Needless to say, this isn't rock-solid code that's guaranteed to work in the future - but you get the idea.

like image 33
Ryan Avatar answered Oct 15 '22 11:10

Ryan