Slingshot

Slingshot enhance try and throw for Clojure leveraging Clojure’s capabilities. It provide try+ and throw+ that is 100% compatible with Clojure and Java’s native try and throw both in source code and at runtime. Furthermore, we can now throw+ map, records, or anything we want (You are kidding right? It must at least be an Java object.)

Real world example:

(interact
   [this command expected_ok expected_err]
   (write this command)
   (let [bin (read this)
         data (string/split bin #" ")
         resp (first data)]
     (cond
      (member? expected_ok resp)
      data

      (member? expected_err resp)
      (throw+ {:type :command-failure :message bin})

      true
      (throw+ {:type :unexpected-response :message bin}))))

  )

And now I normally use these snippet to help testing my functions.

(defn slingshot-exception-class
  "Return the best guess at a slingshot exception class."
  []
  (try
    (Class/forName "slingshot.Stone")
    (catch Exception _
      (let [ei (Class/forName "slingshot.ExceptionInfo")]
        (if (and (resolve 'clojure.core/ex-info)
                 (resolve 'clojure.core/ex-data))
          (Class/forName "clojure.lang.ExceptionInfo")
          ei)))))

(defmacro is-thrown+?
  "clojure.test clause for testing that a slingshot exception is thrown."
  [& body]
  `(is (~'thrown? ~(slingshot-exception-class) ~@body)))

(defmacro is-thrown-with-msg+?
  "clojure.test clause for testing that a slingshot exception is thrown."
  [& body]
  `(is (~'thrown-with-msg? ~(slingshot-exception-class) ~@body)))

(deftest put-body
  (let [bt (beanstalkd-factory)]
    (watch bt "default")
    (testing "Put non-str body"
      (is-thrown+? {:type :type-error :message "Job body must be a String"} (put bt 1234)))))