That's close to what I want. However, there's sometimes maps nested inside of vectors / list and I need to handle those too. So imagine data looks like this:
(def data
{:AThing {:AAThing [{:AABAThing 1} {:AABBThing 2} {:AABCThing 3}]
:A2Thing {:AAAThing "x"}}})
I'm not concerned about records or things like that for this use case. It's just all plain Clojure mapsThis seems to have the desired effect:
(def ALL-MAPS
(specter/recursive-path [] p
(specter/if-path map?
(specter/continue-then-stay specter/MAP-VALS p)
(specter/if-path (some-fn seq? vector? set? list?)
specter/ALL)
)))
(def data
{:AThing {:AAThing [{:AABAThing 1} {:AABBThing 2} {:AABCThing 3}]
:A2Thing {:AAAThing "x"}}})
(specter/transform [ALL-MAPS specter/MAP-KEYS] csk/->snake_case data)
Any reasons not to do it this way?it would be more elegant with cond-path, but you have the right idea
Cool. Thank you!
I updated to use cond-path, but it looks like the transformer isn't fully recursive.
(def ALL-MAPS
(specter/recursive-path [] p
(specter/cond-path
map? (specter/continue-then-stay specter/MAP-VALS p)
(some-fn seq? vector? set? list?) specter/ALL)))
(def data
{:AThing {:AAThing [{:AABAThing 1} {:AABBThing 2} {:AABCThing 3 :DeeplyNestedThing [{:ABC 1} {:ABC 2}]}]
:A2Thing {:AAAThing "x"}}})
(specter/transform [ALL-MAPS specter/MAP-KEYS] csk/->snake_case data)
Result is this:
{:a_thing {:aa_thing [{:aaba_thing 1} {:aabb_thing 2} {:aabc_thing 3, :deeply_nested_thing [{:ABC 1} {:ABC 2}]}],
:a_2_thing {:aaa_thing "x"}}}
What do I need to change for the maps in deeply_nested_thing to be selected too?This seems to work:
(def ALL-MAPS
(specter/recursive-path [] p
(specter/cond-path
map? (specter/continue-then-stay specter/MAP-VALS p)
(some-fn seq? vector? set? list?) [specter/ALL p])))
(note the change to [specter/ALL p] )
Is that the right way to do it? Why did the other way mostly work?I think you can change the some-fn part to just sequential?
otherwise that looks right
or I suppose just replace seq?, vector?, and list? with sequential?
I would also wrap the some-fn part in pred to make it higher performance, since otherwise Rama needs to determine how to convert the function to a navigator at runtime
Originally, I was going to use sequential?, but I realized it didn't match for set. So I tried seqable? but that had the unintended consequence of also matching strings. Using sequential? with set? works well.
Final product looks like this:
(def ALL-MAPS
(specter/recursive-path [] p
(specter/cond-path
map? (specter/continue-then-stay specter/MAP-VALS p)
(specter/pred (some-fn sequential? set?)) [specter/ALL p])))
Thanks for the help!