added collected? and DISPENSE navigators

This commit is contained in:
Nathan Marz 2016-06-10 07:57:18 -04:00
parent 3af11575d7
commit 3dc7ad25ff
5 changed files with 86 additions and 2 deletions

View file

@ -5,6 +5,8 @@
* Added `selected-any?` operation that returns true if any element is navigated to. * Added `selected-any?` operation that returns true if any element is navigated to.
* Huge performance improvements to `select`, `select-one`, `select-first`, and `select-one!` * Huge performance improvements to `select`, `select-one`, `select-first`, and `select-one!`
* Added META navigator (thanks @aengelberg) * Added META navigator (thanks @aengelberg)
* Added DISPENSE navigator to drop all collected values for subsequent navigation
* Added `collected?` macro to create a filter function which operates on the collected values
* Bug fix: END, BEGINNING, FIRST, and LAST now work properly on nil * Bug fix: END, BEGINNING, FIRST, and LAST now work properly on nil
## 0.11.2 ## 0.11.2

View file

@ -564,6 +564,11 @@
(collect-val [this structure] (collect-val [this structure]
val )) val ))
(def
^{:doc "Drops all collected values for subsequent navigation."}
DISPENSE i/DISPENSE*)
(defpathedfn if-path (defpathedfn if-path
"Like cond-path, but with if semantics." "Like cond-path, but with if semantics."
([cond-p then-path] ([cond-p then-path]

View file

@ -609,6 +609,36 @@
ret ret
)))) ))))
(def collected?*
(->ParamsNeededPath
(->TransformFunctions
RichPathExecutor
(fn [params params-idx vals structure next-fn]
(let [afn (aget ^objects params params-idx)]
(if (afn vals)
(next-fn params (inc params-idx) vals structure)
NONE
)))
(fn [params params-idx vals structure next-fn]
(let [afn (aget ^objects params params-idx)]
(if (afn vals)
(next-fn params (inc params-idx) vals structure)
structure
))))
1
))
(def DISPENSE*
(no-params-compiled-path
(->TransformFunctions
RichPathExecutor
(fn [params params-idx vals structure next-fn]
(next-fn params params-idx [] structure))
(fn [params params-idx vals structure next-fn]
(next-fn params params-idx [] structure))
)))
(defn transform-fns-field [^CompiledPath path] (defn transform-fns-field [^CompiledPath path]
(.-transform-fns path)) (.-transform-fns path))

View file

@ -611,3 +611,11 @@
[apath transform-fn structure & args] [apath transform-fn structure & args]
`(i/compiled-replace-in* (path ~apath) ~transform-fn ~structure ~@args)) `(i/compiled-replace-in* (path ~apath) ~transform-fn ~structure ~@args))
(defmacro collected?
"Creates a filter function navigator that takes in all the collected values
as input. For arguments, can use `(collected? [a b] ...)` syntax to look
at each collected value as individual arguments, or `(collected? v ...)` syntax
to capture all the collected values as a single vector."
[params & body]
`(i/collected?* (fn [~params] ~@body))
)

View file

@ -8,7 +8,7 @@
:refer [paramsfn defprotocolpath defnav extend-protocolpath :refer [paramsfn defprotocolpath defnav extend-protocolpath
nav declarepath providepath select select-one select-one! nav declarepath providepath select select-one select-one!
select-first transform setval replace-in defnavconstructor select-first transform setval replace-in defnavconstructor
select-any selected-any?]]) select-any selected-any? collected?]])
(:use (:use
#+clj [clojure.test :only [deftest is]] #+clj [clojure.test :only [deftest is]]
#+clj [clojure.test.check.clojure-test :only [defspec]] #+clj [clojure.test.check.clojure-test :only [defspec]]
@ -17,7 +17,7 @@
:only [paramsfn defprotocolpath defnav extend-protocolpath :only [paramsfn defprotocolpath defnav extend-protocolpath
nav declarepath providepath select select-one select-one! nav declarepath providepath select select-one select-one!
select-first transform setval replace-in defnavconstructor select-first transform setval replace-in defnavconstructor
select-any selected-any?]] select-any selected-any? collected?]]
) )
@ -1201,3 +1201,42 @@
(is (empty? (select s/LAST nil))) (is (empty? (select s/LAST nil)))
(is (empty? (select s/ALL nil))) (is (empty? (select s/ALL nil)))
) )
(defspec dispense-test
(for-all+
[k1 gen/int
k2 gen/int
k3 gen/int
m (gen-map-with-keys gen/int gen/int k1 k2 k3)]
(= (select [(s/collect-one (s/keypath k1))
(s/collect-one (s/keypath k2))
s/DISPENSE
(s/collect-one (s/keypath k2))
(s/keypath k3)]
m)
(select [(s/collect-one (s/keypath k2))
(s/keypath k3)]
m)
)))
(deftest collected?-test
(let [data {:active-id 1 :items [{:id 1 :name "a"} {:id 2 :name "b"}]}]
(is (= {:id 1 :name "a"}
(select-any [(s/collect-one :active-id)
:items
s/ALL
(s/collect-one :id)
(collected? [a i] (= a i))
s/DISPENSE
]
data)
(select-any [(s/collect-one :active-id)
:items
s/ALL
(s/collect-one :id)
(collected? v (apply = v))
s/DISPENSE
]
data)
))
))