-
Notifications
You must be signed in to change notification settings - Fork 1
/
core.cljc
75 lines (58 loc) · 2.17 KB
/
core.cljc
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
(ns defntly.core
(:require [defntly.specs]
[clojure.spec.alpha :as s]
[clojure.core.specs.alpha :as specs]))
(defn update-conf [{[arity] :fn-tail :as conf} body-update-fn]
(case arity
:arity-1 (update-in conf [:fn-tail 1 :body 1] body-update-fn)
:arity-n (update-in conf [:fn-tail 1 :bodies] (fn [bodies]
(map (fn [body]
(update-in body [:body 1] body-update-fn))
bodies)))))
(comment
(throw (Exception. "aa")))
(defn defn-update-body
"Return a `defn` form where the body is updated by `f`.
`f` receives `name` and `body` and returns an updated body.
It supports all the `defn` arguments (doctrings, metadata, multi-artities etc..)
It is meant to by used to create `defn` like macros.
Based on https://blog.klipse.tech/clojure/2019/03/08/spec-custom-defn.html
Example:
Let's create a `defn-try` macro that automatically wraps the function body in a `try/catch` form.
(defn wrap-try [name body]
`((try ~@body
(catch Throwable ~'e
(throw (Exception. (str \"Exception caught in function \" ~name \": \" ~'e)))))))
(defmacro defn-try [& args]
(defn-update-body wrap-try args))
We use `defn-try` exactly like `defn`:
(defn-try foo [a b]
(+ a b))
is macroexpanded into:
(defn foo [a b]
(try
(+ a b)
(catch
java.lang.Throwable
e
(throw (str \"Exception caught in function \" \"foo\" \": \" e)))))
"
[f args]
(let [{:keys [fn-name] :as conf} (s/conform ::specs/defn-args args)
new-conf (update-conf conf (partial f (str fn-name)))
new-args (s/unform ::specs/defn-args new-conf)]
(cons `defn new-args)))
(defn wrap-try [name body]
`((try ~@body
(catch Throwable ~'e
(throw (str "Exception caught in function " ~name ": " ~'e))))))
(defn-update-body wrap-try '(foo [a b] (+ a b)))
(comment
(defmacro defn-try [& args]
(defn-update-body wrap-try args))
(defn-try foo [a b]
(+ a b))
(defn-try foo
"foo has a docstring"
([a] (foo a 42))
([a b] (+ a b))))