Iterate over a map in selmer - clojure

I would like to iterate over a map in selmer, in such a way that allows my to print the keys as well as the values. As far as I can see this is not supported out of the box, so I have tried the following:
(defn mapper-tag [args context-map content]
(when-let [map-data (get context-map (keyword (first args))
(get context-map (first args)))]
(apply str (for [[k v] map-data]
(selmer.parser/render (get-in content [:mapper :content]) {:key k :val v})))))
(selmer.parser/add-tag! :mapper mapper-tag :endmapper)
(selmer.parser/render "{% mapper m %}KEY {{key}} \n{% endmapper %}" {:m {:a 1 :b 1}})
I expect this to output something like
KEY a
KEY b
But it outputs
KEY
KEY
Any pointers?

Maps in Clojure are seqs so you can just use selmer for:
(selmer.filters/add-filter! :key key)
(selmer.filters/add-filter! :val val)
(selmer.parser/render "{% for item in m %} KEY is {{item|key}} VALUES is {{item|val}}\n{% endfor %}" {:m {:a 1 :b 1}})

Selmer's built-in {% for %} loop allows for destructuring, so you can pull out the key/value right there in the template:
(selmer.parser/render
"{% for key,val in m %}KEY: {{key}}, VALUE: {{val}}\n{% endfor %}"
{:m {:a 1 :b 1}})
Output:
KEY: a, VALUE: 1
KEY: b, VALUE: 1

Related

how to remove a given key from a series of maps in a vector in clojure?

