Skip to content

Commit c0e9184

Browse files
authored
Add rewrite-clj.zip of-string* and of-file* (#196)
* Add rewrite-clj.zip of-string* and of-file* These new zip API functions are the same as their of-string and of-file counterparts except that they do no auto navigation at all. Closes #189 * usage of deprecated edn functions in user guide switch to of-node functions instead * minor typo in user guide example
1 parent f4d570d commit c0e9184

File tree

7 files changed

+156
-77
lines changed

7 files changed

+156
-77
lines changed

CHANGELOG.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ For a list of breaking changes see link:#v1-breaking[breaking changes].
1616

1717
=== Unreleased
1818

19+
* added new `rewrite-clj.zip` functions `of-string*` and `of-file*`, these are versions of `of-string` and `of-file` that do no auto-navigation
20+
https://github.com/clj-commons/rewrite-clj/issues/189[#189]
21+
(thanks @mainej for the analysis work)
1922
* a lazy sequence now coerces to a rewrite-clj list node https://github.com/clj-commons/rewrite-clj/pull/180[#180] (thanks @borkdude!)
2023
* exceptions thrown while reading now include `:row` and `:col` keys in `ex-data` https://github.com/clj-commons/rewrite-clj/pull/181[#181] (thanks @ferdinand-beyer)
2124
* docs
2225
** a docstring typo fix https://github.com/clj-commons/rewrite-clj/pull/191[#191] (thanks @BTowersCoding!)
2326

27+
2428
=== v1.1.45
2529

2630
* dropped the alpha status

doc/01-user-guide.adoc

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Read link:design/01-merging-rewrite-clj-and-rewrite-cljs.adoc[Merging rewrite-cl
5959
Thanks to @xsc's transfer of rewrite-clj to clj-commons we'll continue on with the rewrite-clj namespace and clojars deploy target.
6060

6161
To upgrade to rewrite-clj v1, update your project dependencies.
62-
If you were using both rewrite-cljs and rewrite-clj v0 in your project you can now drop the rewrite-cljs dependency.
62+
If you were using both rewrite-cljs and rewrite-clj v0 in your project you should now drop the rewrite-cljs dependency.
6363

6464
Rewrite-clj unit tests are run against the current version of ClojureScript and Clojure versions >= v1.8.0.
6565
We recommend that while bumping your rewrite-clj dependency to v1, that you also bump your Clojure and ClojureScript dependencies to current official releases.
@@ -229,8 +229,10 @@ You may want to refer to link:#nodes[rewrite-clj nodes] while reviewing this int
229229
====
230230
The zip location movement functions (`right`, `left`, `up`, `down`, etc) skip over Clojure whitespace nodes and comment nodes.
231231
Remember that Clojure whitespace includes commas.
232-
233232
If you want to navigate over all nodes, use the `+*+` counterparts (`right*`, `left*`, `up*`, `down*`, etc).
233+
234+
Similarily, the zipper creation functions `of-node`, `of-string` and `of-file` automatically skip over the the first Clojure whitespace and comment nodes.
235+
This is usually appropriate, but if you don't want this auto-navigation on create use the `+*+` counterparts `of-node*`, `of-string*`, and `of-file*`.
234236
====
235237

236238
See link:{cljdoc-api-url}/rewrite-clj.zip[zip API docs].
@@ -410,23 +412,23 @@ Let's explore:
410412
(require '[rewrite-clj.zip :as z])
411413
412414
;; Let's contrive an example with multiple top level forms:
413-
(def zloc (z/of-string "(def x 1) (def y [2 3 [4 [5]]])"))
415+
;; Let's contrive an example with multiple top level forms:
416+
(def s "(def x 1) (def y [2 3 [4 [5]]])")
414417
415418
;; Now let's add 100 to all numbers:
416-
(-> zloc
419+
(-> (z/of-string s)
417420
(z/postwalk (fn select [zloc] (number? (z/sexpr zloc)))
418421
(fn visit [zloc] (z/edit zloc + 100)))
419422
z/root-string)
420423
;; => "(def x 101) (def y [2 3 [4 [5]]])"
421424
422425
;; Hmmm... what happened? Only the first number was affected.
423-
;; A new zipper automaticaly navigates to the first non-whitespace/non-comment node.
426+
;; A new zipper created by of-string automaticaly navigates to the first non-whitespace/non-comment node.
424427
;; In our example, this is node (def x 1).
425428
;; Our walk was isolated to current node (def x 1) so that's all that got updated
426429
427-
;; We can adapt to walk all nodes with a movement up to the top level prior to our walk
428-
(-> zloc
429-
z/up
430+
;; We can adapt to walk all nodes by instead using of-string* which does no auto navigation
431+
(-> (z/of-string* s)
430432
(z/postwalk (fn select [zloc] (number? (z/sexpr zloc)))
431433
(fn visit [zloc] (z/edit zloc + 100)))
432434
z/root-string)
@@ -532,7 +534,7 @@ The options passed into the original zipper on creation will not be automaticall
532534
z/down z/right z/right
533535
(z/edit inc)
534536
z/root ;; <- applying changes and getting root node
535-
(z/edn zip-opts) ;; <- pass the original zip-opts on creation of new zipper
537+
(z/of-node zip-opts) ;; <- pass the original zip-opts on creation of new zipper
536538
z/down z/right z/right
537539
(z/edit inc)
538540
(z/root-string))
@@ -547,7 +549,7 @@ The link:#zip-api[zip API] makes use of the parser API to parse Clojure into zip
547549
If your focus is parsing instead of rewriting, you might find this lower level API useful.
548550
Keep in mind that if you forgo the zip API, you forgo niceties such as the automatic handling of whitespace.
549551

550-
You can choose to parse the first, or all forms from a string or a file.footnote:file[]
552+
You can choose to parse the first, or all forms from a string or, if using Clojure, a file.
551553

552554
Here we parse a single form from a string:
553555

@@ -1176,7 +1178,7 @@ For example, if you know namespace and alias info for the code rewrite-clj is op
11761178
The `:auto-resolve` option is accepted in the `opts` map arg for:
11771179

11781180
* The `rewrite-clj.node` namespace functions `sexpr` and `child-sexpr`.
1179-
* The `rewrite-clj.zip` namespace zipper creation functions `edn*`, `edn`, `of-string` and `of-file`.
1181+
* The `rewrite-clj.zip` namespace zipper creation functions `of-node*`, `of-node`, `of-string*`, `of-string`, `of-file*` and `of-file`.
11801182
The resulting zipper will then automatically apply your `:auto-resolve` within any zip operation that makes use of sexpr, namely:
11811183
** `sexpr`
11821184
** `find-value` and `find-next-value` - sexpr is applied to each node to get the "value" for comparison

src/rewrite_clj/zip.cljc

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@
1919
2020
Because this API contains many functions, we offer the following categorized listing:
2121
22-
**Create a zipper**
22+
**Create a zipper and move to first non-whitespace/comment node**
2323
[[of-node]]
24-
[[of-node*]]
2524
[[of-string]]
2625
[[of-file]]
2726
27+
**Create a zipper without skipping any nodes**
28+
[[of-node*]]
29+
[[of-string*]]
30+
[[of-file*]]
31+
2832
**Move**
2933
[[left]]
3034
[[right]]
@@ -225,7 +229,6 @@
225229
"Create and return zipper from a rewrite-clj `node` (likely parsed by [[rewrite-clj.parser]]),
226230
and move to the first non-whitespace/non-comment child. If node is not forms node, is wrapped in forms node
227231
for a consistent root.
228-
229232
Optional `opts` can specify:
230233
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
231234
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
@@ -270,14 +273,28 @@
270273

271274
;; DO NOT EDIT FILE, automatically imported from: rewrite-clj.zip.base
272275
(defn of-string
273-
"Create and return zipper from all forms in Clojure/ClojureScript/EDN string `s`.
276+
"Create and return zipper from all forms in Clojure/ClojureScript/EDN string `s`, and move to the first non-whitespace/non-comment child.
277+
278+
See [[of-string*]] for same but with no automatic move.
274279
275280
Optional `opts` can specify:
276281
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
277282
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
278283
([s] (rewrite-clj.zip.base/of-string s))
279284
([s opts] (rewrite-clj.zip.base/of-string s opts)))
280285

286+
;; DO NOT EDIT FILE, automatically imported from: rewrite-clj.zip.base
287+
(defn ^{:added "1.1.46"} of-string*
288+
"Create and return zipper from all forms in Clojure/ClojureScript/END string `s`, and do no automatic move.
289+
290+
See [[of-string]] for same but with automatic move to first interesting node.
291+
292+
Optional `opts` can specify:
293+
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
294+
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
295+
([s] (rewrite-clj.zip.base/of-string* s))
296+
([s opts] (rewrite-clj.zip.base/of-string* s opts)))
297+
281298
;; DO NOT EDIT FILE, automatically imported from: rewrite-clj.zip.base
282299
(defn ^{:added "0.4.0"} string
283300
"Return string representing the current node in `zloc`."
@@ -797,12 +814,11 @@
797814
798815
When `p?` is not specified `f` is called on all locations.
799816
800-
Note that by default a newly created zipper automatically navigates to the first non-whitespace
801-
node. If you want to be sure to walk all forms in a zipper, you'll want to navigate one up prior to your walk:
817+
To walk all nodes, you'll want to walk from the root node.
818+
You can do this by, for example, using [[of-string*]] instead of [[of-string]].
802819
803820
```Clojure
804-
(-> (zip/of-string \"my clojure forms\")
805-
zip/up
821+
(-> (zip/of-string* \"my clojure forms\")
806822
(zip/prewalk ...))
807823
```
808824
@@ -840,12 +856,11 @@
840856
841857
When `p?` is not specified `f` is called on all locations.
842858
843-
Note that by default a newly created zipper automatically navigates to the first non-whitespace
844-
node. If you want to be sure to walk all forms in a zipper, you'll want to navigate one up prior to your walk:
859+
To walk all nodes, you'll want to walk from the root node.
860+
You can do this by, for example, using [[of-string*]] instead of [[of-string]].
845861
846862
```Clojure
847-
(-> (zip/of-string \"my clojure forms\")
848-
zip/up
863+
(-> (zip/of-string* \"my clojure forms\")
849864
(zip/postwalk ...))
850865
```
851866
@@ -943,14 +958,30 @@
943958

944959
;; DO NOT EDIT FILE, automatically imported from: rewrite-clj.zip.base
945960
(defn of-file
946-
"Create and return zipper from all forms in Clojure/ClojureScript/EDN File `f`.
961+
"Create and return zipper from all forms in Clojure/ClojureScript/EDN File `f`, and move to the first non-whitespace/non-comment child.
962+
963+
See [[of-file*]] for same but with no automatic move.
947964
948965
Optional `opts` can specify:
949966
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
950967
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
951968
([f] (rewrite-clj.zip.base/of-file f))
952969
([f opts] (rewrite-clj.zip.base/of-file f opts))))
953970

971+
#?(:clj
972+
973+
;; DO NOT EDIT FILE, automatically imported from: rewrite-clj.zip.base
974+
(defn ^{:added "1.1.46"} of-file*
975+
"Create and return zipper from all forms in Clojure/ClojureScript/EDN File `f`, and do no automatic move.
976+
977+
See [[of-file]] for same but with automatic move to first interesting node.
978+
979+
Optional `opts` can specify:
980+
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
981+
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
982+
([f] (rewrite-clj.zip.base/of-file* f))
983+
([f opts] (rewrite-clj.zip.base/of-file* f opts))))
984+
954985

955986
;; DO NOT EDIT FILE, automatically imported from: rewrite-clj.custom-zipper.core
956987
(defn right*

src/rewrite_clj/zip/base.cljc

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
"Create and return zipper from a rewrite-clj `node` (likely parsed by [[rewrite-clj.parser]]),
3030
and move to the first non-whitespace/non-comment child. If node is not forms node, is wrapped in forms node
3131
for a consistent root.
32-
3332
Optional `opts` can specify:
3433
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
3534
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
@@ -95,26 +94,55 @@
9594
(some-> zloc zraw/node node/value))
9695

9796
;; ## Read
97+
(defn of-string*
98+
"Create and return zipper from all forms in Clojure/ClojureScript/END string `s`, and do no automatic move.
99+
100+
See [[of-string]] for same but with automatic move to first interesting node.
101+
102+
Optional `opts` can specify:
103+
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
104+
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
105+
([s] (of-string* s {}))
106+
([s opts]
107+
(some-> s p/parse-string-all (of-node* opts))))
108+
98109
(defn of-string
99-
"Create and return zipper from all forms in Clojure/ClojureScript/EDN string `s`.
110+
"Create and return zipper from all forms in Clojure/ClojureScript/EDN string `s`, and move to the first non-whitespace/non-comment child.
111+
112+
See [[of-string*]] for same but with no automatic move.
100113
101114
Optional `opts` can specify:
102115
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
103116
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
104117
([s] (of-string s {}))
105118
([s opts]
106-
(some-> s p/parse-string-all (edn opts))))
119+
(some-> s p/parse-string-all (of-node opts))))
120+
121+
#?(:clj
122+
(defn of-file*
123+
"Create and return zipper from all forms in Clojure/ClojureScript/EDN File `f`, and do no automatic move.
124+
125+
See [[of-file]] for same but with automatic move to first interesting node.
126+
127+
Optional `opts` can specify:
128+
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
129+
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
130+
([f] (of-file* f {}))
131+
([f opts]
132+
(some-> f p/parse-file-all (of-node* opts)))))
107133

