MichaelDrogalis/dire — pull request #16 by dparis (2013-10-22 20:11:55+00:00)
Title: Add support for slingshot selector syntax when using with-handler

As discussed in #9, full support for slingshot selector syntax would be a nice addition to dire. Until slingshot opens up a (catch+ ...) function, I feel like I did the next best thing. First, I figured that rather than just using class names as keys in the error-handlers meta map, dire could use any type of slingshot selector: vector of key-value pairs, class name, or a predicate function. Then, I created a set of multimethods to match various error handlers to the thrown object. Each multimethod implementation, along with the dispatch, try to follow the logic of slingshot's selector syntax as closely as possible. Since it's not implemented as a macro, full support for a selector form was left out for now, but otherwise every other selector syntax is usuable. If anyone wants to take a stab at support full forms, it should just require creating a new multimethod and adding some logic to the dispatch function. As well, making it modular, if slingshot ever does expose it's catch macro logic we can just use the multimethods to pass the value into the slingshot functions. I think this strikes a nice balance between getting the functionality now while still making it painless to hook into the slingshot code if it becomes available.

Using the built-in slingshot support for predicate matching in the try+, I'm calling a HOF to generate a predicate closure around the task context when matching the catch clause. This allows the catch clause to only catch exceptions which match known selectors for that task. Any exception that comes through that isn't matched to a registered error-handler is passed along to the next catch clause in the try+. Right now, this shouldn't happen, since all current with-handler call semantics will be caught by either the pre-/post-condition clauses or the selector matching predicate, but it's nice to know the option exists.

As an example of what can now be done:

```clojure
(defn div [a b]
(if (= b 0)
(throw+ {:type :div-by-zero :message "You divided by zero, ya turkey!"})
(/ a b)))

(with-handler!
#'div
[:type :div-by-zero]
(fn [e & args] (println (:message e))))
```

There are some additional tests in the test suite which handle the supported slingshot syntax cases. All tests, new and old, pass cleanly. Oh, and I updated midje and lein-midje to the current stable versions in order to get :autotest support. Let me know if the code looks good and, if you like it, what an ETA might be for getting it merged upstream. In the mean time, I'm going to likely create a new clojars fork so that I can use the functionality in a project I'm working on.

Cheers!