# com.noahbogart/sinker catch exceptions hook, line, and sinker. fuck ai forever. ## installation ```clojure lazytest/skip=true :deps {com.noahbogart/sinker {:mvn/version "0.2.0"}} ``` ## features it's `try` but a little nicer: ```clojure (require '[com.noahbogart.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 `:com.noahbogart.sinker/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 `:com.noahbogart.sinker/exception`. (try+ (throw (ex-info "Wrong parameter" {::sinker/type :invalid-parameter :expected 'abc :given 'foobar})) (catch :invalid-parameter data (ex-message (::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 - [exoscale/ex](https://github.com/exoscale/ex) - [scgilardi/slingshot](https://github.com/scgilardi/slingshot/) 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](https://github.com/NoahTheDuke/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.