-
Notifications
You must be signed in to change notification settings - Fork 128
/
exceptions.clj
67 lines (48 loc) · 2.06 KB
/
exceptions.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 ^{:doc "Functions for Midje to deal elegantly with exceptions."}
midje.util.exceptions
(:require [clojure.string :refer [join]]
[midje.util.ecosystem :refer [line-separator]]))
;;; Creating
(defn user-error
"Used when a user does something off-limits or incompatible"
[& lines]
(Error. (join line-separator lines)))
;;; Printing ergonomic stacktraces
(defn- ^{:testable true} stacktrace-as-strings [^Throwable ex]
(map str (.getStackTrace ex)))
(letfn [(remove-matches [re strings]
(remove #(re-find re %) strings))]
(defn- ^{:testable true} without-clojure-strings [all-strings]
(remove-matches #"^java\.|^clojure\.|^sun\.|^swank\.|^user\$eval" all-strings))
(defn- ^{:testable true} without-midje-or-clojure-strings [all-strings]
(remove-matches #"^java\.|^clojure\.|^sun\.|^swank\.|^user\$eval|^midje" all-strings)))
(defn- ^{:testable true} friendly-exception-lines [ex prefix]
(cons (str ex)
(map #(str prefix %)
(without-midje-or-clojure-strings (stacktrace-as-strings ex)))))
(defn user-error-exception-lines [throwable]
(cons (str throwable)
(without-clojure-strings (stacktrace-as-strings throwable))))
(defn- friendly-caused-by [ex prefix]
(when-let [cause (.getCause ex)]
(let [[data & stacktrace] (friendly-exception-lines cause prefix)]
(cons (str line-separator prefix "Caused by: " data)
stacktrace))))
;; When a fact throws an Exception or Error it gets wrapped
;; in this deftype
(defprotocol ICapturedThrowable
(throwable [this])
(friendly-stacktrace [this]))
(deftype CapturedThrowable [ex]
ICapturedThrowable
(throwable [this] ex)
(friendly-stacktrace [this]
(join line-separator
(concat (friendly-exception-lines (throwable this) " ")
(friendly-caused-by (throwable this) " ")))))
(defn captured-throwable [ex]
(CapturedThrowable. ex))
(defn captured-throwable? [x]
(instance? CapturedThrowable x))
(defn captured-message [ex]
(.getMessage ^Throwable (throwable ex)))