Fork me on GitHub
#specter
<
2017-10-29
>
eoliphant02:10:43

Hi i just discovered specter, it’s awesome. I have a quick question. I’m trying to add a map to a list of maps., but setval treats it as a collection and adding each k-v pair. Like so:

testmap
=> {:a "a", :b [{:id 1, :str "1"} {:id 2, :str "2"} {:id 3, :str "2"}]}
(s/setval [:b s/END] {:id 5
                      :a 6} testmap)
=> {:a "a", :b [{:id 1, :str "1"} {:id 2, :str "2"} {:id 3, :str "2"} [:id 5] [:a 6]]}
How do I get around this?

michaelwfogleman02:10:35

Not sure if this is the idiomatic way but does this do what you're looking for?

michaelwfogleman02:10:37

(def test-map {:a "a", :b [{:id 1, :str "1"} {:id 2, :str "2"} {:id 3, :str "2"}]})
(transform [:b END] #(conj % {:id 5 :a 6}) test-map) 

michaelwfogleman02:10:50

That returns

{:a "a", :b [{:id 1, :str "1"} {:id 2, :str "2"} {:id 3, :str "2"} {:id 5, :a 6}]}
for me

eoliphant02:10:08

ah pass a function that returns it

eoliphant02:10:15

ok cool thanks will give that a shot

michaelwfogleman02:10:33

I also don't think I needed end there

michaelwfogleman02:10:42

(transform [:b] #(conj % {:id 5 :a 6}) test-map)

michaelwfogleman02:10:47

that should do the same

michaelwfogleman02:10:54

since a vector gets added to the end anyway

eoliphant02:10:12

hey i just tried this too

(s/setval [:b s/END] [{:id 5
                      :a 6}] testmap)
seems to work

nathanmarz03:10:49

@eoliphant use AFTER-ELEM to append a single element to a sequence

nathanmarz03:10:10

(setval [:b AFTER-ELEM] {:id 5 :a 6} testmap)

nathanmarz03:10:26

that's more efficient than using END for this use case

schmee08:10:33

this Specter snippet works, but I think it’s a bit of a code smell to have both cond-path and a cond in my transformation function. This being Specter, I suspect that there is a better way to do it 🙂

(def DATA-WALKER
  (s/recursive-path [] p
    (s/cond-path
      map? (s/continue-then-stay s/MAP-VALS p)
      seq? (s/continue-then-stay s/ALL p))))

(defn simplify [m]
  (s/transform
    DATA-WALKER
    #(cond
       (sequential? %) (vec %)
       (map? %) (into {} %))
    m))
Any suggestions?

schmee08:10:59

I’ve looked at multi-transform, but I haven’t figured out how to use it with recursive paths

nathanmarz13:10:21

@schmee multi-transform version would be (multi-transform [DATA-WALKER (if-path map? (terminal #(into {} %)) (terminal vec))] m)

nathanmarz13:10:56

you don't need the cond since after DATA-WALKER it's either map? or seq?

schmee16:10:21

nice, thank you! 😄