This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-26
Channels
- # announcements (1)
- # beginners (42)
- # biff (11)
- # calva (15)
- # cider (3)
- # clj-http-lite (3)
- # clojure (52)
- # clojure-europe (16)
- # clojure-nl (1)
- # clojure-norway (39)
- # clojure-uk (4)
- # clojurescript (52)
- # code-reviews (13)
- # conjure (1)
- # cursive (4)
- # data-science (1)
- # datomic (5)
- # emacs (6)
- # events (3)
- # graalvm (5)
- # hyperfiddle (7)
- # kaocha (14)
- # lsp (11)
- # malli (3)
- # nbb (13)
- # off-topic (87)
- # pathom (15)
- # polylith (23)
- # portal (5)
- # reitit (4)
- # shadow-cljs (110)
- # squint (114)
- # testing (1)
- # vim (13)
I wrote a cute little macro that does a threading diff: 🧵
(comment
(-diff->
{}
(assoc :a 1 :b {})
(assoc-in [:b :c] [1 2 3 4])
(update-in [:b :c 2] inc)
(update-in [:b :c] reverse))
)
if you run what’s in the comment block, it’ll print out:
https://clojurians.slack.com/files/U051GFP2V/F03VCU6MBQT/screen_shot_2022-08-26_at_1.47.36_pm.png(ns playground.thread-diff
(:require [clojure.pprint :as pprint]
[lambdaisland.deep-diff2 :as ddiff]
[clojure.walk :as walk]
[clojure.string :as str]))
(defn print-diff! [a b]
(ddiff/pretty-print (ddiff/diff a b) (ddiff/printer {:width 80})))
(defn outerpose [x ys]
(concat [x] (interpose x ys) [x]))
(defmacro -diff->
"Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
second item in second form, etc."
{:added "1.0"}
[in-x & in-forms]
(loop [x [::nothing in-x],
forms (concat
;; Starting:
[(list (list 'fn '[[old new]]
(list 'println "Starting -diff-> with:" '(pr-str new) "\n")
'[old new]))]
(interleave
;; run with old and new context steps
(mapv
(fn [form]
(list (list 'fn '[[_ new]] ['new (list '-> 'new form)])))
in-forms)
;; report diff result steps
(mapv (fn [form]
(list (list 'fn '[[old new]]
(list 'println "")
;; print Running step
(list 'println "Running: " (list 'str "(-> " (list pr-str 'old) " " (pr-str form) ")"))
;; print diff
'(print-diff! old new)
'[old new])))
in-forms)))]
(if forms
(let [form (first forms)
threaded (if (seq? form)
(with-meta `(~(first form) ~x [email protected](next form)) (meta form))
(list form x))]
(recur threaded (next forms)))
(list last x))))
(comment
(-diff->
{}
(assoc :a 1 :b {})
(assoc-in [:b :c] [1 2 3 4])
(update-in [:b :c 2] inc)
(update-in [:b :c] reverse))
)
the way it works, is by wrapping the steps that do actions in functions that take 2 args: old
and new
.
the wrapping functions apply a step, put its result into new, and the input to the step into old
then there’s a function that takes the initial value and turns it into [::nothing in-x] at the beginning and calls last at the end with (list last x)
Super cool. I assume this will be useful in every day development? Would it work to replace the threading macro with this temporarily to get more info about some context? I can't see why not...
Are the clojure.pprint, clojure.string, and clojure.walk requires relicts from earlier experiments?
Must be. I see that those aren’t needed here. I think I was trying to write the macro a different way
Also, it would be great to have a version that plays nicely with large data structures, perhaps by printing just smaller portion of the diff.
Finally, I think you can make it more general by accepting the threading symbol as an argument.
So it's automatically usable for both ->
and ->>
.
As in
(tdiff -> ...)
https://github.com/jumarko/clojure-experiments/pull/34/files#diff-8e10d07b03ac46755d48405271bfef8ecde8e64a3b4a35559f6440c8bdf88fcfR50