diff options
Diffstat (limited to 'src/clojure')
-rw-r--r-- | src/clojure/contrib/except/except.clj | 75 |
1 files changed, 46 insertions, 29 deletions
diff --git a/src/clojure/contrib/except/except.clj b/src/clojure/contrib/except/except.clj index d6dd62d9..e65044dc 100644 --- a/src/clojure/contrib/except/except.clj +++ b/src/clojure/contrib/except/except.clj @@ -8,55 +8,72 @@ ;; ;; except.clj ;; +;; Provides functions that make it easy to specify the class and message +;; when throwing an Exception or Error. The optional message is formatted +;; using clojure/format. +;; ;; scgilardi (gmail) ;; Created 07 July 2008 (ns clojure.contrib.except (:import (clojure.lang Reflector))) -(declare throw-formatted) +(declare throwable) (defn throwf - "Throws a formatted Exception or Error with an optional message formatted - like clojure/printf. All arguments are optional: + "Throws an Exception or Error with an optional message formatted using + clojure/format. All arguments are optional: class? format? format-args* - - class defaults to Exception + - class defaults to Exception, if present it must name a kind of + Throwable - format is a format string for clojure/format - - format-args are objects that correspond format specifiers in format." + - format-args are objects that correspond to format specifiers in + format." [& args] - (apply throw-formatted "clojure.contrib.except.throwf" args)) + (throw (throwable args))) (defn throw-if - "Throws a formatted Exception or Error if test is true. args are those - documented for throwf." + "Throws an Exception or Error if test is true. args are those documented + for throwf." [test & args] (when test - (apply throw-formatted "clojure.contrib.except.throw_if" args))) + (throw (throwable args)))) ;; throw-if-not is synonymous with assert, but clojure/assert exists (defn throw-if-not - "Throws a formatted Exception or Error if test is false. args are those - documented for throwf." + "Throws an Exception or Error if test is false. args are those documented + for throwf." [test & args] (when-not test - (apply throw-formatted "clojure.contrib.except.throw_if_not" args))) - -(defn- throw-formatted - "Internal helper for formatted exceptions. It builds the formatted message, - creates the exception object, and edits the exception's stack trace to - exclude frames that are internal to our implementation. The stack trace - will start with the line in the caller that contains the throwf, - throw-if, or throw-if-not call." - [fn-prefix & args] - (let [[class & [fmt & fmt-args]] - (if (class? (first args)) args (cons Exception args)) - args (into-array (if fmt [(apply format fmt fmt-args)] [])) - exception (Reflector/invokeConstructor class args) - raw-trace (.getStackTrace exception) - not-our-fn? #(not (.startsWith (.getClassName %) fn-prefix)) - trace (into-array (rrest (drop-while not-our-fn? raw-trace)))] - (.setStackTrace exception trace) - (throw exception))) + (throw (throwable args)))) + +(defn throw-arg + "Throws an IllegalArgumentException. All arguments are optional: + + format? format-args* + + - format is a format string for clojure/format + - format-args are objects that correspond to format specifiers in + format." + [& args] + (throw (throwable (cons IllegalArgumentException args)))) + +(defn- throwable + "Constructs a Throwable with an optional formatted message. Its stack + trace will begin with our caller's caller. Args are as described for + throwf except throwable accepts them as list rather than inline." + [args] + (let [[class & [fmt & fmt-args]] (if (class? (first args)) + args + (cons Exception args)) + ctor-args (into-array (if fmt [(apply format fmt fmt-args)] [])) + throwable (Reflector/invokeConstructor class ctor-args) + our-prefix "clojure.contrib.except.throwable" + not-us? #(not (.startsWith (.getClassName %) our-prefix)) + raw-trace (.getStackTrace throwable) + edited-trace (into-array (drop 3 (drop-while not-us? raw-trace)))] + (.setStackTrace throwable edited-trace) + throwable)) |