108134
#?(:clj
109135
(defn of-file
110-
"Create and return zipper from all forms in Clojure/ClojureScript/EDN File `f`.
136+
"Create and return zipper from all forms in Clojure/ClojureScript/EDN File `f`, and move to the first non-whitespace/non-comment child.
137+
138+
See [[of-file*]] for same but with no automatic move.
111139
112140
Optional `opts` can specify:
113141
- `:track-position?` set to `true` to enable ones-based row/column tracking, see [docs on position tracking](/doc/01-user-guide.adoc#position-tracking).
114142
- `:auto-resolve` specify a function to customize namespaced element auto-resolve behavior, see [docs on namespaced elements](/doc/01-user-guide.adoc#namespaced-elements)"
115143
([f] (of-file f {}))
116144
([f opts]
117-
(some-> f p/parse-file-all (edn opts)))))
145+
(some-> f p/parse-file-all (of-node opts)))))
118146

119147
;; ## Write
120148

src/rewrite_clj/zip/walk.cljc

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,11 @@
5252
5353
When `p?` is not specified `f` is called on all locations.
5454
55-
Note that by default a newly created zipper automatically navigates to the first non-whitespace
56-
node. If you want to be sure to walk all forms in a zipper, you'll want to navigate one up prior to your walk:
55+
To walk all nodes, you'll want to walk from the root node.
56+
You can do this by, for example, using [[of-string*]] instead of [[of-string]].
5757
5858
```Clojure
59-
(-> (zip/of-string \"my clojure forms\")
60-
zip/up
59+
(-> (zip/of-string* \"my clojure forms\")
6160
(zip/prewalk ...))
6261
```
6362
@@ -109,12 +108,11 @@
109108
110109
When `p?` is not specified `f` is called on all locations.
111110
112-
Note that by default a newly created zipper automatically navigates to the first non-whitespace
113-
node. If you want to be sure to walk all forms in a zipper, you'll want to navigate one up prior to your walk:
111+
To walk all nodes, you'll want to walk from the root node.
112+
You can do this by, for example, using [[of-string*]] instead of [[of-string]].
114113
115114
```Clojure
116-
(-> (zip/of-string \"my clojure forms\")
117-
zip/up
115+
(-> (zip/of-string* \"my clojure forms\")
118116
(zip/postwalk ...))
119117
```
120118

