From 6a2afccbfda97b492ea2222ec95ecfec4fa2f7c3 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Thu, 25 Jun 2015 16:30:27 -0400 Subject: [PATCH] add multi-path implementation --- src/clj/com/rpl/specter.clj | 6 ++++++ src/clj/com/rpl/specter/impl.clj | 19 +++++++++++++++++++ test/clj/com/rpl/specter/core_test.clj | 17 +++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/clj/com/rpl/specter.clj b/src/clj/com/rpl/specter.clj index f117e99..ee7f494 100644 --- a/src/clj/com/rpl/specter.clj +++ b/src/clj/com/rpl/specter.clj @@ -203,3 +203,9 @@ ([cond-fn if-path] (cond-path cond-fn if-path)) ([cond-fn if-path else-path] (cond-path cond-fn if-path nil else-path))) + +(defn multi-path + "A path that branches on multiple paths. For updates, + applies updates to the paths in order." + [& paths] + (->MultiPath (->> paths (map comp-paths*) doall))) diff --git a/src/clj/com/rpl/specter/impl.clj b/src/clj/com/rpl/specter/impl.clj index 6b864a5..a171ed1 100644 --- a/src/clj/com/rpl/specter/impl.clj +++ b/src/clj/com/rpl/specter/impl.clj @@ -47,6 +47,7 @@ (defprotocol CoerceTransformFunctions (coerce-path [this])) + (defn no-prot-error-str [obj] (str "Protocol implementation cannot be found for object. Extending Specter protocols should not be done inline in a deftype definition @@ -519,3 +520,21 @@ structure ))) +(deftype MultiPath [paths]) + +(extend-protocol StructurePath + MultiPath + (select* [this structure next-fn] + (->> (.paths this) + (mapcat #(compiled-select* % structure)) + (mapcat next-fn) + doall + )) + (transform* [this structure next-fn] + (reduce + (fn [structure selector] + (compiled-transform* selector next-fn structure)) + structure + (.paths this)) + )) + diff --git a/test/clj/com/rpl/specter/core_test.clj b/test/clj/com/rpl/specter/core_test.clj index 0111004..610b4f3 100644 --- a/test/clj/com/rpl/specter/core_test.clj +++ b/test/clj/com/rpl/specter/core_test.clj @@ -345,3 +345,20 @@ (= (select (if-path [k1 pred] k2 k3) m) (select k m)) )))) + +(defspec multi-path-test + (for-all+ + [k1 (max-size 3 gen/keyword) + k2 (max-size 3 gen/keyword) + m (max-size 5 + (gen-map-with-keys + gen/keyword + gen/int + k1 + k2)) + ] + (= (transform (multi-path k1 k2) inc m) + (->> m + (transform k1 inc) + (transform k2 inc))) + ))