Liking cljdoc? Tell your friends :D

noahtheduke/sinker

catch exceptions hook, line, and sinker.

installation

:deps {io.github.noahtheduke/sinker {:mvn/version "0.1.0"}}

features

it's try but a little nicer:

(require '[noahtheduke.sinker :as sinker :refer [try+]])

;; works like normal try
(try+)
;; => nil

(try+ 1 2 3)
;; => 3

(try+ (throw (Exception. "hello world!"))
  (catch Exception ex
    (ex-message ex)))
;; => "hello world!"

;; ex-infos with `:noahtheduke.sinker/type` (or `:type`) ex-data can be caught with a keyword.
;; the keywords are compared with isa? to respect heirarchies.
;; the bound variable is the ex-data, not the exception itself.
(try+ (throw (ex-info "Wrong parameter" {::sinker/type :invalid-parameter
                                         :expected :abc
                                         :given :foobar}))
  (catch :invalid-parameter data
    (:given data)))
;; => :foobar

;; the exception is on the metadata of the bind under the key `:noahtheduke.sinker/exception`.
(try+ (throw (ex-info "Wrong parameter" {::sinker/type :invalid-parameter
                                         :expected 'abc
                                         :given 'foobar}))
  (catch :invalid-parameter data
    (ex-message (:noahtheduke.sinker/exception (meta data)))))
;; => "Wrong parameter"

;; because the ex-data is a map, it can be destructured
(try+ (throw (ex-info "Wrong parameter" {::sinker/type :invalid-parameter
                                         :expected :abc
                                         :given :foobar}))
  (catch :invalid-parameter {:keys [expected given]}
    [expected given (= expected given)]))
;; => [:abc :foobar false]

;; ex-infos can also be caught with predicate functions or vars.
;; the predicate must be a 1-arg function that takes the `ex-data`.
;; like catching a keyword, the bound variable is the ex-data, not the exception itself.
(defn pred [data]
  (= :value (:key data)))

(try+ (throw (ex-info "KV pair" {::sinker/type :incorrect-argument
                                 :key :value}))
  (catch pred {k :key}
    k))
;; => :value

;; like normal try, each catch is checked in definition order,
;; and finally clauses gotta come last
(defn pred2 [data]
  (= :value2 (:key2 data)))

(def finally-ran? (atom nil))

(try+ (assert (= 1 2) "This will work")
  (catch :invalid-argument _
    :invalid-argument)
  (catch pred2 ex
    (ex-message ex))
  (catch clojure.lang.ExceptionInfo ex
    (ex-data ex))
  (catch Exception _
    "Got us an exception!")
  (catch Throwable t
    (str "Received a " (.getName (class t))))
  (finally
    (reset! finally-ran? "hoodee hoodee hoo")))
;; => "Received a java.lang.AssertionError"

@finally-ran?
;; => "hoodee hoodee hoo"

others in the space

this library is quite similar to exoscale/ex, but ex is solely focused on exception infos and does a lot more, with a stronger emphasis on a specific pattern of error handling. i wrote this to fill a gap in lazytest and to satisfy my curiosity. i don't expect this to receive widespread adoption nor do i really want it. sometimes it's just nice to make something and let others check it out, you know?

license

Copyright © Noah Bogart

Distributed under the Mozilla Public License version 2.0.

Can you improve this documentation?Edit at git repository

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close