diff --git a/src/clj/com/rpl/specter/impl.cljx b/src/clj/com/rpl/specter/impl.cljx index 55ee39b..2fb618e 100644 --- a/src/clj/com/rpl/specter/impl.cljx +++ b/src/clj/com/rpl/specter/impl.cljx @@ -8,7 +8,7 @@ [select* transform* collect-val]]) (:require [com.rpl.specter.protocols :as p] [clojure.walk :as walk] - [clojure.core.reducers :as r] + #+clj [clojure.core.reducers :as r] [clojure.string :as s] #+clj [com.rpl.specter.defhelpers :as dh] ) @@ -502,12 +502,30 @@ (assoc structure akey (next-fn (get structure akey)) )) +#+clj (defn all-select [structure next-fn] (into [] (r/mapcat next-fn structure))) +#+cljs +(defn next-fn-mapcat-transformation [next-fn] + (mapcat #(next-fn %1))) + +#+cljs +(defn all-select [structure next-fn] + (into [] (next-fn-mapcat-transformation next-fn) structure)) + +#+cljs +(defn queue? [coll] + (= (type coll) (type #queue []))) + +#+clj +(defn queue? [coll] + (= (type coll) (type clojure.lang.PersistentQueue/EMPTY))) + +#+clj (defn all-transform [structure next-fn] (let [empty-structure (empty structure)] - (cond (list? empty-structure) + (cond (and (list? empty-structure) (not (queue? empty-structure))) ;; this is done to maintain order, otherwise lists get reversed (doall (map next-fn structure)) @@ -518,6 +536,19 @@ (->> structure (r/map next-fn) (into empty-structure)) ))) +#+cljs +(defn next-fn-map-transformation [next-fn] + (map #(next-fn %1))) + +#+cljs +(defn all-transform [structure next-fn] + (let [empty-structure (empty structure)] + (if (and (list? empty-structure) (not (queue? empty-structure))) + ;; this is done to maintain order, otherwise lists get reversed + (doall (map next-fn structure)) + (into empty-structure (next-fn-map-transformation next-fn) structure) + ))) + (deftype AllStructurePath []) (extend-protocol p/StructurePath diff --git a/test/com/rpl/specter/core_test.cljx b/test/com/rpl/specter/core_test.cljx index 442d7a4..34a0397 100644 --- a/test/com/rpl/specter/core_test.cljx +++ b/test/com/rpl/specter/core_test.cljx @@ -740,3 +740,41 @@ (is (= [2 3 [[[4]] :b 0] {:a 4 :b 10}] (s/transform [CustomWalker number?] inc [1 2 [[[3]] :b -1] {:a 3 :b 10}]))) ) + +#+cljs +(defn make-queue [coll] + (reduce + #(conj %1 %2) + #queue [] + coll)) + +#+clj +(defn make-queue [coll] + (reduce + #(conj %1 %2) + clojure.lang.PersistentQueue/EMPTY + coll)) + +(defspec transform-idempotency + (for-all+ + [v1 (gen/vector gen/int) + l1 (gen/list gen/int) + m1 (gen/map gen/keyword gen/int)] + (let [s1 (set v1) + q1 (make-queue v1) + v2 (s/transform s/ALL identity v1) + m2 (s/transform s/ALL identity m1) + s2 (s/transform s/ALL identity s1) + l2 (s/transform s/ALL identity l1) + q2 (s/transform s/ALL identity q1)] + (and + (= v1 v2) + (= (type v1) (type v2)) + (= m1 m2) + (= (type m1) (type m2)) + (= s1 s2) + (= (type s1) (type s2)) + (= l1 l2) + (seq? l2) ;; Transformed lists are only guaranteed to impelment ISeq + (= q1 q2) + (= (type q1) (type q2))))))