-
Notifications
You must be signed in to change notification settings - Fork 982
/
re_frame.clj
90 lines (87 loc) · 3.7 KB
/
re_frame.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
(ns utils.re-frame (:refer-clojure :exclude [defn]))
(defn- register-events
[events interceptors name argsyms]
(mapv (fn [event]
`(utils.re-frame/register-handler-fx
~event
~interceptors
(fn [cofx# [_# ~@argsyms]] (~name cofx# ~@argsyms))))
events))
(defn- fully-qualified-name
[sym]
(str *ns* "/" (name sym)))
(defmacro defn
"Defines an fx producing function
Takes the same arguments as the defn macro
Produces a 2 arity function:
- first arity takes the declared parameters and returns a function that takes cofx as
single argument, for use in composition of effects
- second arity takes cofx as first arguments and declared parameters as next arguments,
for use in repl or direct call
Notes:
- destructuring of cofx is possible
- supports docstring
- supports attr-map with optional :events key which needs to be a vector of
event keywords under which the function will be registered
- TODO: add suport for `prepost-map?` (don't forget to add it to arglist)
- TODO: add validation of macro parameters"
{:arglists '([name doc-string? attr-map? [params*] body])}
[name & fdecl]
(let [m (if (string? (first fdecl))
{:doc (first fdecl)}
{})
fdecl (if (string? (first fdecl))
(next fdecl)
fdecl)
m (if (map? (first fdecl))
(conj m (first fdecl))
m)
events (get m :events [])
interceptors (get m :interceptors [])
fdecl (if (map? (first fdecl))
(next fdecl)
fdecl)
[cofx & args] (first fdecl)
fdecl (next fdecl)
argsyms (take (count args) (repeatedly #(gensym "arg")))]
(if (and (sequential? events)
(every? keyword? events))
`(do
(clojure.core/defn ~(with-meta name m)
([~@argsyms] (fn [cofx#] (~(with-meta name m) cofx# ~@argsyms)))
([cofx# ~@args]
(when js/goog.DEBUG
(when (taoensso.timbre/level>=
:trace
(:level taoensso.timbre/*config*))
(println
(clojure.string/join
(concat
(repeat
(deref utils.re-frame/handler-nesting-level)
"│ ")
["├─"]))
~(str (clojure.core/name name) " " *ns*))))
(if (and (map? cofx#)
(not (nil? (:db cofx#))))
(let [res# (let [~cofx cofx#] ~@fdecl)]
(when-not (nil? res#)
(aset res#
"cljs$core$ILookup$_lookup$arity$2"
(fn [foo# k#]
(clojure.core/this-as
m#
(when (and (map? k#)
(contains? k# :db))
(throw (js/Error. (str
"fx/defn's result is used as fx producing function in "
~(fully-qualified-name name)))))
(get m# k# nil)))))
res#)
(throw (js/Error. (str "fx/defn expects a map of cofx as first argument got " cofx#
" in function " ~(fully-qualified-name name)))))))
~@(register-events events interceptors (with-meta name m) argsyms))
(throw
(Exception.
(str "fx/defn expects a vector of keyword as value for :events key in attr-map in function "
name))))))