Fork me on GitHub
#specter
<
2018-02-04
>
justinlee00:02:11

I use specter to manipulate my state object in the front end. I’m curious: is there a way to apply multiple specter transformations to an atom atomically? If I were doing this with the normal swap! function I’d just wrap all the transformations in a fn. But I’m not sure how to do that with specter. (I’m asking because I’m worried that applying multiple specter transformations to a reagent atom might cause me grief, given that components get re-rendered in response to updates. So far, I’m not 100% this is a real problem, because I think reagent batches updates, but I’m still curious.)

nathanmarz00:02:55

@lee.justin.m yes you can use multi-transform for that

nathanmarz00:02:30

e.g. (multi-transform [ATOM (multi-path [:a (terminal inc)] [:b (terminal dec)])] state-object)

justinlee00:02:11

oh i hadn’t seen this list-of-macros page. there are all kinds of goodies here.

nathanmarz00:02:48

definitely worth skimming through the wiki

nathanmarz00:02:52

it's mostly up to date nowadays

justinlee20:02:23

@nathanmarz Just following up on the example you just used in #clojure, could you explain this:

(def data 
  {:a [:x :y]
   :b [:x :y]})
(select [ALL (collect-one FIRST) LAST] data)
;; -> [[:a [:x :y]] [:b [:x :y]]]

;; The next statement will distribute the :a and :b
(select [ALL (collect-one FIRST) LAST ALL] data)
;; -≥ [[:a :x] [:a :y] [:b :x] [:b :y]]

;; But this, which applies the same selector to the intermediate result, does not
(select [ALL] [[:a [:x :y]] [:b [:x :y]]])
;; -> [[:a [:x :y]] [:b [:x :y]]]

schmee20:02:20

@justinlee collecting variables is a special thing, search for “collect” in the readme for an explanation: https://github.com/nathanmarz/specter

justinlee20:02:58

@schmee thanks yea i read that and the docs for collect and collect-one but i can’t for the life of me figure out how they alter the ALL selector in the context of a select

justinlee20:02:55

there is some reference to adding a value to the ‘collected values’ but I haven’t seen how the collected values are used in selectors like ALL (though I understand how they are used in the transform example when you need an argument to the transforming function

schmee20:02:30

user=> (select [ALL (collect-one FIRST) LAST] data)
[[:a [:x :y]] [:b [:x :y]]]
user=> (select [ALL (collect-one FIRST) (collect-one FIRST) LAST] data)
[[:a :a [:x :y]] [:b :b [:x :y]]]

schmee20:02:55

looks to me like select just calls vector on the collected arguments + the value(s) you’ve navigated to

justinlee20:02:23

Yea I guess that’s it. I’m not sure why it does that. 🙂

com.rpl.specter=> (select [(putval "a") ALL] [1 2 3])
[["a" 1] ["a" 2] ["a" 3]]
com.rpl.specter=> (select [(putval "a") FIRST] [1 2 3])
[["a" 1]]
com.rpl.specter=> (select [(putval "a") (putval "b") ALL] [1 2 3])
[["a" "b" 1] ["a" "b" 2] ["a" "b" 3]]

justinlee21:02:03

got it thanks. that makes sense.