From 6bf7e932d0c9e1dbf47bfce5daef0a32055df748 Mon Sep 17 00:00:00 2001 From: Jeff Evans Date: Thu, 22 Apr 2021 09:50:05 -0500 Subject: [PATCH] Support MAP-VALS for records Add implementation for IRecord almost identical to that of Object, but using a new empty-record fn Throwing exception from map-keys-transform, since it doesn't really make sense to change the keys of a record Adding simple test --- src/clj/com/rpl/specter/navs.cljc | 29 ++++++++++++++++++++++++++++- test/com/rpl/specter/core_test.cljc | 10 ++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/clj/com/rpl/specter/navs.cljc b/src/clj/com/rpl/specter/navs.cljc index 6465432..b65bffe 100644 --- a/src/clj/com/rpl/specter/navs.cljc +++ b/src/clj/com/rpl/specter/navs.cljc @@ -246,6 +246,19 @@ empty-map structure)) +;; adapted from https://stackoverflow.com/a/45447810/375670 +(defn- empty-record + "Creates a new instance of the given record, with all values nil" + [record] + (reduce + (fn [record k] + (let [without (dissoc record k)] + (if (= (type record) (type without)) + without + (assoc record k nil)))) + record + (keys record))) + (extend-protocol MapTransformProtocol nil (map-vals-transform [structure next-fn] @@ -370,7 +383,21 @@ m (assoc m newk v)))) (empty structure) - structure))) + structure)) + + #?(:clj clojure.lang.IRecord :cljs cljs.core/IRecord) + (map-vals-transform [structure next-fn] + (reduce-kv + (fn [m k v] + (let [newv (next-fn v)] + (if (identical? newv i/NONE) + m + (assoc m k newv)))) + (empty-record structure) + structure)) + (map-keys-transform [structure _] + (throw (ex-info "Can't transform keys of a record" + {:record structure})))) (defn srange-select [structure start end next-fn] (next-fn diff --git a/test/com/rpl/specter/core_test.cljc b/test/com/rpl/specter/core_test.cljc index 1ba123c..a58f6a0 100644 --- a/test/com/rpl/specter/core_test.cljc +++ b/test/com/rpl/specter/core_test.cljc @@ -1693,6 +1693,16 @@ (multi-transform (s/terminal (f #?(:clj String :cljs js/String))) 1))) )) +(defrecord TestRecord [a b c]) + +(deftest map-navs-on-records-test + (let [r (TestRecord. 8 -12 91)] + (is (= {:a 9 :b -11 :c 92} (into {} (transform [s/MAP-VALS] inc r)))) + (is (thrown-with-msg? + Exception + #"Can't transform keys of a record" + (transform [s/MAP-KEYS] #(case % :a :x :b :y :c :z) r))))) + #?(:clj (do (defprotocolpath FooPP)