error.clj
Branches > namespace-reorganization > e863077 > files / src / dev / grahp / error.clj
(ns dev.grahp.error
"Error handling stuff idk sometimes it's annoying in clojure lol"
(:require [clojure.spec.alpha :as s]
[clojure.string :as str]))
(defmacro raise
"Throws an error with msg and an optional map and cause"
{:arglists '([msg]
[msg m]
[msg m cause]
[exception-class msg]
[exception-class msg cause])}
([msg] `(throw (RuntimeException. ~msg)))
([msg m]
(if (symbol? msg)
`(throw (~msg ~m))
`(throw (ex-info ~msg ~m))))
([msg m cause]
(if (symbol? msg)
`(throw (~msg ~m ~cause))
`(throw (ex-info ~msg ~m ~cause)))))
#_(defmacro guard
"If form throws an exception, evaluates handler with the exception as an argument."
([form] `(guard ~form (constantly nil)))
([form handler]
`(try ~form
(catch Exception e# (~handler e#)))))
(defmacro assert!
"Yields x if it is truthy, else throws an ex-info with optional message and map.
Only run when *assert* is truthy, otherwise yields x"
([x] `(assert! ~x nil))
([x msg] `(assert! ~x ~msg {}))
([x msg m]
(if *assert*
`(or ~x
(raise (str "Assert Failed!" (when ~msg (str " " ~msg)) "\n"
'~x)
~m))
x)))
#_(defmacro assert2!
"Yields x if it is truthy, else throws an ex-info with optional message and map.
Only run when *assert* is truthy, otherwise yields x"
([x] `(assert2! ~x {}))
([x m & msg]
(if *assert*
`(or ~x
(raise (str "Assert Failed! " ~@(interpose \space msg) \newline (pr-str '~x))
~m))
x)))
(defmacro ensure!
"Yields x if it conforms to spec, else throws and ex-info with optional message and map"
([spec x] `(ensure! ~spec ~x nil))
([spec x msg] `(ensure! ~spec ~x ~msg {}))
([spec x msg m]
`(let [x# ~x]
(if (s/valid? ~spec x#)
x#
(raise (str "Assertion failed: " (pr-str '~x) "\n"
(when-let [msg# ~msg]
(str msg# "\n"))
(str/trim-newline (s/explain-str ~spec x#)))
(assoc ~m '~x x#))))))
(defmacro ensure-not!
"Yields x if it does not conform to spec, else throws and ex-info with optional message and map"
([spec x] `(ensure-not! ~spec ~x nil))
([spec x msg] `(ensure-not! ~spec ~x ~msg {}))
([spec x msg m]
`(let [x# ~x]
(if (s/valid? ~spec x#)
(raise (str "Assertion failed: " (pr-str '~x) "\n"
(when-let [msg# ~msg]
(str msg# "\n"))
(str/trim-newline (s/explain-str ~spec x#)))
(assoc ~m '~x x#))
x#))))