Add macros for more convenient javascript interop

This commit is contained in:
Dan Holmsand 2014-03-14 10:27:49 +01:00
parent 23ae1661fe
commit 8b59d1509b
3 changed files with 92 additions and 0 deletions

40
src/reagent/interop.clj Normal file
View File

@ -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)))

3
src/reagent/interop.cljs Normal file
View File

@ -0,0 +1,3 @@
(ns reagent.interop)
;; Empty file, to allow require with :refer-macros

49
test/testinterop.cljs Normal file
View File

@ -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))))