added cond-path and if-path selectors

This commit is contained in:
Nathan Marz 2015-06-18 00:56:03 -04:00
parent 6ba23bc438
commit da2019b07b
3 changed files with 80 additions and 12 deletions

View file

@ -11,12 +11,8 @@
;; Selector functions
(defn compiled-select
"Version of select that takes in a selector pre-compiled with comp-paths"
[^com.rpl.specter.impl.TransformFunctions tfns structure]
(let [^com.rpl.specter.impl.ExecutorFunctions ex (.executors tfns)]
((.select-executor ex) (.selector tfns) structure)
))
(def ^{:doc "Version of select that takes in a selector pre-compiled with comp-paths"}
compiled-select compiled-select*)
(defn select
"Navigates to and returns a sequence of all the elements specified by the selector."
@ -63,12 +59,9 @@
;; Update functions
(defn compiled-update
"Version of update that takes in a selector pre-compiled with comp-paths"
[^com.rpl.specter.impl.TransformFunctions tfns update-fn structure]
(let [^com.rpl.specter.impl.ExecutorFunctions ex (.executors tfns)]
((.update-executor ex) (.updater tfns) update-fn structure)
))
(def ^{:doc "Version of update that takes in a selector pre-compiled with comp-paths"}
compiled-update compiled-update*)
(defn update
"Navigates to each value specified by the selector and replaces it by the result of running
@ -190,3 +183,22 @@
(update [:a :b (putval 3)] + some-map)"
[val]
(->PutValCollector val))
(defn cond-path
"Takes in alternating cond-fn selector cond-fn selector...
Tests the structure on the cond-fn, and if it matches uses the following selector for
the rest of the selector. Otherwise, it moves on to the next selector. If nothing
matches, then the structure is not selected."
[& conds]
(->> conds
(partition 2)
(map (fn [[c p]] [c (comp-paths* p)]))
doall
->ConditionalPath
))
(defn if-path
"Like cond-path, but with if semantics."
([cond-fn if-path] (cond-path cond-fn if-path))
([cond-fn if-path else-path]
(cond-path cond-fn if-path (fn [_] true) else-path)))

View file

@ -469,3 +469,39 @@
(update* [this structure next-fn]
(next-fn structure)
))
(defn compiled-select*
[^com.rpl.specter.impl.TransformFunctions tfns structure]
(let [^com.rpl.specter.impl.ExecutorFunctions ex (.executors tfns)]
((.select-executor ex) (.selector tfns) structure)
))
(defn compiled-update*
[^com.rpl.specter.impl.TransformFunctions tfns update-fn structure]
(let [^com.rpl.specter.impl.ExecutorFunctions ex (.executors tfns)]
((.update-executor ex) (.updater tfns) update-fn structure)
))
(deftype ConditionalPath [cond-pairs])
(defn- retrieve-selector [cond-pairs structure]
(->> cond-pairs
(drop-while (fn [[c-fn _]] (not (c-fn structure))))
first
second
))
;;TODO: test nothing matches case
(extend-protocol StructurePath
ConditionalPath
(select* [this structure next-fn]
(if-let [selector (retrieve-selector (.cond-pairs this) structure)]
(->> (compiled-select* selector structure)
(mapcat next-fn)
doall)))
(update* [this structure next-fn]
(if-let [selector (retrieve-selector (.cond-pairs this) structure)]
(compiled-update* selector next-fn structure)
structure
)))

View file

@ -295,3 +295,23 @@
(select [(comp-paths) k1 k2] m)
(select [k1 (comp-paths) k2] m)
)))
(deftest cond-path-test
(is (= [4 2 6 8 10]
(select [ALL (cond-path even? [(view inc) (view inc)]
#(= 3 %) (view dec))]
[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)
ALL
(if-path odd? [(view inc) (view inc)] (view dec))]
*
[1 2 3 4 5]
)))
(is (= 2
(update [(putval 2)
(if-path odd? (view inc))]
*
2)))
)