A micro toolkit for Clojure/Script errors.
Optional context to add to the data of exceptions created by `truss/ex-info`. Value may be any type, but is usually nil or a map. Default (root) value is nil. When present, value will be assoc'ed to `:truss/ctx` key of exception data. Useful for dynamically providing arbitrary contextual info to exceptions: Re/bind dynamic value using `with-ctx`, `with-ctx+`, or `binding`. Modify root (default) value using `set-ctx!`. As with all dynamic Clojure vars, "binding conveyance" applies when using futures, agents, etc.
?(fn [failed-assertion-info]) to call with failed assertion info map when a Truss assertion (`have`, `have?`, `have!`, `have!?`) fails. Will by default throw an appropriate `truss/ex-info`. This is a decent place to inject logging for assertion failures.
(callsite-coords macro-form)Returns [line column] from meta on given macro `&form`. See also `keep-callsite`.
(catching expr)(catching catch-class expr)Terse cross-platform util to swallow exceptions in `expr`. Like (try* expr (catch :default _ nil)). See also `try*`.
(catching-rf rf)(catching-rf error-fn rf)Returns wrapper around given reducing function `rf` so that if `rf` throws, (error-fn <thrown-error> <contextual-data>) will be called. The default `error-fn` will rethrow the original error, wrapped in extra contextual information to aid debugging. Helps make reducing fns easier to debug! See also `catching-xform`.
(catching-xform xform)(catching-xform error-fn xform)Like `catching-rf`, but applies to a transducer (`xform`).
Helps make transductions much easier to debug by greatly improving
the info provided in any errors thrown by `xform` or the reducing fn:
(transduce
(catching-xform (comp (filter even?) (map inc))) ; Modified xform
<reducing-fn>
<...>)(ex-info msg)(ex-info msg data-map)(ex-info msg data-map cause)Like `core/ex-info` but when dynamic `*ctx*` value is present, it will be assoc'ed to `:truss/ctx` key of returned exception's data. Useful for dynamically providing arbitrary contextual info to exceptions. See `*ctx*` for details.
(ex-info! msg)(ex-info! msg data-map)(ex-info! msg data-map cause)Throws a `truss/ex-info`.
(failed-assertion-ex-info failed-assertion-info)(failed-assertion-ex-info legacy-ex-data? failed-assertion-info)Returns an appropriate `truss/ex-info` for given failed assertion info map.
(have x)(have pred (:in) x)(have pred (:in) x & more-xs)Main Truss assertion util.
Takes a (fn pred [x]) => truthy, and >=1 vals.
Tests pred against each val,trapping errors.
If any pred test fails, throws a detailed `truss/ex-info`.
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).
Examples:
(defn my-trim [x] (str/trim (have string? x)))
;; Add arb optional info to thrown ex-data using `:data`:
(have string? "foo" :data {:user-id 101}) => "foo"
;; Assert inside collections using `:in`:
(have string? :in #{"foo" "bar"}) => #{"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! x)(have! pred (:in) x)(have! pred (:in) x & more-xs)Truss assertion util. Like `have` but ignores `*assert*` value (so will never be elided). Useful for important conditions in production (e.g. security checks).
(have!? x)(have!? pred (:in) x)(have!? pred (:in) x & more-xs)Truss assertion util. Returns `true` (rather than given arg value) on success, and ignores `*assert*` value (so will never be elided). **WARNING**: do NOT use in `:pre`/`:post` conditions since those ALWAYS respect `*assert*`, contradicting the intention of the bang (`!`) here.
(have? x)(have? pred (:in) x)(have? pred (:in) x & more-xs)Truss assertion util.
Like `have` but returns `true` (rather than given arg value) on success.
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 inner-form)CLJ-865 means that it's not possible for an inner macro to access `&form`
metadata (incl. {:keys [line column]}) of a wrapping outer macro:
(defmacro inner [] (meta &form))
(defmacro outer [] `(inner))
(outer) => nil
This util offers a workaround for authors of the outer macro, preserving
the outer `&form` metadata for the inner macro:
(defmacro inner [] (meta &form))
(defmacro outer [] (keep-callsite `(inner)))
(outer) => {:keys [line column ...]}(matching-error error)(matching-error kind error)(matching-error kind pattern error)Given a platform error and criteria for matching, returns the error if it matches all criteria. Otherwise returns nil. `kind` may be: - A class (`ArithmeticException`, `AssertionError`, etc.) - A special keyword as given to `try*` (`:default`, `:common`, `:ex-info`, `:all`) - A set of `kind`s as above, at least one of which must match - A predicate function, (fn match? [x]) -> bool `pattern` may be: - A string or Regex against which `ex-message` must match - A map against which `ex-data` must match using `submap?` - A set of `pattern`s as above, at least one of which must match When an error with (nested) causes doesn't match, a match will be attempted against its (nested) causes. This is a low-level util, see also `throws`, `throws?`.
(set-ctx! root-ctx-val)Set `*ctx*` var's default (root) value. See `*ctx*` for details.
(submap? super-map sub-map)Returns true iff `sub-map` is a (possibly nested) submap of `super-map`, i.e. iff every (nested) value in `sub-map` has the same (nested) value in `super-map`. `sub-map` may contain special values: `:submap/nx` - Matches iff `super-map` does not contain key `:submap/ex` - Matches iff `super-map` does contain key (any val) `:submap/some` - Matches iff `super-map` does contain key (non-nil val) (fn [super-val]) - Matches iff given unary predicate returns truthy Uses stack recursion so supports only limited nesting.
(throws form)(throws kind form)(throws kind pattern form)Evals `form` and if it throws an error that matches given criteria using
`matching-error`, returns the matching error. Otherwise returns nil.
Useful for unit tests, e.g.:
(is (throws :default {:a :b} (throw (ex-info "MyEx" {:a :b, :c :d})))) ; => ExceptionInfo
(is (throws :default "MyEx" (throw (ex-info "MyEx" {:a :b, :c :d})))) ; => ExceptionInfo
See also `throws?`, `matching-error`.(throws? form)(throws? kind form)(throws? kind pattern form)Evals `form` and if it throws an error that matches given criteria using
`matching-error`, returns true. Otherwise returns false.
Useful for unit tests, e.g.:
(is (throws? :default {:a :b} (throw (ex-info "MyEx" {:a :b, :c :d})))) ; => true
(is (throws? :default "MyEx" (throw (ex-info "MyEx" {:a :b, :c :d})))) ; => true
See also `throws`, `matching-error`.(try* expr* catch-clauses* ?finally-clause)Like `try`, but `catch` clause class may be:
`:ex-info` -- Catches only `ExceptionInfo`
`:common` --- Catches `js/Error` (Cljs), `Exception` (Clj)
`:all` ------ Catches `:default` (Cljs), `Throwable` (Clj)
`:default` -- Catches `:default` (Cljs), `Exception`, and `AssertionError` (Clj)
but NOT other (usually critical) `Error`s
Addresses CLJ-1293 and the fact that `AssertionError`s are typically NON-critical
(so desirable to catch, in contrast to other `Error` classes).(unexpected-arg! arg)(unexpected-arg! arg {:keys [msg context param expected ...]})(unexpected-arg! arg & {:keys [msg context param expected ...]})Throws `truss/ex-info` to indicate an unexpected argument.
Takes optional kvs for merging into exception's data map.
(let [mode :unexpected]
(case mode
:read (do <...>)
:write (do <...>)
(unexpected-arg! mode
{:param 'mode
:context `my-function
:expected #{:read :write}}))) =>
Unexpected argument: :unexpected
{:param 'mode,
:arg {:value :unexpected, :type clojure.lang.Keyword},
:context 'taoensso.encore/my-function,
:expected #{:read :write}}(with-ctx ctx-val form)Evaluates given form with given `*ctx*` value. See `*ctx*` for details.
(with-ctx+ update-map-or-fn form)Evaluates given form with updated `*ctx*` value. `update-map-or-fn` may be: - A map to merge with current `*ctx*` value, or - A unary fn to apply to current `*ctx*` value See `*ctx*` for details.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |