diff --git a/CHANGES.md b/CHANGES.md index d3600fa..5c6aeb8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,7 @@ +## 1.0.6-SNAPSHOT + +* Add `vterminal` that takes in collected vals as vector in first argument rather than spliced into full argument list. + ## 1.0.5 * Add `regex-nav` navigator for regexes, which navigates to every match in a string and supports replacement with a new substring (thanks @mwfogleman) diff --git a/src/clj/com/rpl/specter.cljc b/src/clj/com/rpl/specter.cljc index e482d35..79b7b68 100644 --- a/src/clj/com/rpl/specter.cljc +++ b/src/clj/com/rpl/specter.cljc @@ -351,8 +351,8 @@ (defmacro multi-transform "Just like `transform` but expects transform functions to be specified - inline in the path using `terminal`. Error is thrown if navigation finishes - at a non-`terminal` navigator. `terminal-val` is a wrapper around `terminal` and is + inline in the path using `terminal` or `vterminal`. Error is thrown if navigation finishes + at a non-terminal navigator. `terminal-val` is a wrapper around `terminal` and is the `multi-transform` equivalent of `setval`. This macro will do inline caching of the path." [apath structure] @@ -564,8 +564,8 @@ (defn multi-transform* "Just like `transform` but expects transform functions to be specified - inline in the path using `terminal`. Error is thrown if navigation finishes - at a non-`terminal` navigator. `terminal-val` is a wrapper around `terminal` and is + inline in the path using `terminal` or `vterminal`. Error is thrown if navigation finishes + at a non-terminal navigator. `terminal-val` is a wrapper around `terminal` and is the `multi-transform` equivalent of `setval`." [path structure] (compiled-multi-transform (i/comp-paths* path) structure)) @@ -644,6 +644,19 @@ (transform* [this vals structure next-fn] (i/terminal* afn vals structure)))) +(def + ^{:doc "For usage with `multi-transform`, defines an endpoint in the navigation + that will have the parameterized transform function run. The transform + function works differently than it does in `transform`. Rather than receive + collected vals spliced in as the first arguments to the function, this function + always takes two arguemnts. The first is all collected + vals in a vector, and the second is the navigated value."} + vterminal + (richnav [afn] + (select* [this vals structure next-fn] + (i/throw-illegal "'terminal' should only be used in multi-transform")) + (transform* [this vals structure next-fn] + (afn vals structure)))) (defn ^:direct-nav terminal-val "Like `terminal` but specifies a val to set at the location regardless of diff --git a/test/com/rpl/specter/core_test.cljc b/test/com/rpl/specter/core_test.cljc index 3ed621a..2875cc3 100644 --- a/test/com/rpl/specter/core_test.cljc +++ b/test/com/rpl/specter/core_test.cljc @@ -1650,6 +1650,12 @@ (is (= 1 (select-any ["a" true \c 10 'd] {"a" {true {\c {10 {'d 1}}}}}))) ) +(deftest vterminal-test + (is (= {:a {:b [[1 2] 3]}} + (multi-transform [(s/putval 1) :a (s/putval 2) :b (s/vterminal (fn [vs v] [vs v]))] + {:a {:b 3}}))) + ) + #?(:clj (do (defprotocolpath FooPP)