-
Notifications
You must be signed in to change notification settings - Fork 3
/
intercept.clj
67 lines (61 loc) · 2.82 KB
/
intercept.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
57
58
59
60
61
62
63
64
65
66
67
(ns tuck.intercept)
(defmacro intercept
"Return a new send function that wraps the given send function.
The event types specified in intercept forms are intercepted and
the their respective forms are run instead of sending the event.
Events that have no intercept are sent unaltered.
A final default interceptor may be specified with the type :default."
[e! & intercept-forms]
(let [event (gensym "EVENT")]
`(let [e!# ~e!
interceptors# ~(into {}
(map
(fn [[type bind form]]
[type `(fn [event#]
(let [~bind event#]
~form))]))
(take-while #(not= :default (first %))
intercept-forms))
default-interceptor# ~(when-let [default-form (first (drop-while #(not= :default (first %))
intercept-forms))]
(let [[_ bind form] default-form]
`(fn [event#]
(let [~bind event#]
~form))))]
(fn ui-send-intercept# [event#]
(assert (satisfies? tuck.core/Event event#))
(binding [tuck.core/*current-send-function* (or tuck.core/*current-send-function* e!#)]
(if-let [interceptor# (or (get interceptors# (type event#))
default-interceptor#)]
(interceptor# event#)
(e!# event#)))))))
(defmacro send-to
"Send to the given UI send function. Sends to captured send-functions must
be done via this function when called in intercept handlers. This sets the
binding of *current-send-function* properly so that it does not point to a
wrapped function when calling send-async!."
[e! event]
`(let [e!# ~e!]
(binding [tuck.core/*current-send-function* nil]
(e!# ~event))))
(comment
;; Simple example of syntax
;; Generic messages for a "table of items" type of component
(defrecord AddRow [data])
(defrecord RemoveRow [at-position])
;; We want to translate the generic types into
;; our domain specific order model. (for example we store
;; the data in a different format)
(defrecord AddOrderItem [id data])
(defrecord RemoveOrderItem [id])
;; then in our component
(defn order-view [e! orders]
[order (intercept
e!
(AddRow {:keys [data]}
(e! (->AddOrderItem (orders/next-order-id orders)
data)))
(RemoveRow {p :at-position}
(e! (->RemoveOrderItem (:id (nth orders p)))))
(:default e ))
orders]))