-
Notifications
You must be signed in to change notification settings - Fork 0
/
repl.clj
229 lines (175 loc) · 5.32 KB
/
repl.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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
(ns ^{:clojure.tools.namespace.repl/load false} rumble.repl
(:refer-clojure :exclude [find-ns])
(:require
[clojure.pprint]
[clojure.repl]
[clojure.string :as str]
[clojure.tools.namespace.find :as ns.find]
[clojure.tools.namespace.repl :as ns.repl]
[kaocha.repl])
(:import
(java.io
File)))
(ns.repl/disable-reload! *ns*)
(defn pp
"Alias for pprint, but returns passed in data"
[thing]
(clojure.pprint/pprint thing)
thing)
(defn help [& _n]
(println (str ";; in ns " 'rumble.repl))
(->> (ns-publics 'rumble.repl)
(sort-by (fn [[_ v]] (str v)))
(mapv (fn [[_k v]]
(printf ";; %s - %s %s\n" (.replaceAll (str v) "#'" "")
(:arglists (meta v))
(:doc (meta v))))))
::ok)
(defn- init!
"Initialize the helper namespace"
[]
(ns.repl/disable-reload! *ns*)
(ns.repl/set-refresh-dirs "src" "test")
(help))
(defn list-ns
"Return list of symbols of namespaces found in src dir. Default: ./src"
([root]
(ns.find/find-namespaces-in-dir (File. root)))
([]
(list-ns "./src/")))
(defn find-ns
"Find namespace vars by a regex"
[re]
(let [nss (vec (filter #(re-find re (str %)) (list-ns)))]
(printf ";; found %s ns\n" (count nss))
(when (<= (count nss) 10)
(for [n nss]
(printf ";; %s\n" n)))
nss))
(defn find-test-ns
"Find test namespace vars by a regex"
[pattern]
(let [re (cond
(string? pattern) (re-pattern pattern)
(= java.util.regex.Pattern (class pattern)) pattern
:else (throw (ex-info "this is not a patternable thing" {:pattern pattern})))
nss (vec (filter #(re-find re (str %)) (list-ns "./test/")))]
(printf ";; found %s nss\n" (count nss))
(when (<= (count nss) 10)
(for [n nss]
(printf ";; %s\n" n)))
nss))
(def ^:private system-status (atom {}))
(defn safe-to-refresh?
"Check if refresh is safe, by verifying that application system is not running"
[]
(or (empty? @system-status)
(= #{false} (-> @system-status vals set))))
(defn refresh
"Refresh changed namespaces, only if its safe"
[]
(if (safe-to-refresh?)
(ns.repl/refresh)
::system-running!))
(defn refresh-all
"Refresh everything, only if its safe"
[]
(if (safe-to-refresh?)
(ns.repl/refresh-all)
::system-running!))
(defn start-system!
"Given a namespace, usually some-service, do the following:
- find some-service.user namespace (by convention)
- refresh
- require the user ns e.g. some-service.user
- start system, invoking somer-service.user/start
Warning: best if the system is not running, or things will go south
Example: (rumble.repl/start-system! 'foo.user)"
([]
;; automagically guess the <app>.user namespace
(let [an-ns (-> *ns*
str
(str/replace #"\..+" ".user")
symbol)]
(require an-ns)
(start-system! an-ns)))
([an-ns]
(printf ";; Starting %s\n" an-ns)
(when (= "rumble.repl" (str an-ns))
(throw (ex-info "nope" {:ns (str an-ns)})))
(if (get @system-status an-ns)
(println ";; System possibly running" an-ns)
(do
(println ";; Refreshing and reloading " an-ns)
(remove-ns an-ns)
(refresh)
(require [an-ns] :reload)
(when-let [f (ns-resolve an-ns 'start)]
(f)
(swap! system-status (fn [s] (assoc s an-ns true))))))))
(defn stop-system!
"Given a namespace, usually some-service.user, stop the system. If not passed, stops currently running system"
([]
(stop-system! (first (keys @system-status))))
([an-ns]
(let [f (ns-resolve an-ns 'stop)]
(f)
(swap! system-status (fn [s] (assoc s an-ns false))))))
(defn restart-system!
"Restarts the system with an optiona reload"
[]
(when (stop-system!)
(start-system!)))
(defn sys
"Pull out the system for passing around"
[]
(var-get (ns-resolve (first (keys @system-status)) 'SYS)))
(defn c
"Pul out a compont from a running system, pass keyword for the component name"
[component-name]
(let [sys (sys)]
(get sys component-name)))
(def ^:private kaocha-conf {:config (System/getenv "KAOCHA_CONFIG")})
(defn t
"Run tests via kaocha - either all or a list of vars. WILL NOT REFRESH"
([]
(kaocha.repl/run :unit kaocha-conf))
([ns-list]
(apply kaocha.repl/run (flatten [ns-list [kaocha-conf]]))))
(defn t!
"Run tests via kaocha, but refresh first - runs all tests or a list (or one) of ns vars"
([]
(refresh)
(kaocha.repl/run :unit kaocha-conf))
([& ns-list]
(refresh)
(apply kaocha.repl/run (flatten [ns-list [kaocha-conf]]))))
(defn clear-aliases
"Reset aliases for given ns or current if no args given"
([]
(clear-aliases *ns*))
([an-ns]
(mapv #(ns-unalias an-ns %) (keys (ns-aliases an-ns)))))
;; Tap helpers
(def ^:private tap-log (atom []))
(def ^:private tap-ref (atom nil))
(defn tap-log-init!
"Initialize a tap> listener and store the ref to it"
[]
(reset! tap-ref (add-tap (fn [input]
(swap! tap-log conj input)))))
(defn tap-log-get
"Return tap logged data"
[]
@tap-log)
(defn tap-log-reset!
"Clear the log"
[]
(reset! tap-log []))
(defn tap-log-stop!
"Clear tap log and remove the listener"
[]
(remove-tap @tap-ref)
(tap-log-reset!)
(reset! tap-ref nil))
(init!)