In clojure, given a data structure [{:a "foo" :b "bar"} {:a "biz" :b "baz"}] how would I get [{:b "bar"}{:b "baz"}] the most succinctly?
dissoc is a function for dissociating a key from an associative structure like a map. Here's how you'd do it with one map:
(dissoc my-map :a)
If you have a sequence of maps, you can map a function over them to dissoc the key(s) from each map:
(map #(dissoc % :a) the-maps)
This phrasing passes an anonymous function to map, but depending on usage you may want to extract a named function:
(defn fix-the-map [m]
(dissoc m :a))
(map fix-the-map the-maps)
#Taylor's above answer to dissoc :a from each map is fine if you want all maps without :a.
In case if you want a list of maps with just :b key, you can do
<!-- language-all: lang-clj -->
;; Assuming my-map is the object map
;; map returns a lazy sequence
(map #(hash-map :b (:b %)) my-map)
;; or
(map #(select-keys % [:b]) mp)

Replace item in vector by id

(defonce channels (atom []))
(defn register-channel! [id tag channel]
(swap! channels conj [id tag channel]))
(register-channel! "456" :player {})
#channels ;; => [["456" :player {}]]
The id and tag are the indexes for the data, the id is unique, the tag is not.
I can conj new items on to channels. But calling register-channel! with an existing id will not conj a new item instead the third element, channel, of the existing item should be changed.
Here is what I have, which works:
(defn register-channel! [id tag channel]
(let [without-id (remove #(= id (first %)) #channels)
with-id (conj without-id [id tag channel])]
(reset! channels with-id)))
I'm pretty sure there is a more elegant way :)
Note that I am using a collection of vector because I'll only ever have 3 elements, I could use a map if there is no significant performance penalty. However I will need to write functions to find a channel by id or channels by tag afterwards, e.g.
(defn one-by-id [id] (first (filter #(= id (first %)) #channels)))
(defn many-by-tag [tag] (filter #(= tag (second %)) #channels))
If you really need channels to be a vector of pairs, you can add or replace new channels like this:
> (vec (assoc (into {} [[:a 1]]) :a 2))
[[:a 2]]
> (vec (assoc (into {} [[:a 1]]) :b 2))
[[:a 1] [:b 2]]
But that begs the question of whether you'd rather have channels itself be a map.
Define the atom as an empty map and job done!
(defonce channels (atom {}))
(defn register-channel! [id channel]
(swap! channels conj [id channel]))
> (register-channel! "456" {:a 1})
{"456" {:a 1}}
> (register-channel! "457" {:a 1})
{"456" {:a 1}, "457" {:a 1}}
> (register-channel! "457" {:a 2})
{"456" {:a 1}, "457" {:a 2}}

Why partial is so slow in clojure

The following is super fast.
(let [a (atom {})]
(doall (map #(swap! a merge {% 1}) (range 10000))) (println #a))
But if add partial, then is so slow. The result return by the code should be same,right? why does the performance diff so much?
(let [a (atom {})]
(doall (map #(swap! a (partial merge {% 1})) (range 10000))) (println #a))
(partial f a) and #(f a %) are actually quite different.
No matter the definition of f, you are allowed to provide any number of arguments to the partially applied function, and the runtime will put them in a list and use apply to get the result. So, no matter what, you have a short lived list constructed every time you use a function constructed with partial. On the other hand, #() creates a new class, and if you use an older JVM that segregates permgen from regular heap, this can become an issue as you use up more and more of the dedicated memory for classes.
Even if #noisesmith answer is right, the performance problem does not come from partial.
The problem is more trivial: it is only the order in which the parameters are passed to merge.
In #(swap! a merge {% 1}) the atom is passed as the first parameter to merge. At each step, only {% 1} is conjoined to the atom growing map.
In #(swap! a (partial merge {% 1})), the atom is passed as second parameter to merge and at each step all elements of the atom a are conjoined to {% 1}.
Let's try a test with merge' that call merge, reversing the parameters. The map on which all elements from other maps are conjoined is the last one :
(defn merge' [& maps]
(apply merge (reverse maps)))
(require '[criterium.core :as c])
(c/quick-bench
(let [a (atom {})]
(dorun (map #(swap! a merge {% 1}) (range 10000))) ))
=> Execution time mean : 4.990763 ms
(c/quick-bench
(let [a (atom {})]
(dorun (map #(swap! a (partial merge' {% 1})) (range 10000))) ))
=> Execution time mean : 7.168238 ms
(c/quick-bench
(let [a (atom {})]
(dorun (map #(swap! a (partial merge {% 1})) (range 10000))) ))
=> Execution time mean : 10.610342 sec
The performances with merge and (partial merge') are comparable. (partial merge) is effectively awful.

In clojure enlive how to create template to add values and keys from a map

I want to create a template with Clojure's Enlive for a "table" like html page, that should have a header and rows. I want to populate this "table" with data that comes from this map. Basicaly I want to populate header with keys, and cells with vals from each of the maps that come from :event-data key.
(def dummy-content
{:title "Events Mashup"
:event-data [{ :event-name "event name 1"
:performer "performer 1"
:date "date 1"
:start-time "start time 1"
:end-time "end time 1"}
{:event-name "event name 2"
:performer "performer 2"
:date "date 2"
:start-time "start time 2"
:end-time "end time 2"}]})
My snippets and template look like this:
(defsnippet header-cell "index.html" [:.psdg-top-cell] [value] [:.psdg-top-cell]
(defsnippet value-cell "index.html" [:.psdg-right] [value] [:.psdg-right]
(deftemplate mshp "index.html" [content]
[:.psdg-top] (append (for [c (keys content)] (header-cell c)))
[:.psdg-right] (append (for [v (vals content)] (value-cell v))))
And index.html has these tags, that are rellevant for this template.
<div id="psdg-top">
<div class="psdg-top-cell" style="width:129px; text-align:left; padding- left:24px;">Summary</div>
<div class="psdg-top-cell">Website.com</div>
</div>
<div class="psdg-right">10 000</div>
When I call the template I get this error:
=> (mshp (:event-data dummy-content))
ClassCastException clojure.lang.PersistentHashMap cannot be cast to java.util.Map$Entry clojure.lang.APersistentMap$ValSeq.first (APersistentMap.java:183)
What am I doing wrong?
The error is occurring when you call (keys content), because (:event-data dummy-content) returns a vector, and keys won't work on a vector. You've got two options - you can either define your header columns elsewhere, or just take them from the first element in the vector, like this: (keys (first content)).
Edit
I've had a go at replicating what you set out in the question, but fixing the errors, and you can find my efforts here: https://www.refheap.com/17659.
If you want something that has a more typical table structure, with the value cells contained in rows, you can try the following. It uses clone-for rather than a combination of append and for, and uses nth-of-type to just return the first "psdg-top-cell" (otherwise there would be twice as many)
(def template
(html-snippet
"<div id=\"psdg-top\">
<div class=\"psdg-top-cell\">Summary</div>
<div class=\"psdg-top-cell\">Website.com</div>
</div>
<div class=\"psdg-right\">10 000</div>"))
(defsnippet header-row template [[:.psdg-top-cell (nth-of-type 1)] ] [headers]
(clone-for [h headers]
(content h)))
(defsnippet value-row template [:.psdg-right] [values]
(clone-for [v values]
(content v)))
(deftemplate mshp template [events]
[:#psdg-top] (content (header-row (map name (keys (first events)))))
[:.psdg-right] (clone-for [e events]
(do->
(wrap :div {:class "psdg-row"})
(content (value-row (vals e))))))

Why merge-with is used instead of simple 'merge' in Ring, Clojure?

I'm very new to Clojure and learning Clojure by reading
good open source code. So I choose Ring and starting to read
the code but got stuck in assoc-query-params function.
(which is located in ring.middleware/params.clj)
And I could not understand why "merge-with" is used.
Can anybody help me to understand this code snippet?
(defn- assoc-query-params
"Parse and assoc parameters from the query string with the request."
[request encoding]
; I think (merge request (some-form)) is enough
; but the author used merge-with with merge function.
(merge-with merge request
(if-let [query-string (:query-string request)]
(let [params (parse-params query-string encoding)]
{:query-params params, :params params})
{:query-params {}, :params {}})))
Here's the description of the merge function: reworded it says that if a key is met more than once than value in the latest map will be selected. In the example that you posted that would mean that values of :query-params :params will be taken as is from the tail of the function instead of combining them with what's in the request.
Let's look at the example:
(def m {:a {:a-key1 "value1"} :b {:b-key1 "value3"} :c {}})
(def m2 {:a {:a-key2 "value2"} :b {}})
(merge m m2)
;-> {:a {:a-key2 "value2"}, :b {}, :c {}}
(merge-with merge m m2)
;-> {:a {:a-key1 "value1", :a-key2 "value2"}, :b {:b-key1 "value3"} :c {}}
So (merge-with merge ...) construct gives us a way to merge maps in the map. You can look at it this way: merge-with will group all key/value pairs by the key (:a :b :c in our example) and apply merge to their values.
{:a (merge {:a-key1 "value1"} {:a-key2 "value2"})
:b (merge {:b-key1 "value3"} {})
:c (merge {})}
Having handled that I think that the original intention of the assoc-query-params author is to extend :query-params and :params instead of completely replacing them.