Permalink
...
Checking mergeability…
Don’t worry, you can still create the pull request.
Comparing changes
Open a pull request
- 7 commits
- 6 files changed
- 0 commit comments
- 1 contributor
Commits on Jan 04, 2012
|
|
technomancy |
c390372
|
|||
|
|
technomancy |
18a0132
|
|||
|
|
technomancy |
6db3a37
|
|||
|
|
technomancy |
a002c14
|
|||
|
|
technomancy |
7506087
|
|||
|
|
technomancy |
f289279
|
Commits on Jan 05, 2012
|
|
technomancy |
1ff7ca4
|
Unified
Split
Showing
with
69 additions
and 42 deletions.
- +13 −6 README.md
- +2 −2 src/clj_stacktrace/core.clj
- +22 −19 src/clj_stacktrace/repl.clj
- +16 −0 src/clj_stacktrace/utils.clj
- +5 −6 src/leiningen/hooks/clj_stacktrace_test.clj
- +11 −9 test/clj_stacktrace/repl_test.clj
View
19
README.md
| @@ -7,6 +7,8 @@ For example, to print a nice stack trace in a REPL: | ||
| => (use 'clj-stacktrace.repl) | ||
| => ("foo") | ||
| java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0) | ||
| + => (pst) | ||
| + java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0) | ||
| Compiler.java:5440 clojure.lang.Compiler.eval | ||
| Compiler.java:5391 clojure.lang.Compiler.eval | ||
| core.clj:2382 clojure.core/eval | ||
| @@ -25,18 +27,23 @@ For example, to print a nice stack trace in a REPL: | ||
| NO_SOURCE_FILE:2 user/eval100 | ||
| Compiler.java:5424 clojure.lang.Compiler.eval | ||
| - | ||
| In stack traces printed by `pst`: | ||
| -* Java methods are described with the usual `name.space.ClassName.methodName` convention and Clojure functions with their own `name.space/function-name` convention. | ||
| -* Anonymous clojure functions are denoted by adding an `[fn]` to their enclosing, named function. | ||
| +* Java methods are described with the usual | ||
| + `name.space.ClassName.methodName` convention and Clojure functions | ||
| + with their own `name.space/function-name` convention. | ||
| +* Anonymous clojure functions are denoted by adding an `[fn]` to their | ||
| + enclosing, named function. | ||
| * "Caused by" cascades are shown as in regular java stack traces. | ||
| * Elements are vertically aligned for better readability. | ||
| * Printing is directed to `*out*`. | ||
| -If you want to direct the printing to somewhere other than `*out*`, either use `pst-on` to specify the output location or `pst-str` to capture the printing as a string. | ||
| +If you want to direct the printing to somewhere other than `*out*`, | ||
| +either use `pst-on` to specify the output location. | ||
| -The library also offers an API for programatically 'parsing' exceptions. This API is used internal for `pst` and can be used to e.g. improve development tools. Try for example: | ||
| +The library also offers an API for programatically 'parsing' | ||
| +exceptions. This API is used internal for `pst` and can be used to | ||
| +e.g. improve development tools. Try for example: | ||
| ```clj | ||
| (use 'clj-stacktrace.core) | ||
| @@ -46,7 +53,7 @@ The library also offers an API for programatically 'parsing' exceptions. This AP | ||
| (parse-exception e))) | ||
| ``` | ||
| -If you use Leiningen, you can install clj-stacktrace on a per-user basis: | ||
| +If you use Leiningen, you can install clj-stacktrace on a user-level basis: | ||
| $ lein plugin install clj-stacktrace 0.2.4 | ||
View
4
src/clj_stacktrace/core.clj
| @@ -76,7 +76,7 @@ | ||
| :method (.getMethodName elem))))) | ||
| (defn parse-trace-elems | ||
| - "Returns a seq of maps providing usefull information about the java stack | ||
| + "Returns a seq of maps providing useful information about the java stack | ||
| trace elements. See parse-trace-elem." | ||
| [elems] | ||
| (map parse-trace-elem elems)) | ||
| @@ -110,7 +110,7 @@ | ||
| base))) | ||
| (defn parse-exception | ||
| - "Returns a Clojure map providing usefull informaiton about the exception. | ||
| + "Returns a Clojure map providing useful information about the exception. | ||
| The map has keys | ||
| :class Class of the exception. | ||
| :message Regular exception message string. | ||
View
41
src/clj_stacktrace/repl.clj
| @@ -1,6 +1,6 @@ | ||
| (ns clj-stacktrace.repl | ||
| - (:use clj-stacktrace.core) | ||
| - (:require [clj-stacktrace.utils :as utils])) | ||
| + (:use [clj-stacktrace.core :only [parse-exception]] | ||
| + [clj-stacktrace.utils :only [omit-frames fence rjust]])) | ||
| (def color-codes | ||
| {:red "\033[31m" | ||
| @@ -59,16 +59,14 @@ | ||
| (defn pst-elem-str | ||
| [color? parsed-elem print-width] | ||
| (colored color? (elem-color parsed-elem) | ||
| - (str (utils/rjust print-width (source-str parsed-elem)) | ||
| + (str (rjust print-width (source-str parsed-elem)) | ||
| " " (method-str parsed-elem)))) | ||
| (defn pst-elems-on | ||
| [^java.io.Writer on color? parsed-elems & [source-width]] | ||
| (let [print-width (+ 6 (or source-width | ||
| - (utils/fence | ||
| - (sort | ||
| - (map #(.length ^String %) | ||
| - (map source-str parsed-elems))))))] | ||
| + (fence (sort (for [elem parsed-elems] | ||
| + (count (source-str elem)))))))] | ||
| (doseq [parsed-elem parsed-elems] | ||
| (.append on ^String (pst-elem-str color? parsed-elem print-width)) | ||
| (.append on "\n") | ||
| @@ -80,11 +78,12 @@ | ||
| (.flush on)) | ||
| (defn- pst-cause-on | ||
| - [^java.io.Writer on color? exec source-width] | ||
| + [^java.io.Writer on exec {:keys [source-width omit color?]}] | ||
| (pst-caused-by-on on color?) | ||
| (pst-class-on on color? (:class exec)) | ||
| (pst-message-on on color? (:message exec)) | ||
| - (pst-elems-on on color? (:trimmed-elems exec) source-width) | ||
| + (pst-elems-on on color? (omit-frames (:trimmed-elems exec) omit) | ||
| + source-width) | ||
| (if-let [cause (:cause exec)] | ||
| (pst-cause-on on color? cause source-width))) | ||
| @@ -94,29 +93,33 @@ | ||
| [excp] | ||
| (let [this-source-width (->> (:trace-elems excp) | ||
| (map (comp count source-str)) | ||
| - (sort) | ||
| - (utils/fence))] | ||
| + (sort) (fence))] | ||
| (if-let [cause (:cause excp)] | ||
| (max this-source-width (find-source-width cause)) | ||
| this-source-width))) | ||
| -(defn pst-on [on color? e] | ||
| +(defn pst-on | ||
| "Prints to the given Writer on a pretty stack trace for the given exception e, | ||
| ANSI colored if color? is true." | ||
| + [on e {:keys [omit color?] :as opts}] | ||
| (let [exec (parse-exception e) | ||
| - source-width (find-source-width exec)] | ||
| + source-width (find-source-width exec) | ||
| + color? (or color? (:color? opts) (:test-color opts))] | ||
| (pst-class-on on color? (:class exec)) | ||
| (pst-message-on on color? (:message exec)) | ||
| - (pst-elems-on on color? (:trace-elems exec) source-width) | ||
| + (pst-elems-on on color? (omit-frames (:trace-elems exec) omit) source-width) | ||
| (if-let [cause (:cause exec)] | ||
| - (pst-cause-on on color? cause source-width)))) | ||
| + (pst-cause-on on cause | ||
| + (assoc opts | ||
| + :source-width source-width | ||
| + :color? color?))))) | ||
| (defn pst | ||
| "Print to *out* a pretty stack trace for an exception, by default *e." | ||
| - [& [e]] | ||
| - (pst-on *out* false (or e *e))) | ||
| + [& [e & {:as opts}]] | ||
| + (pst-on *out* (or e *e) opts)) | ||
| (defn pst+ | ||
| "Like pst, but with ANSI terminal color coding." | ||
| - [& [e]] | ||
| - (pst-on *out* true (or e *e))) | ||
| + [& [e & {:as opts}]] | ||
| + (pst-on *out* (or e *e) (assoc opts :color? true))) | ||
View
16
src/clj_stacktrace/utils.clj
| @@ -37,3 +37,19 @@ | ||
| q3 (quartile3 coll) | ||
| iqr (- q3 q1)] | ||
| (int (+ q3 (/ (* 3 iqr) 2))))) | ||
| + | ||
| +(defn- omitter-fn [to-omit] | ||
| + (if (instance? java.util.regex.Pattern to-omit) | ||
| + ;; Curse you, non ifn regexes! | ||
| + (comp (partial re-find to-omit) pr-str) | ||
| + to-omit)) | ||
| + | ||
| +(defn omit-frames | ||
| + "Remove frames matching to-omit, which can be a function or regex." | ||
| + [trace-elems to-omit] | ||
| + (if-let [omit? (omitter-fn to-omit)] | ||
| + (reduce (fn [trace-elems elem] | ||
| + (if (omit? elem) | ||
| + trace-elems | ||
| + (conj trace-elems elem))) [] trace-elems) | ||
| + trace-elems)) | ||
View
11
src/leiningen/hooks/clj_stacktrace_test.clj
| @@ -3,12 +3,11 @@ | ||
| [robert.hooke :only [add-hook]])) | ||
| (defn- hook-form [form project] | ||
| - (let [pst (if (:test-color (:clj-stacktrace project)) | ||
| - 'clj-stacktrace.repl/pst+ | ||
| - 'clj-stacktrace.repl/pst)] | ||
| - `(do (alter-var-root (resolve '~'clojure.stacktrace/print-cause-trace) | ||
| - (constantly @(resolve '~pst))) | ||
| - ~form))) | ||
| + `(do (alter-var-root (resolve '~'clojure.stacktrace/print-cause-trace) | ||
| + (constantly (fn [e#] | ||
| + (@(resolve '~'pst) e# | ||
| + ~(:clj-stacktrace project))))) | ||
| + ~form)) | ||
| (defn- add-stacktrace-hook [eval-in-project project form & [h s init]] | ||
| (eval-in-project project (hook-form form project) | ||
View
20
test/clj_stacktrace/repl_test.clj
| @@ -1,7 +1,6 @@ | ||
| (ns clj-stacktrace.repl-test | ||
| - (:use clojure.test) | ||
| - (:use clj-stacktrace.utils) | ||
| - (:use clj-stacktrace.repl)) | ||
| + (:use [clojure.test] | ||
| + [clj-stacktrace.repl])) | ||
| (defmacro with-cascading-exception | ||
| "Execute body in the context of a variable bound to an exception instance | ||
| @@ -18,14 +17,17 @@ | ||
| (binding [*e e] | ||
| (is (with-out-str (pst)))))) | ||
| -(deftest test-pst-str | ||
| - (with-cascading-exception e | ||
| - (is (pst-str e)) | ||
| - (binding [*e e] | ||
| - (is (pst-str))))) | ||
| - | ||
| (deftest test-pst+ | ||
| (with-cascading-exception e | ||
| (is (with-out-str (pst+ e))) | ||
| (binding [*e e] | ||
| (is (with-out-str (pst+)))))) | ||
| + | ||
| +(deftest test-omit | ||
| + (with-cascading-exception e | ||
| + (is (not (re-find #"repl-test" (with-out-str | ||
| + (pst e :omit #"repl-test"))))) | ||
| + (is (not (re-find #"Compiler.java" | ||
| + (with-out-str | ||
| + (pst e :omit (fn [e] | ||
| + (= "Compiler.java" (:file e)))))))))) | ||