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.
|
||||
* Huge performance improvements to `select`, `select-one`, `select-first`, and `select-one!`
|
||||
* 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
|
||||
* 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)
|
||||
- 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/)
|
||||
- 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]
|
||||
val ))
|
||||
|
||||
(def
|
||||
^{:doc "Drops all collected values for subsequent navigation."}
|
||||
DISPENSE i/DISPENSE*)
|
||||
|
||||
|
||||
(defpathedfn if-path
|
||||
"Like cond-path, but with if semantics."
|
||||
([cond-p then-path]
|
||||
|
|
|
|||
|
|
@ -609,6 +609,36 @@
|
|||
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]
|
||||
(.-transform-fns path))
|
||||
|
||||
|
|
@ -893,6 +923,11 @@
|
|||
structure))
|
||||
|
||||
(extend-protocol MapValsTransformProtocol
|
||||
nil
|
||||
(map-vals-transform [structure next-fn]
|
||||
nil
|
||||
)
|
||||
|
||||
#+clj clojure.lang.PersistentArrayMap #+cljs cljs.core/PersistentArrayMap
|
||||
(map-vals-transform [structure next-fn]
|
||||
(map-vals-non-transient-transform structure {} next-fn)
|
||||
|
|
|
|||
|
|
@ -620,3 +620,11 @@
|
|||
[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
|
||||
nav declarepath providepath select select-one select-one!
|
||||
select-first transform setval replace-in defnavconstructor
|
||||
select-any selected-any?]])
|
||||
select-any selected-any? collected?]])
|
||||
(:use
|
||||
#+clj [clojure.test :only [deftest is]]
|
||||
#+clj [clojure.test.check.clojure-test :only [defspec]]
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
:only [paramsfn defprotocolpath defnav extend-protocolpath
|
||||
nav declarepath providepath select select-one select-one!
|
||||
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/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