diff --git a/src/clj/com/rpl/specter.clj b/src/clj/com/rpl/specter.clj index d46c448..f117e99 100644 --- a/src/clj/com/rpl/specter.clj +++ b/src/clj/com/rpl/specter.clj @@ -57,22 +57,22 @@ [selector structure] (compiled-select-first (comp-unoptimal selector) structure)) -;; Update functions +;; Transformfunctions -(def ^{:doc "Version of update that takes in a selector pre-compiled with comp-paths"} - compiled-update compiled-update*) +(def ^{:doc "Version of transform that takes in a selector pre-compiled with comp-paths"} + compiled-transform compiled-transform*) -(defn update +(defn transform "Navigates to each value specified by the selector and replaces it by the result of running - the update-fn on it" - [selector update-fn structure] - (compiled-update (comp-unoptimal selector) update-fn structure)) + the transform-fn on it" + [selector transform-fn structure] + (compiled-transform (comp-unoptimal selector) transform-fn structure)) (defn compiled-setval "Version of setval that takes in a selector pre-compiled with comp-paths" [selector val structure] - (compiled-update selector (fn [_] val) structure)) + (compiled-transform selector (fn [_] val) structure)) (defn setval "Navigates to each value specified by the selector and replaces it by val" @@ -81,11 +81,11 @@ (defn compiled-replace-in "Version of replace-in that takes in a selector pre-compiled with comp-paths" - [selector update-fn structure & {:keys [merge-fn] :or {merge-fn concat}}] + [selector transform-fn structure & {:keys [merge-fn] :or {merge-fn concat}}] (let [state (mutable-cell nil)] - [(compiled-update selector + [(compiled-transform selector (fn [e] - (let [res (update-fn e)] + (let [res (transform-fn e)] (if res (let [[ret user-ret] res] (->> user-ret @@ -99,13 +99,13 @@ )) (defn replace-in - "Similar to update, except returns a pair of [updated-structure sequence-of-user-ret]. - The update-fn in this case is expected to return [ret user-ret]. ret is - what's used to update the data structure, while user-ret will be added to the user-ret sequence + "Similar to transform, except returns a pair of [transformd-structure sequence-of-user-ret]. + The transform-fn in this case is expected to return [ret user-ret]. ret is + what's used to transform the data structure, while user-ret will be added to the user-ret sequence in the final return. replace-in is useful for situations where you need to know the specific values - of what was updated in the data structure." - [selector update-fn structure & {:keys [merge-fn] :or {merge-fn concat}}] - (compiled-replace-in (comp-unoptimal selector) update-fn structure :merge-fn merge-fn)) + of what was transformd in the data structure." + [selector transform-fn structure & {:keys [merge-fn] :or {merge-fn concat}}] + (compiled-replace-in (comp-unoptimal selector) transform-fn structure :merge-fn merge-fn)) ;; Built-in pathing and context operations @@ -154,7 +154,7 @@ StructurePath (select* [kw structure next-fn] (next-fn (get structure kw))) - (update* [kw structure next-fn] + (transform* [kw structure next-fn] (assoc structure kw (next-fn (get structure kw))) )) @@ -163,7 +163,7 @@ (select* [afn structure next-fn] (if (afn structure) (next-fn structure))) - (update* [afn structure next-fn] + (transform* [afn structure next-fn] (if (afn structure) (next-fn structure) structure))) @@ -176,11 +176,11 @@ (defn putval "Adds an external value to the collected vals. Useful when additional arguments - are required to the update function that would otherwise require partial + are required to the transform function that would otherwise require partial application or a wrapper function. e.g., incrementing val at path [:a :b] by 3: - (update [:a :b (putval 3)] + some-map)" + (transform [:a :b (putval 3)] + some-map)" [val] (->PutValCollector val)) diff --git a/src/clj/com/rpl/specter/impl.clj b/src/clj/com/rpl/specter/impl.clj index 8113b79..6b864a5 100644 --- a/src/clj/com/rpl/specter/impl.clj +++ b/src/clj/com/rpl/specter/impl.clj @@ -15,7 +15,7 @@ (dotimes [_ iters] (afn)))) -(deftype ExecutorFunctions [type select-executor update-executor]) +(deftype ExecutorFunctions [type select-executor transform-executor]) (def StructureValsPathExecutor (->ExecutorFunctions @@ -24,12 +24,12 @@ (selector [] structure (fn [vals structure] (if-not (empty? vals) [(conj vals structure)] [structure])))) - (fn [updater update-fn structure] - (updater [] structure + (fn [transformer transform-fn structure] + (transformer [] structure (fn [vals structure] (if (empty? vals) - (update-fn structure) - (apply update-fn (conj vals structure)))))) + (transform-fn structure) + (apply transform-fn (conj vals structure)))))) )) (def StructurePathExecutor @@ -37,11 +37,11 @@ :spath (fn [selector structure] (selector structure (fn [structure] [structure]))) - (fn [updater update-fn structure] - (updater structure update-fn)) + (fn [transformer transform-fn structure] + (transformer structure transform-fn)) )) -(deftype TransformFunctions [executors selector updater]) +(deftype TransformFunctions [executors selector transformer]) (defprotocol CoerceTransformFunctions @@ -64,13 +64,13 @@ (defn coerce-structure-vals-path [this] (let [pimpl (find-protocol-impl! StructureValsPath this) selector (:select-full* pimpl) - updater (:update-full* pimpl)] + transformer (:transform-full* pimpl)] (->TransformFunctions StructureValsPathExecutor (fn [vals structure next-fn] (selector this vals structure next-fn)) (fn [vals structure next-fn] - (updater this vals structure next-fn))) + (transformer this vals structure next-fn))) )) (defn coerce-collector [this] @@ -93,25 +93,25 @@ (defn coerce-structure-path [this] (let [pimpl (structure-path-impl this) selector (:select* pimpl) - updater (:update* pimpl)] + transformer (:transform* pimpl)] (->TransformFunctions StructurePathExecutor (fn [structure next-fn] (selector this structure next-fn)) (fn [structure next-fn] - (updater this structure next-fn)) + (transformer this structure next-fn)) ))) (defn coerce-structure-path-direct [this] (let [pimpl (structure-path-impl this) selector (:select* pimpl) - updater (:update* pimpl)] + transformer (:transform* pimpl)] (->TransformFunctions StructureValsPathExecutor (fn [vals structure next-fn] (selector this structure (fn [structure] (next-fn vals structure)))) (fn [vals structure next-fn] - (updater this structure (fn [structure] (next-fn vals structure)))) + (transformer this structure (fn [structure] (next-fn vals structure)))) ))) (defn obj-extends? [prot obj] @@ -171,7 +171,7 @@ (->TransformFunctions exs (combiner (.selector curr) (.selector next)) - (combiner (.updater curr) (.updater next)) + (combiner (.transformer curr) (.transformer next)) )) all)))) @@ -179,13 +179,13 @@ (if (= (extype tfns) :svalspath) tfns (let [selector (.selector tfns) - updater (.updater tfns)] + transformer (.transformer tfns)] (->TransformFunctions StructureValsPathExecutor (fn [vals structure next-fn] (selector structure (fn [structure] (next-fn vals structure)))) (fn [vals structure next-fn] - (updater structure (fn [structure] (next-fn vals structure)))) + (transformer structure (fn [structure] (next-fn vals structure)))) )))) (extend-protocol StructureValsPathComposer @@ -218,7 +218,7 @@ )) ;;this composes paths together much faster than comp-paths* but the resulting composition -;;won't execute as fast. Useful for when select/update are used without pre-compiled paths +;;won't execute as fast. Useful for when select/transform are used without pre-compiled paths ;;(where cost of compiling dominates execution time) (defn comp-unoptimal [sp] (if (instance? java.util.List sp) @@ -307,10 +307,10 @@ ((.select-executor ex) (.selector tfns) structure) )) -(defn compiled-update* - [^com.rpl.specter.impl.TransformFunctions tfns update-fn structure] +(defn compiled-transform* + [^com.rpl.specter.impl.TransformFunctions tfns transform-fn structure] (let [^com.rpl.specter.impl.ExecutorFunctions ex (.executors tfns)] - ((.update-executor ex) (.updater tfns) update-fn structure) + ((.transform-executor ex) (.transformer tfns) transform-fn structure) )) (defn selected?* @@ -348,7 +348,7 @@ (defn key-select [akey structure next-fn] (next-fn (get structure akey))) -(defn key-update [akey structure next-fn] +(defn key-transform [akey structure next-fn] (assoc structure akey (next-fn (get structure akey)) )) @@ -358,7 +358,7 @@ AllStructurePath (select* [this structure next-fn] (into [] (r/mapcat next-fn structure))) - (update* [this structure next-fn] + (transform* [this structure next-fn] (let [empty-structure (empty structure)] (if (list? empty-structure) ;; this is done to maintain order, otherwise lists get reversed @@ -379,7 +379,7 @@ LastStructurePath (select* [this structure next-fn] (next-fn (last structure))) - (update* [this structure next-fn] + (transform* [this structure next-fn] (set-last structure (next-fn (last structure))))) (deftype FirstStructurePath []) @@ -388,7 +388,7 @@ FirstStructurePath (select* [this structure next-fn] (next-fn (first structure))) - (update* [this structure next-fn] + (transform* [this structure next-fn] (set-first structure (next-fn (first structure))))) (deftype WalkerStructurePath [afn]) @@ -397,7 +397,7 @@ WalkerStructurePath (select* [^WalkerStructurePath this structure next-fn] (walk-select (.afn this) next-fn structure)) - (update* [^WalkerStructurePath this structure next-fn] + (transform* [^WalkerStructurePath this structure next-fn] (walk-until (.afn this) next-fn structure))) (deftype CodeWalkerStructurePath [afn]) @@ -406,7 +406,7 @@ CodeWalkerStructurePath (select* [^CodeWalkerStructurePath this structure next-fn] (walk-select (.afn this) next-fn structure)) - (update* [^CodeWalkerStructurePath this structure next-fn] + (transform* [^CodeWalkerStructurePath this structure next-fn] (codewalk-until (.afn this) next-fn structure))) @@ -416,7 +416,7 @@ FilterStructurePath (select* [^FilterStructurePath this structure next-fn] (->> structure (filter #(selected?* (.path this) %)) doall next-fn)) - (update* [^FilterStructurePath this structure next-fn] + (transform* [^FilterStructurePath this structure next-fn] (let [[filtered ancestry] (filter+ancestry (.path this) structure) ;; the vec is necessary so that we can get by index later ;; (can't get by index for cons'd lists) @@ -432,8 +432,8 @@ KeyPath (select* [^KeyPath this structure next-fn] (key-select (.akey this) structure next-fn)) - (update* [^KeyPath this structure next-fn] - (key-update (.akey this) structure next-fn) + (transform* [^KeyPath this structure next-fn] + (key-transform (.akey this) structure next-fn) )) (deftype SelectCollector [sel-fn selector]) @@ -452,7 +452,7 @@ end ((.end-fn this) structure)] (next-fn (-> structure vec (subvec start end))) )) - (update* [^SRangePath this structure next-fn] + (transform* [^SRangePath this structure next-fn] (let [start ((.start-fn this) structure) end ((.end-fn this) structure) structurev (vec structure) @@ -471,7 +471,7 @@ ViewPath (select* [^ViewPath this structure next-fn] (->> structure ((.view-fn this)) next-fn)) - (update* [^ViewPath this structure next-fn] + (transform* [^ViewPath this structure next-fn] (->> structure ((.view-fn this)) next-fn) )) @@ -488,10 +488,11 @@ nil (select* [this structure next-fn] (next-fn structure)) - (update* [this structure next-fn] + (transform* [this structure next-fn] (next-fn structure) )) + (deftype ConditionalPath [cond-pairs]) (defn- retrieve-selector [cond-pairs structure] @@ -512,9 +513,9 @@ (->> (compiled-select* selector structure) (mapcat next-fn) doall))) - (update* [this structure next-fn] + (transform* [this structure next-fn] (if-let [selector (retrieve-selector (.cond-pairs this) structure)] - (compiled-update* selector next-fn structure) + (compiled-transform* selector next-fn structure) structure ))) diff --git a/src/clj/com/rpl/specter/protocols.clj b/src/clj/com/rpl/specter/protocols.clj index 2a4912e..a87cc8a 100644 --- a/src/clj/com/rpl/specter/protocols.clj +++ b/src/clj/com/rpl/specter/protocols.clj @@ -2,11 +2,11 @@ (defprotocol StructureValsPath (select-full* [this vals structure next-fn]) - (update-full* [this vals structure next-fn])) + (transform-full* [this vals structure next-fn])) (defprotocol StructurePath (select* [this structure next-fn]) - (update* [this structure next-fn])) + (transform* [this structure next-fn])) (defprotocol Collector (collect-val [this structure])) diff --git a/test/clj/com/rpl/specter/core_test.clj b/test/clj/com/rpl/specter/core_test.clj index 54e0a9f..5e94f01 100644 --- a/test/clj/com/rpl/specter/core_test.clj +++ b/test/clj/com/rpl/specter/core_test.clj @@ -58,67 +58,67 @@ (is (nil? (select-first [ALL even?] [1 3 5 9]))) ) -(defspec update-all-on-map +(defspec transform-all-on-map (for-all+ [m (max-size 5 (gen/map gen/keyword gen/int))] - (= (update [ALL LAST] inc m) + (= (transform [ALL LAST] inc m) (into {} (for [[k v] m] [k (inc v)])) ))) -(defspec update-all +(defspec transform-all (for-all+ [v (gen/vector gen/int)] - (let [v2 (update [ALL] inc v)] + (let [v2 (transform [ALL] inc v)] (and (vector? v2) (= v2 (map inc v))) ))) -(defspec update-all-list +(defspec transform-all-list (for-all+ [v (gen/list gen/int)] - (let [v2 (update [ALL] inc v)] + (let [v2 (transform [ALL] inc v)] (and (seq? v2) (= v2 (map inc v))) ))) -(defspec update-all-filter +(defspec transform-all-filter (for-all+ [v (gen/vector gen/int) pred (gen/elements [odd? even?]) action (gen/elements [inc dec])] - (let [v2 (update [ALL pred] action v)] + (let [v2 (transform [ALL pred] action v)] (= v2 (map (fn [v] (if (pred v) (action v) v)) v)) ))) -(defspec update-last +(defspec transform-last (for-all+ [v (gen/not-empty (gen/vector gen/int)) pred (gen/elements [inc dec])] - (let [v2 (update [LAST] pred v)] + (let [v2 (transform [LAST] pred v)] (= v2 (concat (butlast v) [(pred (last v))])) ))) -(defspec update-first +(defspec transform-first (for-all+ [v (gen/not-empty (gen/vector gen/int)) pred (gen/elements [inc dec])] - (let [v2 (update [FIRST] pred v)] + (let [v2 (transform [FIRST] pred v)] (= v2 (concat [(pred (first v))] (rest v) )) ))) -(defspec update-filterer-all-equivalency +(defspec transform-filterer-all-equivalency (prop/for-all [v (gen/vector gen/int)] - (let [v2 (update [(filterer odd?) ALL] inc v) - v3 (update [ALL odd?] inc v)] + (let [v2 (transform [(filterer odd?) ALL] inc v) + v3 (transform [ALL odd?] inc v)] (= v2 v3)) )) -(defspec update-with-context +(defspec transform-with-context (for-all+ [kw1 gen/keyword kw2 gen/keyword m (max-size 10 (gen-map-with-keys gen/keyword gen/int kw1 kw2)) pred (gen/elements [odd? even?])] - (= (update [(collect-one kw2) kw1 pred] + m) + (= (transform [(collect-one kw2) kw1 pred] + m) (if (pred (kw1 m)) (assoc m kw1 (+ (kw1 m) (kw2 m))) m @@ -131,10 +131,10 @@ i))) (filter identity))) -(defspec update-last-compound +(defspec transform-last-compound (for-all+ [v (gen/such-that #(some odd? %) (gen/vector gen/int))] - (let [v2 (update [(filterer odd?) LAST] inc v) + (let [v2 (transform [(filterer odd?) LAST] inc v) differing-elems (differing-elements v v2)] (and (= (count v2) (count v)) (= (count differing-elems) 1) @@ -142,7 +142,7 @@ )))) ;; max sizes prevent too much data from being generated and keeps test from taking forever -(defspec update-keyword +(defspec transform-keyword (for-all+ [k1 (max-size 3 gen/keyword) k2 (max-size 3 gen/keyword) @@ -152,7 +152,7 @@ (gen-map-with-keys gen/keyword gen/int k2) k1)) pred (gen/elements [inc dec])] - (let [m2 (update [k1 k2] pred m1)] + (let [m2 (transform [k1 k2] pred m1)] (= (assoc-in m1 [k1 k2] nil) (assoc-in m2 [k1 k2] nil)) (= (pred (get-in m1 [k1 k2])) (get-in m2 [k1 k2])) ))) @@ -201,7 +201,7 @@ predcount (fn [pred v] (->> v (filter pred) count)) even-count (partial predcount even?) odd-count (partial predcount odd?) - b (update (srange b e) (fn [r] (filter odd? r)) v)] + b (transform (srange b e) (fn [r] (filter odd? r)) v)] (and (= (odd-count v) (odd-count b)) (= (+ (even-count b) (even-count sv)) (even-count v))) @@ -219,7 +219,7 @@ (= (first (select (view afn) i)) (first (select (viewfn [i] (afn i)) i)) (afn i) - (update (view afn) identity i) + (transform (view afn) identity i) ))) (deftest selected?-test @@ -234,7 +234,7 @@ [i gen/int afn (gen/elements [inc dec])] (and (= [i] (select nil i)) - (= (afn i) (update nil afn i))))) + (= (afn i) (transform nil afn i))))) (deftest nil-comp-test (is (= [5] (select (comp-paths* nil) 5)))) @@ -244,8 +244,8 @@ [kw gen/keyword m (max-size 10 (gen-map-with-keys gen/keyword gen/int kw)) c gen/int] - (= (update [(putval c) kw] + m) - (update [kw (putval c)] + m) + (= (transform [(putval c) kw] + m) + (transform [kw (putval c)] + m) (assoc m kw (+ c (get m kw))) ))) @@ -260,20 +260,20 @@ (select [nil nil nil] v) ))) -(defspec empty-selector-update-test +(defspec empty-selector-transform-test (for-all+ [kw gen/keyword m (max-size 10 (gen-map-with-keys gen/keyword gen/int kw))] (and (= m - (update nil identity m) - (update [] identity m) - (update (comp-paths []) identity m) - (update (comp-paths nil nil) identity m) + (transform nil identity m) + (transform [] identity m) + (transform (comp-paths []) identity m) + (transform (comp-paths nil nil) identity m) ) - (= (update kw inc m) - (update [nil kw] inc m) - (update (comp-paths kw nil) inc m) - (update (comp-paths nil kw nil) inc m) + (= (transform kw inc m) + (transform [nil kw] inc m) + (transform (comp-paths kw nil) inc m) + (transform (comp-paths nil kw nil) inc m) )))) (deftest compose-empty-comp-path-test @@ -307,14 +307,14 @@ [1 2 3 4 5 6 7 8]))) (is (empty? (select (if-path odd? (view inc)) 2))) (is (= [6 2 10 6 14] - (update [(putval 2) + (transform [(putval 2) ALL (if-path odd? [(view inc) (view inc)] (view dec))] * [1 2 3 4 5] ))) (is (= 2 - (update [(putval 2) + (transform [(putval 2) (if-path odd? (view inc))] * 2))) @@ -337,8 +337,8 @@ (let [v1 (get m k1) k (if (pred v1) k2 k3)] (and - (= (update (if-path [k1 pred] k2 k3) inc m) - (update k inc m)) + (= (transform (if-path [k1 pred] k2 k3) inc m) + (transform k inc m)) (= (select (if-path [k1 pred] k2 k3) m) (select k m)) ))))