-
Notifications
You must be signed in to change notification settings - Fork 410
/
interop.clj
56 lines (50 loc) · 2.11 KB
/
interop.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
(ns reagent.interop
(:require [clojure.string :as string :refer [join]]))
(defn- js-call [f args]
(let [argstr (->> (repeat (count args) "~{}")
(join ","))]
(list* 'js* (str "~{}(" argstr ")") f args)))
(defn- dot-args [object member]
(assert (or (symbol? member)
(keyword? member))
(str "Symbol or keyword expected, not " (pr-str 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 '.'.
($ o :foo) is equivalent to (.-foo o), except that it gives
the same result under advanced compilation.
($ o foo arg1 arg2) is the same as (.foo o arg1 arg2)."
[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 '.'.
($! o :foo 1) is equivalent to (set! (.-foo o) 1), except that it
gives the same result under advanced compilation."
[object field value]
(let [[field names] (dot-args object field)]
(assert field (str "Field name must start with - in " field))
`(aset ~object ~@names ~value)))