Merge pull request #10 from pietromenna/update-transform

Renamed update to transform because of Clojure 1.7
This commit is contained in:
Nathan Marz 2015-06-24 11:49:45 -04:00
commit 09ef28c25f
4 changed files with 98 additions and 97 deletions

View file

@ -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))

View file

@ -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
)))

View file

@ -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]))

View file

@ -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))
))))