Fork me on GitHub
#rewrite-clj
<
2021-08-23
>
andrea.crotti14:08:38

first time I try to play around with rewrite-clj

andrea.crotti15:08:03

I'm just trying to do something like this (simplifying a bit) from (log/error exc "Message") to (log/error "message" {} exc) So from my understanding I have to use z/subedit to avoid replacing the whole content of the file.

andrea.crotti15:08:08

but I'm not getting how to actually do the inner transformations, I got something semi-working extracting the inner sexprs with various z/right calls, and putting them back with format, but I guess that's not really the right way

andrea.crotti15:08:26

any suggestions about how to do that more properly maybe?

lread17:08:05

Hi @andrea.crotti! Welcome to rewrite-clj! There is no one right answer, but I seem to find myself reaching for the rewrite-clj walk functions when making a change like this. First let’s do some requiring, setup a string that includes your sample code, and print it out for later comparison:

(require '[clojure.string :as string]
         '[rewrite-clj.zip :as z]
         '[rewrite-clj.node :as n])

(def s ";; my source sample\n(+ 1 2 3)\n\n(log/error exc \"Message\")\n\n(dingo dango bango)")
(println s)
Gives us:
;; my source sample
(+ 1 2 3)

(log/error exc "Message")

(dingo dango bango)
Now let’s see how we can use the zipper to update the sample code:
(-> (z/of-string s)
    z/up ;; because we want to walk the whole zipper - not just the first non-whitespace node
    (z/postwalk (fn visit? [zloc]
                  (and (z/list? zloc)
                       (= "log/error" (-> zloc z/down z/string))))
                (fn visit [zloc]
                  ;; the exception is the first arg, lets save its node
                  (let [ex-node (-> zloc z/down z/right z/node)]
                    (-> zloc
                        ;; append an empty map as the last arg
                        (z/append-child (n/map-node []))
                        ;; now append the exception arg as the last arg (after the empty map)
                        (z/append-child ex-node)
                        ;; move to the old exception arg...
                        z/down
                        z/right
                        ;; ... and remove it
                        z/remove
                        ;; did you really want to lowercase your message? We can do that.
                        ;; move to the message...
                        z/right
                        ;; ... and lowercase it
                        (z/edit string/lower-case)
                        ;; move back up to maintain our incoming zloc position in the zipper
                        z/up))))
    z/print-root)
Gives us:
;; my source sample
(+ 1 2 3)

(log/error "message" {} exc)

(dingo dango bango)
Whatcha think? Is all that pretty clear and easy to understand? If not, just ask.

Noah Bogart17:08:43

Damn, I’m not the one asking but this is the most clear example I’ve seen. Love it

lread18:08:21

Thanks @nbtheduke, glad you liked it!

andrea.crotti18:08:26

Ah nice thanks I'll try tomorrow

andrea.crotti18:08:15

It's amazing that we can use this with babashka btw

lread19:08:17

Yeah that bb integration is super sweet, I love that too.

andrea.crotti20:08:45

I also have to check if we are using clojure.tools.logging or the other namespace we are switching to

andrea.crotti20:08:07

I wonder if it's worth using a regexp for that instead, or just try to use rewrite-clj for everyting

lread20:08:01

I find that sometimes rewrite-clj can be overkill when a simple regex will do.

borkdude21:08:05

@andrea.crotti do you mean you want to know what the log alias is referring to?

borkdude21:08:33

you can also use clj-kondo analysis for this, it gives you the same locations as rewrite-clj uses (because clj-kondo uses rewrite-clj, it plays quite nice with it)

borkdude21:08:53

examples of that are carve (which you are familiar with) and e.g. this script for turning double-colon'd keywords into normal ones: https://github.com/babashka/babashka/blob/master/examples/normalize-keywords.clj

borkdude21:08:28

you can actually use clj-kondo analysis and then skip straight to the locations that are relevant, without matching literally on "log/error"

andrea.crotti21:08:08

ah cool yes I can try that

lread21:08:47

https://github.com/clj-commons/rewrite-clj/blob/main/CHANGELOG.adoc#v10682-alphahttps://github.com/clj-commons/rewrite-clj/blob/main/CHANGELOG.adoc#v10682-alpha has been released • I don’t think these will have affected many folks - but want to get fixes out into the wild: ◦ zipper now works correctly when using both :auto-resolve and :track-position? options ◦ a Cons now coerces to a list node (thanks @borkdude!) • and thanks to @vemv rewrite-clj sources are now also linted with Eastwood

🍻 8