"JQuery" type function for managing clojure maps

Is there a function like jQuery to solve the problem of navigating through nested maps?

for example, if I have a configuration that looks like this:

(def fig {:config {:example {:a "a" :b "b" :c "c"} :more {:a "a" :b "b" :c "c"}}}) 

I still haven't figured out a great way to manipulate nested persistent data structures with assoc and dissoc. However, if there is a jquery style way to manage maps, then I can write the code as follows:

  (-> fig ($ [:config :example :a] #(str % "a")) ($ [:config :b] #(str % "b"))) Giving this output: {:config {:example {:a "aa" :b "bb" :c "c"} :more {:a "a" :b "bb" :c "c"}}} 

And something like this for selectors:

 ($ fig [:config :example :a]) ;=> "a" ($ fig [:config :b]) ;=> {[:config :example :b] "b", ; [:config :more :b] "b"} 

So essentially I am looking for a jayq implementation for managing clojure objects instead of html doms.

Thanks in advance!

+4
source share
2 answers

First of all, you should check Enlive.

Otherwise: if you want to do what jQuery does (of course, very simplified) - unlike a simple update-in call:

Choose:

 (defn clj-query-select [obj path] (if (empty? path) (list obj) (when (map? obj) (apply concat (remove nil? (for [[key value] obj] (clj-query-select value (if (= key (first path)) (rest path) path)))))))) 

To call:

 (clj-query-select {:a {:b 1} :b 2} [:b]) 

he should give:

 (1 2) 

Update / Replace:

 (defn clj-query-update [obj path fn] (if (empty? path) (fn obj) (if (map? obj) (into obj (remove nil? (for [[key value] obj] (let [res (clj-query-update value (if (= key (first path)) (rest path) path) fn)] (when (not= res value) [key res]))))) obj))) 

To call:

 (clj-query-update {:c {:a {:b 1} :b 2}} [:c :b] #(* % 2)) 

he should give:

 {:c {:a {:b 2} :b 4}} 

I have not tested it completely, though.

+4
source

update-in is a great feature for updating nested maps.

 user> (def data {:config {:example {:a "a" :b "b" :c "c"}} :more {:a "a" :b "b" :c "c"}}) user> (pprint (update-in data [:config :example] assoc :d 4)) {:config {:example {:a "a", :c "c", :b "b", :d 4}}, :more {:a "a", :c "c", :b "b"}} 

assoc-in may be a little closer to what you want

 user> (pprint (assoc-in data [:config :example :d] 4)) {:config {:example {:a "a", :c "c", :b "b", :d 4}}, :more {:a "a", :c "c", :b "b"}} 

to read values ​​without changing them, you can use the fact that keywords look in maps for writing even more compact form than jquery form

 user> (-> data :config :example :a) "a" 
+6
source

All Articles