Mercurial > lasercutter
view src/clojure/contrib/condition.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 ;; Copyright (c) Stephen C. Gilardi. All rights reserved. The use and2 ;; distribution terms for this software are covered by the Eclipse Public3 ;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can4 ;; be found in the file epl-v10.html at the root of this distribution. By5 ;; using this software in any fashion, you are agreeing to be bound by the6 ;; terms of this license. You must not remove this notice, or any other,7 ;; from this software.8 ;;9 ;; condition.clj10 ;;11 ;; scgilardi (gmail)12 ;; Created 09 June 200914 (ns ^{:author "Stephen C. Gilardi"15 :doc "Flexible raising and handling of conditions:17 Functions:19 raise: raises a condition20 handler-case: dispatches raised conditions to appropriate handlers21 print-stack-trace: prints abbreviated or full condition stack traces23 Data:25 A condition is a map containing values for these keys:27 - :type, a condition type specifier, typically a keyword28 - :stack-trace, a stack trace to the site of the raise29 - :message, a human-readable message (optional)30 - :cause, a wrapped exception or condition (optional)31 - other keys given as arguments to raise (optional)33 Note: requires AOT compilation.35 Based on an idea from Chouser:36 http://groups.google.com/group/clojure/browse_frm/thread/da1285c538f22bb5"}37 clojure.contrib.condition38 (:require clojure.contrib.condition.Condition)39 (:import clojure.contrib.condition.Condition40 clojure.lang.IPersistentMap)41 (:use (clojure.contrib42 [def :only (defvar)]43 [seq :only (separate)])))45 (defvar *condition*46 "While a handler is running, bound to the condition being handled")48 (defvar *selector*49 "While a handler is running, bound to the selector returned by the50 handler-case dispatch-fn for *condition*")52 (defvar *condition-object*53 "While a handler is running, bound to the Condition object whose metadata54 is the condition")56 (defvar *full-stack-traces* false57 "Bind to true to include clojure.{core,lang,main} frames in stack58 traces")60 (defmacro raise61 "Raises a condition. With no arguments, re-raises the current condition.62 With one argument (a map), raises the argument. With two or more63 arguments, raises a map with keys and values from the arguments."64 ([]65 `(throw *condition-object*))66 ([m]67 `(throw (Condition. ~m)))68 ([key val & keyvals]69 `(raise (hash-map ~key ~val ~@keyvals))))71 (defmacro handler-case72 "Executes body in a context where raised conditions can be handled.74 dispatch-fn accepts a raised condition (a map) and returns a selector75 used to choose a handler. Commonly, dispatch-fn will be :type to dispatch76 on the condition's :type value.78 Handlers are forms within body:80 (handle key81 ...)83 If a condition is raised, executes the body of the first handler whose84 key satisfies (isa? selector key). If no handlers match, re-raises the85 condition.87 While a handler is running, *condition* is bound to the condition being88 handled and *selector* is bound to to the value returned by dispatch-fn89 that matched the handler's key."90 [dispatch-fn & body]91 (let [[handlers code]92 (separate #(and (list? %) (= 'handle (first %))) body)]93 `(try94 ~@code95 (catch Condition c#96 (binding [*condition-object* c#97 *condition* (meta c#)98 *selector* (~dispatch-fn (meta c#))]99 (cond100 ~@(mapcat101 (fn [[_ key & body]]102 `[(isa? *selector* ~key) (do ~@body)])103 handlers)104 :else (raise)))))))106 (defmulti stack-trace-info107 "Returns header, stack-trace, and cause info from conditions and108 Throwables"109 class)111 (defmethod stack-trace-info IPersistentMap112 [condition]113 [(format "condition: %s, %s" (:type condition)114 (dissoc condition :type :stack-trace :cause))115 (:stack-trace condition)116 (:cause condition)])118 (defmethod stack-trace-info Condition119 [condition]120 (stack-trace-info (meta condition)))122 (defmethod stack-trace-info Throwable123 [throwable]124 [(str throwable)125 (.getStackTrace throwable)126 (.getCause throwable)])128 (defn print-stack-trace129 "Prints a stack trace for a condition or Throwable. Skips frames for130 classes in clojure.{core,lang,main} unless the *full-stack-traces* is131 bound to logical true"132 [x]133 (let [[header frames cause] (stack-trace-info x)]134 (printf "%s\n" header)135 (doseq [frame frames]136 (let [classname (.getClassName frame)]137 (if (or *full-stack-traces*138 (not (re-matches139 #"clojure.(?:core|lang|main).*" classname)))140 (printf " at %s/%s(%s:%s)\n"141 classname142 (.getMethodName frame)143 (.getFileName frame)144 (.getLineNumber frame)))))145 (when cause146 (printf "caused by: ")147 (recur cause))))