From 8b59d1509b76dc306a37dee3ecd0ad4b99cf0d56 Mon Sep 17 00:00:00 2001 From: Dan Holmsand Date: Fri, 14 Mar 2014 10:27:49 +0100 Subject: [PATCH] Add macros for more convenient javascript interop --- src/reagent/interop.clj | 40 ++++++++++++++++++++++++++++++++ src/reagent/interop.cljs | 3 +++ test/testinterop.cljs | 49 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/reagent/interop.clj create mode 100644 src/reagent/interop.cljs create mode 100644 test/testinterop.cljs diff --git a/src/reagent/interop.clj b/src/reagent/interop.clj new file mode 100644 index 0000000..6377932 --- /dev/null +++ b/src/reagent/interop.clj @@ -0,0 +1,40 @@ +(ns reagent.interop) + +(defn- js-call [f args] + (let [argstr (->> (repeat (count args) "~{}") + (interpose ",") + (apply str))] + (list* 'js* (str "~{}(" argstr ")") f args))) + +(defn- from-keyword [k] + (if (keyword? k) + (name k) + k)) + +(defn- get-names [k] + (->> (if (vector? k) k [k]) + (map from-keyword))) + +(defmacro jget + [o k] + `(aget ~o ~@(get-names k))) + +(defmacro jset + [o k v] + `(aset ~o ~@(get-names k) ~v)) + +(defmacro jcall + [o k & args] + (let [names (get-names k) + f (if (empty? names) + o + (list* 'aget o names))] + (js-call f args))) + +(defmacro jval + [s] + (assert (keyword? s)) + (let [sym (symbol "js" (name s))] + `(when (clojure.core/exists? ~sym) + ~sym))) + diff --git a/src/reagent/interop.cljs b/src/reagent/interop.cljs new file mode 100644 index 0000000..d5a872f --- /dev/null +++ b/src/reagent/interop.cljs @@ -0,0 +1,3 @@ +(ns reagent.interop) + +;; Empty file, to allow require with :refer-macros diff --git a/test/testinterop.cljs b/test/testinterop.cljs new file mode 100644 index 0000000..802386d --- /dev/null +++ b/test/testinterop.cljs @@ -0,0 +1,49 @@ +(ns testinterop + (:require [cemerick.cljs.test :as t :refer-macros [is deftest]] + [reagent.debug :refer-macros [dbg]] + [reagent.interop :refer-macros [jget jset jcall jval]])) + +(deftest interop-basic + (let [o #js {:foo "foo" + :foobar #js {:bar "bar"}}] + (is (= "foo" (jget o :foo))) + (is (= "foo" (jget o [:foo]))) + (is (= "bar" (jget o [:foobar :bar]))) + + (jset o :foo "foo1") + (is (= "foo1" (jget o :foo))) + + (jset o [:foo] "foo2") + (is (= "foo2" (jget o :foo))) + + (jset o [:foobar :bar] "bar1") + (is (= "bar1" (jget o [:foobar :bar]))))) + +(deftest interop-call + (let [o #js {:bar "bar1" + :foo (fn [x] + (this-as this + (str x (jget this :bar))))} + o2 #js {:o o}] + (is (= "ybar1" (jcall o :foo "y"))) + (is (= "xxbar1" (jcall o2 [:o :foo] "xx"))) + (is (= "abar1" (-> o2 + (jget [:o :foo]) + (jcall [] "a")))) + + (is (= "bar1" (jcall o :foo))) + (is (= "bar1" (jcall o [:foo]))) + (is (= "bar1" (jcall o2 [:o :foo]))) + + (jset o :bar "bar2") + (is (= "bar2" (jcall o :foo))) + + (is (= "1bar2" (jcall (jget o :foo) + :call o 1))) + + (is (= "yy" (jcall identity [] "yy"))))) + +(deftest interop-val + (set! js/someGlobal "foo") + (is (= "foo" (jval :someGlobal))) + (is (nil? (jval :nonExistingGlobal))))