Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure programmatically namespace map keys

I recently learned about namespaced maps in clojure. Very convenient, I was wondering what would be the idiomatic way of programmatically namespacing a map? Is there another syntax that I am not aware of?

  ;; works fine
  (def m #:prefix{:a 1 :b 2 :c 3})
  (:prefix/a m) ;; 1

  ;; how to programmatically prefix the map?
  (def m {:a 1 :b 2 :c 3})
  (prn #:prefix(:foo m))        ;; java.lang.RuntimeException: Unmatched delimiter: )
like image 715
nha Avatar asked May 01 '17 15:05

nha


1 Answers

This function will do what you want:

(defn map->nsmap
  [m n]
  (reduce-kv (fn [acc k v]
               (let [new-kw (if (and (keyword? k)
                                     (not (qualified-keyword? k)))
                              (keyword (str n) (name k))
                              k) ]
                 (assoc acc new-kw v)))
             {} m))

You can give it an actual namespace object:

(map->nsmap {:a 1 :b 2} *ns*)
=> #:user{:a 1, :b 2}

(map->nsmap {:a 1 :b 2} (create-ns 'my.new.ns))
=> #:my.new.ns{:a 1, :b 2}

Or give it a string for the namespace name:

(map->nsmap {:a 1 :b 2} "namespaces.are.great")
=> #:namespaces.are.great{:a 1, :b 2}

And it only alters keys that are non-qualified keywords, which matches the behavior of the #: macro:

(map->nsmap {:a 1, :foo/b 2, "dontalterme" 3, 4 42} "new-ns")
=> {:new-ns/a 1, :foo/b 2, "dontalterme" 3, 4 42}
like image 87
Josh Avatar answered Sep 30 '22 19:09

Josh