template/rewrite_clj/zip.cljc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@
1818
1919
Because this API contains many functions, we offer the following categorized listing:
2020
21-
**Create a zipper**
21+
**Create a zipper and move to first non-whitespace/comment node**
2222
[[of-node]]
23-
[[of-node*]]
2423
[[of-string]]
2524
[[of-file]]
2625
26+
**Create a zipper without skipping any nodes**
27+
[[of-node*]]
28+
[[of-string*]]
29+
[[of-file*]]
30+
2731
**Move**
2832
[[left]]
2933
[[right]]
@@ -184,6 +188,7 @@
184188
length
185189
^{:deprecated "0.4.0"} value
186190
of-string
191+
^{:added "1.1.46"} of-string*
187192
^{:added "0.4.0"} string
188193
^{:deprecated "0.4.0"} ->string
189194
^{:added "0.4.0"} root-string
@@ -255,6 +260,11 @@
255260
{:from [[rewrite-clj.zip.base
256261
of-file]]}})
257262

263+
#?(:clj
264+
#_{:import-vars/import
265+
{:from [[rewrite-clj.zip.base
266+
^{:added "1.1.46"} of-file*]]}})
267+
258268
#_{:import-vars/import
259269
{:opts {:sym-to-pattern "@@orig-name@@*"
260270
:doc-to-pattern "Raw version of [[@@orig-name@@]].\n\n@@orig-doc@@\n\nNOTE: This function does not skip, nor provide any special handling for whitespace/comment nodes."}

0 commit comments

Comments
 (0)