Merge branch 'master' into traverse
This commit is contained in:
commit
66d1ce65f3
6 changed files with 109 additions and 3 deletions
|
|
@ -5,7 +5,9 @@
|
||||||
* 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)
|
||||||
* Bug fix: END, BEGINNING, FIRST, and LAST now work properly on nil
|
* 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, LAST, and MAP-VALS now work properly on nil
|
||||||
|
|
||||||
## 0.11.2
|
## 0.11.2
|
||||||
* Renamed com.rpl.specter.transient namespace to com.rpl.specter.transients to eliminate ClojureScript compiler warning about reserved keyword
|
* Renamed com.rpl.specter.transient namespace to com.rpl.specter.transients to eliminate ClojureScript compiler warning about reserved keyword
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ The latest release version of Specter is hosted on [Clojars](https://clojars.org
|
||||||
|
|
||||||
- Introductory blog post: [Functional-navigational programming in Clojure(Script) with Specter](http://nathanmarz.com/blog/functional-navigational-programming-in-clojurescript-with-sp.html)
|
- Introductory blog post: [Functional-navigational programming in Clojure(Script) with Specter](http://nathanmarz.com/blog/functional-navigational-programming-in-clojurescript-with-sp.html)
|
||||||
- Presentation about Specter: [Specter: Powerful and Simple Data Structure Manipulation](https://www.youtube.com/watch?v=VTCy_DkAJGk)
|
- Presentation about Specter: [Specter: Powerful and Simple Data Structure Manipulation](https://www.youtube.com/watch?v=VTCy_DkAJGk)
|
||||||
|
- List of navigators with examples: [This wiki page](https://github.com/nathanmarz/specter/wiki/List-of-Navigators) provides a more comprehensive overview than the API docs about the behavior of specific navigators and includes many examples.
|
||||||
- [API docs](http://nathanmarz.github.io/specter/)
|
- [API docs](http://nathanmarz.github.io/specter/)
|
||||||
- Performance guide: The [Specter 0.11.0 announcement post](https://github.com/nathanmarz/specter/wiki/Specter-0.11.0:-Performance-without-the-tradeoffs) provides a comprehensive overview of how Specter achieves its performance and what you need to know as a user to enable Specter to perform its optimizations.
|
- Performance guide: The [Specter 0.11.0 announcement post](https://github.com/nathanmarz/specter/wiki/Specter-0.11.0:-Performance-without-the-tradeoffs) provides a comprehensive overview of how Specter achieves its performance and what you need to know as a user to enable Specter to perform its optimizations.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -575,6 +575,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]
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
@ -893,6 +923,11 @@
|
||||||
structure))
|
structure))
|
||||||
|
|
||||||
(extend-protocol MapValsTransformProtocol
|
(extend-protocol MapValsTransformProtocol
|
||||||
|
nil
|
||||||
|
(map-vals-transform [structure next-fn]
|
||||||
|
nil
|
||||||
|
)
|
||||||
|
|
||||||
#+clj clojure.lang.PersistentArrayMap #+cljs cljs.core/PersistentArrayMap
|
#+clj clojure.lang.PersistentArrayMap #+cljs cljs.core/PersistentArrayMap
|
||||||
(map-vals-transform [structure next-fn]
|
(map-vals-transform [structure next-fn]
|
||||||
(map-vals-non-transient-transform structure {} next-fn)
|
(map-vals-non-transient-transform structure {} next-fn)
|
||||||
|
|
|
||||||
|
|
@ -620,3 +620,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))
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -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,58 @@
|
||||||
(is (empty? (select s/LAST nil)))
|
(is (empty? (select s/LAST nil)))
|
||||||
(is (empty? (select s/ALL nil)))
|
(is (empty? (select s/ALL nil)))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(deftest map-vals-nil
|
||||||
|
(is (= nil (transform s/MAP-VALS inc nil)))
|
||||||
|
(is (empty? (select s/MAP-VALS 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)
|
||||||
|
)))
|
||||||
|
(let [data {:active 3 :items [{:id 1 :val 0} {:id 3 :val 11}]}]
|
||||||
|
(is (= (transform [:items s/ALL (s/selected? :id #(= % 3)) :val] inc data)
|
||||||
|
(transform [(s/collect-one :active)
|
||||||
|
:items
|
||||||
|
s/ALL
|
||||||
|
(s/collect-one :id)
|
||||||
|
(collected? [a i] (= a i))
|
||||||
|
s/DISPENSE
|
||||||
|
:val]
|
||||||
|
inc
|
||||||
|
data)
|
||||||
|
))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue