Skip to content

Commit 0a082e9

Browse files
committed
0.2.0 Support init-less workflow (closes #4)
1 parent 1745943 commit 0a082e9

File tree

9 files changed

+107
-7
lines changed

9 files changed

+107
-7
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# 0.2.0 - Feb 23, 2024
2+
3+
Support optional “init-less” workflow:
4+
5+
- Initialize by default with all dirs on classpath
6+
- Support `:clj-reload/no-reload` and `:clj-reload/no-unload` meta on ns
7+
18
# 0.1.3 - Feb 21, 2024
29

310
- Support namespaces defined in multiple files #3

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This is only about namespace dependencies within a single project. It has nothin
77
## Dependency
88

99
```clojure
10-
io.github.tonsky/clj-reload {:mvn/version "0.1.3"}
10+
io.github.tonsky/clj-reload {:mvn/version "0.2.0"}
1111
```
1212

1313
## The problem
@@ -227,6 +227,22 @@ Why is this important? With `tools.namespace` you will structure your code in a
227227

228228
Simply put: the fact that you use `clj-reload` during development does not spill into your production code.
229229

230+
## Usage: init-less workflow
231+
232+
Sometimes it might be useful to integrate `clj-reload` into your system-wide profile or into tool like CIDER to be available in all your projects without explicitly adding it as a dependency.
233+
234+
To support that, `clj-reload`:
235+
236+
- Lets you skip `init`, in which case it’ll initialize with every directory it can find on classpath,
237+
- Supports `:clj-reload/no-reload` and `:clj-reload/no-unload` meta on namespace symbol, like this:
238+
239+
```
240+
(ns ^:clj-reload/no-reload no-reload
241+
(:require ...))
242+
```
243+
244+
In that case, you can just call `clj-reload.core/reload` and it should work with default settings.
245+
230246
## Comparison: Evaluating buffer
231247

232248
The simplest way to reload Clojure code is just re-evaluating an entire buffer.

fixtures/core_test/no_reload.clj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(ns ^:clj-reload/no-reload no-reload)
2+
3+
(def rand1
4+
(rand-int Integer/MAX_VALUE))

fixtures/core_test/no_unload.clj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(ns ^:clj-reload/no-unload no-unload)
2+
3+
(def rand1
4+
(rand-int Integer/MAX_VALUE))
5+
6+
(def rand2
7+
(rand-int Integer/MAX_VALUE))

src/clj_reload/core.clj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
; NS :: {:ns-files #{<file> ...} - files containing (ns ...) declaration
3131
; :in-ns-files #{<file> ...} - files containing (in-ns ...) declaration
3232
; :requires #{<symbol> ...} - other nses this depends on
33+
; :meta {} - metadata from ns symbol
3334
; :keep {<symbol> -> Keep}}} - vars to keep between reloads
3435
;
3536
; Keep :: {:tag <symbol> - type of value ('def, 'defonce etc)
@@ -170,6 +171,8 @@
170171

171172
unload? #(and
172173
(loaded %)
174+
(not (:clj-reload/no-unload (:meta (namespaces %))))
175+
(not (:clj-reload/no-reload (:meta (namespaces %))))
173176
(not (no-unload %))
174177
(not (no-reload %)))
175178
deps (parse/dependees namespaces)
@@ -184,6 +187,7 @@
184187

185188
load? #(and
186189
(loaded %)
190+
(not (:clj-reload/no-reload (:meta (namespaces %))))
187191
(not (no-reload %))
188192
(namespaces' %))
189193
deps' (parse/dependees namespaces')
@@ -329,3 +333,9 @@
329333

330334
(defmethod keep-methods 'defprotocol [_]
331335
keep/keep-methods-defprotocol)
336+
337+
;; Initialize with classpath-dirs to support “init-less” workflow
338+
;; See https://github.com/tonsky/clj-reload/pull/4
339+
;; and https://github.com/clojure-emacs/cider-nrepl/issues/849
340+
(init
341+
{:dirs (util/classpath-dirs)})

src/clj_reload/parse.clj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@
8787

8888
(= 'ns tag)
8989
(let [[ns requires] (parse-ns-form form)]
90-
(recur ns(update nses ns util/assoc-some
91-
:requires requires
92-
:ns-files (util/some-set file))))
90+
(recur ns (update nses ns util/assoc-some
91+
:meta (meta ns)
92+
:requires requires
93+
:ns-files (util/some-set file))))
9394

