mirror of https://github.com/status-im/reagent.git
Add better javascript interop macros
This commit is contained in:
parent
907a85db9c
commit
6389a3889a
|
@ -6,8 +6,9 @@
|
||||||
:dependencies [[org.clojure/clojure "1.5.1"]
|
:dependencies [[org.clojure/clojure "1.5.1"]
|
||||||
[org.clojure/clojurescript "0.0-2173"]]
|
[org.clojure/clojurescript "0.0-2173"]]
|
||||||
:plugins [[lein-cljsbuild "1.0.2"]
|
:plugins [[lein-cljsbuild "1.0.2"]
|
||||||
[com.cemerick/clojurescript.test "0.2.2"]]
|
[com.cemerick/clojurescript.test "0.3.0"]]
|
||||||
:profiles {:prod {:cljsbuild
|
:profiles {:dev {:source-paths ["src" "demo"]}
|
||||||
|
:prod {:cljsbuild
|
||||||
{:builds
|
{:builds
|
||||||
{:client {:compiler
|
{:client {:compiler
|
||||||
{:optimizations :advanced
|
{:optimizations :advanced
|
||||||
|
|
|
@ -1,11 +1,54 @@
|
||||||
(ns reagent.interop
|
(ns reagent.interop
|
||||||
(:require [clojure.string :refer [join]]))
|
(:require [clojure.string :as string :refer [join]]))
|
||||||
|
|
||||||
(defn- js-call [f args]
|
(defn- js-call [f args]
|
||||||
(let [argstr (->> (repeat (count args) "~{}")
|
(let [argstr (->> (repeat (count args) "~{}")
|
||||||
(join ","))]
|
(join ","))]
|
||||||
(list* 'js* (str "~{}(" argstr ")") f args)))
|
(list* 'js* (str "~{}(" argstr ")") f args)))
|
||||||
|
|
||||||
|
(defn- dot-args [object member]
|
||||||
|
(assert (or (symbol? member)
|
||||||
|
(keyword? member))
|
||||||
|
(str "Symbol or keyword expected, not " member))
|
||||||
|
(assert (or (not (symbol? object))
|
||||||
|
(not (re-find #"\." (name object))))
|
||||||
|
(str "Dot not allowed in " object))
|
||||||
|
(let [n (name member)
|
||||||
|
field? (or (keyword? member)
|
||||||
|
(= (subs n 0 1) "-"))
|
||||||
|
names (-> (if (symbol? member)
|
||||||
|
(string/replace n #"^-" "")
|
||||||
|
n)
|
||||||
|
(string/split #"\."))]
|
||||||
|
[field? names]))
|
||||||
|
|
||||||
|
(defmacro .'
|
||||||
|
"Access member in a javascript object, in a Closure-safe way.
|
||||||
|
'member' is assumed to be a field if it is a keyword or if
|
||||||
|
the name starts with '-', otherwise the named function is
|
||||||
|
called with the optional args.
|
||||||
|
'member' may contain '.', to allow access in nested objects.
|
||||||
|
If 'object' is a symbol it is not allowed contain '.'."
|
||||||
|
[object member & args]
|
||||||
|
(let [[field names] (dot-args object member)]
|
||||||
|
(if field
|
||||||
|
(do
|
||||||
|
(assert (empty? args)
|
||||||
|
(str "Passing args to field doesn't make sense: " member))
|
||||||
|
`(aget ~object ~@names))
|
||||||
|
(js-call (list* 'aget object names) args))))
|
||||||
|
|
||||||
|
(defmacro .!
|
||||||
|
"Set field in a javascript object, in a Closure-safe way.
|
||||||
|
'field' should be a keyword or a symbol starting with '-'.
|
||||||
|
'field' may contain '.', to allow access in nested objects.
|
||||||
|
If 'object' is a symbol it is not allowed contain '.'."
|
||||||
|
[object field value]
|
||||||
|
(let [[field names] (dot-args object field)]
|
||||||
|
(assert field (str "Field name must start with - in " field))
|
||||||
|
`(aset ~object ~@names ~value)))
|
||||||
|
|
||||||
|
|
||||||
(defn- kwd [k]
|
(defn- kwd [k]
|
||||||
(if (keyword? k) (name k) k))
|
(if (keyword? k) (name k) k))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(ns testinterop
|
(ns testinterop
|
||||||
(:require [cemerick.cljs.test :as t :refer-macros [is deftest]]
|
(:require [cemerick.cljs.test :as t :refer-macros [is deftest]]
|
||||||
[reagent.debug :refer-macros [dbg]]
|
[reagent.debug :refer-macros [dbg]]
|
||||||
[reagent.interop :refer-macros [oget oset odo]]))
|
[reagent.interop :refer-macros [.' .! oget oset odo]]))
|
||||||
|
|
||||||
(deftest interop-basic
|
(deftest interop-basic
|
||||||
(let [o #js{:foo "foo"
|
(let [o #js{:foo "foo"
|
||||||
|
@ -43,3 +43,48 @@
|
||||||
:call o 1)))
|
:call o 1)))
|
||||||
|
|
||||||
(is (= "yy" (odo identity [] "yy")))))
|
(is (= "yy" (odo identity [] "yy")))))
|
||||||
|
|
||||||
|
(deftest iterop-quote
|
||||||
|
(let [o #js{:foo "foo"
|
||||||
|
:foobar #js{:bar "bar"}
|
||||||
|
:bar-foo "barfoo"}]
|
||||||
|
(is (= "foo" (.' o :foo)))
|
||||||
|
(is (= "bar" (.' o :foobar.bar)))
|
||||||
|
(is (= "barfoo" (.' o :bar-foo)))
|
||||||
|
|
||||||
|
(is (= "foo" (.' o -foo)))
|
||||||
|
(is (= "bar" (.' o -foobar.bar)))
|
||||||
|
(is (= "barfoo" (.' o -bar-foo)))
|
||||||
|
|
||||||
|
(.! o :foo "foo1")
|
||||||
|
(is (= "foo1" (.' o :foo)))
|
||||||
|
|
||||||
|
(.! o -foo "foo2")
|
||||||
|
(is (= "foo2" (.' o -foo)))
|
||||||
|
|
||||||
|
(.! o :foobar.bar "bar1")
|
||||||
|
(is (= "bar1" (.' o :foobar.bar)))
|
||||||
|
|
||||||
|
(.! o -foobar.bar "bar1")
|
||||||
|
(is (= "bar1" (.' o -foobar.bar)))))
|
||||||
|
|
||||||
|
(deftest interop-quote-call
|
||||||
|
(let [o #js{:bar "bar1"
|
||||||
|
:foo (fn [x]
|
||||||
|
(this-as this
|
||||||
|
(str x (.' this :bar))))}
|
||||||
|
o2 #js{:o o}]
|
||||||
|
(is (= "ybar1" (.' o foo "y")))
|
||||||
|
(is (= "xxbar1" (.' o2 o.foo "xx")))
|
||||||
|
(is (= "abar1" (-> o2
|
||||||
|
(.' :o)
|
||||||
|
(.' foo "a"))))
|
||||||
|
|
||||||
|
(is (= "bar1" (.' o foo)))
|
||||||
|
(is (= "bar1" (.' o2 o.foo)))
|
||||||
|
|
||||||
|
(.! o :bar "bar2")
|
||||||
|
(is (= "bar2" (.' o foo)))
|
||||||
|
|
||||||
|
(is (= "1bar2" (.' (.' o :foo)
|
||||||
|
call o 1)))))
|
||||||
|
|
Loading…
Reference in New Issue