diff --git a/src/clj/com/rpl/specter.cljx b/src/clj/com/rpl/specter.cljx index a93e01e..0889a3c 100644 --- a/src/clj/com/rpl/specter.cljx +++ b/src/clj/com/rpl/specter.cljx @@ -271,6 +271,27 @@ ancestry)) ))) +(defn subselect + "Navigates to a sequence that contains the results of (select ...), + but is a view to the original structure that can be transformed. + + Requires that the input navigators will walk the structure's + children in the same order when executed on \"select\" and then + \"transform\"." + [& path] + (fixed-pathed-path [late path] + (select* [this structure next-fn] + (next-fn (compiled-select late structure))) + (transform* [this structure next-fn] + (let [select-result (compiled-select late structure) + transformed (next-fn select-result) + values-to-insert (i/mutable-cell transformed)] + (compiled-transform late + (fn [_] (let [next-val (first (i/get-cell values-to-insert))] + (i/update-cell! values-to-insert rest) + next-val)) + structure))))) + (defpath keypath [key] (select* [this structure next-fn] (next-fn (get structure key))) diff --git a/test/com/rpl/specter/core_test.cljx b/test/com/rpl/specter/core_test.cljx index 8a8130c..4123a50 100644 --- a/test/com/rpl/specter/core_test.cljx +++ b/test/com/rpl/specter/core_test.cljx @@ -510,6 +510,37 @@ )) )) +(defspec subselect-nested-vectors + (for-all+ + [v1 (gen/vector + (gen/vector gen/int))] + (let [path (s/comp-paths (s/subselect s/ALL s/ALL)) + v2 (s/compiled-transform path reverse v1)] + (and + (= (s/compiled-select path v1) [(flatten v1)]) + (= (flatten v1) (reverse (flatten v2))) + (= (map count v1) (map count v2)))))) + +(defspec subselect-param-test + (for-all+ + [k gen/keyword + v (gen/vector + (limit-size 5 + (gen-map-with-keys + gen/keyword + gen/int + k)))] + (and + (= (s/compiled-select ((s/subselect s/ALL s/keypath) k) v) + [(map k v)]) + (let [v2 (s/compiled-transform ((s/comp-paths (s/subselect s/ALL s/keypath)) k) + reverse + v)] + (and (= (map k v) (reverse (map k v2))) + (= (map #(dissoc % k) v) + (map #(dissoc % k) v2))) ; only key k was touched in any of the maps + )))) + (defspec param-multi-path-test (for-all+ [k1 gen/keyword @@ -652,8 +683,8 @@ (is (= {:a {:aaa 4 :b {:c {:aaa 3} :aaa 2}}} (s/transform (map-key-walker :aaa) inc {:a {:aaa 3 :b {:c {:aaa 2} :aaa 1}}}))) - (is (= {:a {:c {:b "X"}}}) - (s/setval (map-key-walker :b) "X" {:a {:c {:b {:d 1}}}})) + (is (= {:a {:c {:b "X"}}} + (s/setval (map-key-walker :b) "X" {:a {:c {:b {:d 1}}}}))) ) (deftest recursive-params-composable-path-test