taoensso.truss
An opinionated assertions (micro) library for Clojure/Script.
get-data
clj
(get-data)
Returns current value of dynamic assertion data.
have
macro
clj
(have x)
(have pred (:in) x)
(have pred (:in) x & more-xs)
Takes a (fn pred [x]) => truthy, and >=1 vals.
Tests pred against each val,trapping errors.
If any pred test fails, throws a detailed `ExceptionInfo`.
Otherwise returns input val/s for convenient inline-use/binding.
Respects `*assert*`, so tests can be elided from production if desired
(meaning zero runtime cost).
Provides a small, simple, flexible feature subset to alternative tools like
clojure.spec, core.typed, prismatic/schema, etc.
Examples:
(defn my-trim [x] (str/trim (have string? x)))
;; Attach arb optional info to violations using `:data`:
(have string? x
:data {:my-arbitrary-debug-info "foo"})
;; Assert inside collections using `:in`:
(have string? :in ["foo" "bar"])
Regarding use within other macros:
Due to CLJ-865, callsite info like line number of outer macro
will be lost. See `keep-callsite` for workaround.
See also `have?`, `have!`.
have!
macro
clj
(have! x)
(have! pred (:in) x)
(have! pred (:in) x & more-xs)
Like `have` but ignores `*assert*` value (so can never be elided!).
Useful for important conditions in production (e.g. security checks).
have!?
macro
clj
(have!? x)
(have!? pred (:in) x)
(have!? pred (:in) x & more-xs)
Returns `true` on successful tests, and ignores `*assert*` value
(so can never be elided!).
**WARNING**: Do NOT use in `:pre`/`:post` conditions since those always
respect `*assert*`, contradicting the intention of the bang (`!`) here.
have?
macro
clj
(have? x)
(have? pred (:in) x)
(have? pred (:in) x & more-xs)
Like `have` but returns `true` on successful tests.
Handy for `:pre`/`:post` conditions. Compare:
((fn my-fn [] {:post [(have nil? %)]} nil)) ; {:post [nil ]} FAILS
((fn my-fn [] {:post [(have? nil? %)]} nil)) ; {:post [true]} passes as intended
keep-callsite
macro
clj
added in v1.8.0 (2022-12-13)
(keep-callsite form)
The long-standing CLJ-865 means that it's not possible for an inner
macro to access the `&form` metadata of a wrapping outer macro. This
means that wrapped macros lose calsite info, etc.
This util offers a workaround for macro authors:
(defmacro inner [] (meta &form))
(defmacro outer [] (keep-callsite `(inner)))
(outer) => {:keys [line column ...]}
set-error-fn!
clj
(set-error-fn! f)
Sets the root (fn [data-map-delay]) called on invariant violations.
with-data
macro
clj
(with-data data & body)
Executes body with dynamic assertion data bound to given value.
This data will be included in any violation errors thrown by body.
with-error-fn
macro
clj
(with-error-fn f & body)