diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clojure/contrib/except/except.clj | 76 |
1 files changed, 41 insertions, 35 deletions
diff --git a/src/clojure/contrib/except/except.clj b/src/clojure/contrib/except/except.clj index ce4003ff..d6dd62d9 100644 --- a/src/clojure/contrib/except/except.clj +++ b/src/clojure/contrib/except/except.clj @@ -11,46 +11,52 @@ ;; scgilardi (gmail) ;; Created 07 July 2008 -(ns clojure.contrib.except) +(ns clojure.contrib.except + (:import (clojure.lang Reflector))) -(defn throwf - "Throws an exception with a message formatted like printf. Arguments are: - - class? format format-args* +(declare throw-formatted) - class is optional and defaults to Exception. If present, it must be a - Class in the tree under Throwable with a constructor that takes a single - String. +(defn throwf + "Throws a formatted Exception or Error with an optional message formatted + like clojure/printf. All arguments are optional: - format is a string as documented for java.util.Formatter. + class? format? format-args* - format-args are zero or more objects that correspond to the format - specifiers in format." + - class defaults to Exception + - format is a format string for clojure/format + - format-args are objects that correspond format specifiers in format." [& args] - (let [[class fmt & fmt-args] - (if (instance? Class (first args)) args (cons Exception args)) - ctor (.getConstructor (identity class) (into-array [String])) - message (apply format fmt fmt-args) - exception (.newInstance ctor (into-array [message])) + (apply throw-formatted "clojure.contrib.except.throwf" args)) + +(defn throw-if + "Throws a formatted 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-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." + [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) - boring? #(not= (.getMethodName %) "doInvoke") - trace (into-array (drop 2 (drop-while boring? raw-trace)))] + not-our-fn? #(not (.startsWith (.getClassName %) fn-prefix)) + trace (into-array (rrest (drop-while not-our-fn? raw-trace)))] (.setStackTrace exception trace) (throw exception))) - -(defn throw-if - "Throws an exception with a message if pred is true. Arguments are: - - pred class? format format-args* - - class is optional and defaults to Exception. If present, it must be a - Class in the tree under Throwable with a constructor that takes a single - String. - - format is a string as documented for java.util.Formatter. - - format-args are zero or more objects that correspond to the format - specifiers in format." - [pred & args] - (when pred - (apply throwf args))) |