9495
(= 'in-ns tag)
9596
(let [[_ ns] (expand-quotes form)]

src/clj_reload/util.clj

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
[clojure.string :as str])
55
(:import
66
[clojure.lang LineNumberingPushbackReader]
7-
[java.io File StringReader]))
7+
[java.io File StringReader]
8+
[java.net URLClassLoader]))
89

910
(def ^:dynamic *log-fn*
1011
println)
@@ -93,6 +94,9 @@
9394
(defn file? [^File f]
9495
(some-> f .isFile))
9596

97+
(defn directory? [^File f]
98+
(some-> f .isDirectory))
99+
96100
(defn file-name [^File f]
97101
(some-> f .getName))
98102

@@ -114,3 +118,29 @@
114118
(let [[_ ext] (re-matches #".*\.([^.]+)" (.getName file))
115119
path (-> ns str (str/replace #"\-" "_") (str/replace #"\." "/") (str "." ext))]
116120
(Compiler/load (StringReader. content) path (.getName file))))
121+
122+
(defn loader-classpath []
123+
(->> (clojure.lang.RT/baseLoader)
124+
(iterate #(.getParent ^ClassLoader %))
125+
(take-while identity)
126+
(filter #(instance? URLClassLoader %))
127+
(mapcat #(.getURLs ^URLClassLoader %))
128+
(map io/as-file)
129+
(filter directory?)))
130+
131+
(defn system-classpath []
132+
(-> (System/getProperty "java.class.path")
133+
(str/split (re-pattern (System/getProperty "path.separator")))
134+
(->> (map io/as-file)
135+
(filter directory?))))
136+
137+
(defn classpath-dirs []
138+
(->> (or
139+
(not-empty (loader-classpath))
140+
(not-empty (system-classpath)))
141+
(distinct)
142+
(mapv file-path)))
143+
144+
(comment
145+
(classpath-dirs)
146+
(system-classpath))

test/clj_reload/core_test.clj

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[clojure.test :refer [is are deftest testing use-fixtures]]))
88

99
(defn reset []
10-
(tu/reset '[two-nses-second two-nses split o n m l i j k f a g h d c e double b]))
10+
(tu/reset '[two-nses-second two-nses split o n no-unload m l i j k f a g h d c e double b]))
1111

1212
(defn wrap-test [f]
1313
(binding [tu/*dir* "fixtures/core_test"]
@@ -136,7 +136,7 @@
136136
(deftest reload-all-test
137137
(tu/with-deleted 'err-runtime
138138
(is (= '["Unloading" two-nses-second two-nses split m n o l i j k h f g a d c e double b
139-
"Loading" b double double e c d a g f h k j i l o n m split two-nses two-nses-second]
139+
"Loading" b double double e c d a g f h k j i l no-unload o n m split two-nses two-nses-second]
140140
(modify {:require '[] :only :all})))))
141141

142142
(deftest reload-exception-test
@@ -272,3 +272,25 @@
272272
(is (= '["Unloading" m n o "Loading" o n " failed to load" n] (tu/trace))))
273273
(tu/reload)
274274
(is (= '["Unloading" n "Loading" n m] (tu/trace))))
275+
276+
(deftest no-unload-meta-test
277+
(tu/init 'no-unload)
278+
(let [rand1 @(resolve 'no-unload/rand1)
279+
rand2 @(resolve 'no-unload/rand2)]
280+
(tu/with-changed 'no-unload #ml "(ns ^:clj-reload/no-unload no-unload)
281+
282+
(def rand1
283+
(rand-int Integer/MAX_VALUE))"
284+
(tu/reload)
285+
(let [rand1' @(resolve 'no-unload/rand1)
286+
rand2' @(resolve 'no-unload/rand2)]
287+
(is (not= rand1' rand1))
288+
(is (= rand2' rand2))))))
289+
290+
(deftest no-reload-meta-test
291+
(tu/init 'no-reload)
292+
(let [rand1 @(resolve 'no-reload/rand1)
293+
_ (tu/touch 'no-reload)
294+
_ (tu/reload)
295+
rand1' @(resolve 'no-reload/rand1)]
296+
(is (= rand1' rand1))))

test/clj_reload/parse_test.clj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
(is (= '{x nil}
5555
(read-str "(ns x)")))
5656

57+
(is (= '{x {:meta {:clj-reload/no-reload true}}}
58+
(read-str "(ns ^:clj-reload/no-reload x)")))
59+
5760
(is (= '{x nil}
5861
(read-str "(in-ns 'x)"))))
5962

0 commit comments

Comments
 (0)