-
Notifications
You must be signed in to change notification settings - Fork 0
/
stashing.clj
68 lines (61 loc) · 1.99 KB
/
stashing.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
(ns com.gfredericks.repl.stashing)
(defn ^:private enqueue-max
[q max x]
(let [q' (conj q x)]
(cond-> q'
(> (count q') max)
(pop))))
(defn ^:private all-vars
[ns]
(->> (ns-map ns)
(vals)
(filter var?)
(filter #(= ns (.ns ^clojure.lang.Var %)))))
(def ^:private empty-stash
{:returned clojure.lang.PersistentQueue/EMPTY
:caught clojure.lang.PersistentQueue/EMPTY})
(defn stash-everything!
"Stashes args, return values, and exceptions thrown for all of the
fuctions defined in the current namespace."
[]
(doseq [v (all-vars *ns*)
:when (fn? @v)
:let [tracking (atom empty-stash)]]
(alter-meta! v assoc ::stash tracking)
(alter-var-root v
(fn [orig]
(fn [& args]
(try
(let [ret (apply orig args)]
(swap! tracking update-in [:returned] enqueue-max 10
{:args args :return ret :at (java.util.Date.)})
ret)
(catch Throwable t
(swap! tracking update-in [:caught] enqueue-max 10
{:args args :ex t :at (java.util.Date.)})
(throw t))))))))
(defn get-stash
[a-var]
(let [{:keys [returned caught]} (-> a-var meta ::stash deref)]
;; converting to seq since queue's don't print well :/
{:returned (seq returned)
:caught (seq caught)}))
(defn stashed-exceptions
"Returns all stashed exceptions in all namespaces, in the order they
were thrown."
[]
(->> (all-ns)
(mapcat all-vars)
(keep #(::stash (meta %)))
(mapcat #(:caught (deref %)))
(sort-by :at)
(map :ex)
(distinct)))
(defn clear-all-stashes!
"Clears all stashes in all namespaces"
[]
(doseq [ns (all-ns)
var (all-vars ns)
:let [stash (::stash (meta var))]
:when stash]
(reset! stash empty-stash)))