Fork me on GitHub
#specter
<
2017-02-22
>
chromalchemy16:02:55

I am trying to tranform some "Hiccup-y" style data that will be compiled by Garden into CSS. Ex: [:h1 :h2 {:font-weight "none"}] [:body {:font-size "16px"}] But it seem like the Specter functions expect maps. How can I get these vectors into something that Specter can see better?

chromalchemy16:02:07

ps. Thank you for Specter. I'm coming from front end and dont know much about typical database interactions, But Specter + nested EDN just seems to make sense 😅 I'm trying to use it in cljs client with persistance to Firebase JSON tree.

nathanmarz16:02:26

@chromalchemy specter works on all data structures

nathanmarz16:02:40

what are you trying to do?

chromalchemy16:02:22

It might be a lark, but since CSS uses a form of navigators, and Garden follows suit to compile Hiccup style clojure data into CSS, I could take a super-structure of ready-to-compile Garden data, and transform or filter it as needed with Specter for more specific application of the style data. Kind of like querying a style database dynamically, instead of declaring static css rules/paths directly.

chromalchemy17:02:00

Im not sure how to navigate the Garden vectors though. They arent exactly maps (though there are nested maps) I cant even get the first key-val out of a vector.

tolitius17:02:57

@chromalchemy

=> (def html [[:h1 :h2 {:font-weight "none"}] [:body {:font-size "16px"}]])

=> (transform [(walker :font-size) :font-size] #(s/replace %  #"px" "em") html)

[[:h1 :h2 {:font-weight "none"}] [:body {:font-size "16em"}]]
your examples are just data structures: i.e. maps, vectors, sets, etc.. or not?

tolitius17:02:46

would probably be better if you provided an example of a data structure (Garden, ..) + what you need to do with it

chromalchemy17:02:36

Yes, just data. Primarily a list of vectors, each vector is a css rule. I will try out walker. Not familiar with that one yet.

chromalchemy17:02:11

[:myclass {:color "red}] How can I get the map from the :myclass key?

nathanmarz17:02:31

you mean the element to the right of :myclass in the vector?

nathanmarz17:02:22

you can do it with com.rpl.specter.zipper

nathanmarz17:02:46

navigate to the position of :myclass, and then do z/RIGHT

nathanmarz17:02:05

I would really question why you store data like that instead of just using a map

chromalchemy17:02:38

Ok, How do I navigate to position of :myclass?

nathanmarz17:02:18

user=> (setval [z/VECTOR-ZIP (z/find-first #(= :myclass %)) z/RIGHT z/NODE :color] "blue" [:myclass {:color "red"}])
[:myclass {:color "blue"}]

chromalchemy17:02:35

Your probably right. The style data super-structure should probably just be maps. I was trying to keep it in the format that Garden wants so I dont have to do more syntax-oriented transformations to be able to compile the results to css

chromalchemy17:02:16

Thanks for that!

chromalchemy17:02:31

[[:class1 {foo}] [:class2 {bar}]] I assume I can use something similar to get to bar by filtering on :class2

nathanmarz17:02:52

find-first will descend into nested vectors, so the code is pretty much exactly the same

chromalchemy17:02:07

or in [:class1 :class2 {foo}], getting from class1 to class2 to foo?

chromalchemy17:02:57

Ok cool. I came to Specter after hearing about the challenges of using zippers. But glad that it's all included :)

nathanmarz17:02:30

zippers are just an advanced form of navigation

nathanmarz17:02:42

this happens to be a case where it fits

chromalchemy17:02:57

Thanks for the help

chromalchemy17:02:26

On a side note, do you have any best practices on size of nested data in a cljs client. Like could i serialize a one-tree to-do datastructure, and transact on it in the client with atoms. Is this reasonable or am i asking for trouble? especially if there are thousands of items & notes & metadata (i have a lot to do lol)

nathanmarz17:02:11

no idea, I don't do much clojurescript

nathanmarz17:02:20

better to ask in #clojurescript channel

mccraigmccraig18:02:58

@chromalchemy i have a largish cljs (re-frame) app with a single atom for all client state - there are commonly many thousands of items in the tree and it's fine

chromalchemy18:02:36

Cool. good to know. Tree soup it is.

alexyakushev19:02:36

Hello folks! Can anyone help me implement a deep filter? I'm looking for the following transformation:

;; Drop all maps from the vector in :stuff where :c key is present
{:fluff 42, :stuff [{:a 1, :b 2} {:a 1, :c 3} {:b 2, :c 3} {:b 2, :d 4}]}
=>
{:fluff 42, :stuff [{:a 1, :b 2} {:b 2, :d 4}]}

alexyakushev19:02:47

I also discovered NONE, but the example from Github doesn't work correctly for me (see the impl/NONE):

(setval [:a ALL nil?] NONE {:a [1 2 nil 3 nil]})
=>
{:a [1 2 :com.rpl.specter.impl/NONE 3 :com.rpl.specter.impl/NONE]}

alexyakushev19:02:39

Worked with 0.13.0-SNAPSHOT:

(setval [:stuff ALL (pred :c)] NONE {:fluff 42, :stuff [{:a 1, :b 2} {:a 1, :c 3} {:b 2, :c 3} {:b 2, :d 4}]})
=>
{:fluff 42, :stuff [{:a 1, :b 2} {:b 2, :d 4}]}
Thanks for help! 😄

nathanmarz19:02:40

@alexyakushev more precise to do (selected? (must :c)) rather than (pred :c)

alexyakushev19:02:44

Thanks! What is the case when they will work differently?

nathanmarz19:02:45

(pred :c) will filter out maps with :c being false or nil

alexyakushev19:02:10

Oh, I see. must is like contains?. I get it now, thanks!

nathanmarz19:02:25

must is keypath that navigates only if the key is present