Fork me on GitHub
#specter
<
2018-07-13
>
idiomancy00:07:43

I picked up specter to play with hiccup, and I'm trying to form compound keys by grabbing the keys of sub elements within the data. essentially, given

[[:div.row
  [:div.column {:key "A"}]
  [:div.column {:key "B"}]]
 [:div.row
  [:div.culumn {:key "C"}]
  [:div.column {:key "D"}]]]
I want
[[:div.row {:key "AB"}
  [:div.column {:key "A"}]
  [:div.column {:key "B"}]]
 [:div.row {:key "CD"}
  [:div.culumn {:key "C"}]
  [:div.column {:key "D"}]]]
I'll be working on this myself, but if anyone has any ideas, this is effing crazy to write with handrolled clojure, and it seems like the perfect specter magic trick from what I've seen in the videos

nathanmarz00:07:29

@idiomancy

(def data
  [[:div.row
    [:div.column {:key "A"}]
    [:div.column {:key "B"}]]
   [:div.row
    [:div.culumn {:key "C"}]
    [:div.column {:key "D"}]]])

(transform
  [ALL
   (collect ALL coll? (nthpath 1) :key)
   (before-index 1)]
  (fn [keys _] {:key (apply str keys)})
  data
  )

idiomancy00:07:58

oooh, man. No way.

idiomancy00:07:12

It was gonna take me a while to figure out that "collect" navigator, I think šŸ˜†

idiomancy00:07:16

that's amazing!

nathanmarz00:07:11

the cheat sheet is handy for finding navigators you need https://github.com/nathanmarz/specter/wiki/Cheat-Sheet

8
idiomancy00:07:13

let me spend a couple hours reverse engineering this. thanks, @nathanmarz

denik14:07:44

I asked this in the #clojure channel and wondering if specter could be a solution: https://clojurians.slack.com/archives/C03S1KBA2/p1531346207000010

denik14:07:15

the reason clojure.spec doesnā€™t work for this case is because spec tries to conform everything. The ebooks I looked at are highly inconsistent. I think what Iā€™m looking for more like a data matcher, rather than a parser

nathanmarz15:07:59

@denik don't understand the output you're looking for

nathanmarz15:07:38

{:class "indent" :content "key lesson 1"} does not match {:class "indent" :content "key lesson 1"}

nathanmarz15:07:48

and there's no "key lesson 3" in your input

denik15:07:19

@nathanmarz start at ā€œSTART HEREā€ and match multiple :class fields, in this case indent and indent1 but ignore these items before( and after with the stop condition to )

nathanmarz15:07:24

and you only want to keep items that match the :filter predicate?

denik15:07:26

yes, but only when they were found between from and to sequentially

nathanmarz15:07:17

you can do it with specter like this:

(defn start-index [data]
    ;; fill in
  )

(def end-index
  (end-fn [data start-index]
    ;; fill in
    ))


(select
  [(srange-dynamic start-index end-index)
   ALL
   (selected?
    (multi-path
      #(= "START HERE" (:class %))
      #(= "bl" (:class %))
      ))
   ]
  data)

nathanmarz15:07:27

but really this is better done with a parser

nathanmarz15:07:01

I'm not very familiar with what spec is capable of, but this is real easy with monadic parser

denik15:07:42

thank you!

denik15:07:51

hereā€™s what that looks like in spec

(require '[clojure.spec.alpha :as s]
         '[clojure.pprint :as pp])

(def ebook
  [{:class "indent" :content "ignore"}
   {:class "indent" :content "ignore"}
   {:class "START HERE" :content "Key Lessons"}
   {:class "indent" :content "ignore"}
   {:class "indent1" :content "ignore"}
   {:class "bl" :content "key lesson 1"}
   {:class "bl" :content "key lesson 2"}
   {:class "indent3" :content "ignore"}])

(s/def
  ::ebook-tree
  (s/and
    (s/cat
     :ignore (s/* (s/and map? #(= "ignore" (:content %))))
     :start (s/and map? #(= (:class %) "START HERE"))
     :body (s/* (s/alt
                 :ignore (s/and map? #(= "ignore" (:content %)))
                 :item (s/and map? #(= "bl" (:class %)))))
     :end (s/and map? #(= "indent3" (:class %))))
    (s/conformer
     (fn [{:keys [start body]}]
       (assoc start :children (for [[tag item] body
                                    :when (not= tag :ignore)]
                                item))))))

(pp/pprint
 (s/conform ::ebook-tree ebook))

nathanmarz15:07:07

with https://github.com/nathanmarz/specter/issues/236 you could do it more easily with specter

denik15:07:14

@nathanmarz I think thatā€™s exactly what Iā€™m looking for.