-
Notifications
You must be signed in to change notification settings - Fork 105
List of Navigators
It is a convention in Specter that unparameterized navigators are capitalized, whereas parameterized navigators and macros are lowercase. When writing your own navigators, you can follow this convention for consistency and readability.
Note: Many of the descriptions and a couple of the examples are lightly edited from those found on the Codox documentation.
Table of Contents
- Unparameterized Navigators
-
Parameterized Navigators (and Functions)
- before-index
- codewalker
- collect
- collect-one
- comp-paths
- compact
- compiled-select
- compiled-select-any
- compiled-select-first
- compiled-select-one
- compiled-select-one!
- compiled-selected-any?
- compiled-setval
- compiled-transform
- compiled-traverse
- compiled-traverse-all
- cond-path
- continue-then-stay
- continuous-subseqs
- eachnav
- filterer
- if-path
- index-nav
- keypath
- map-key
- multi-path
- must
- nil->val
- nthpath
- parser
- pred
- pred=
- pred<
- pred<=
- pred>
- pred>=
- putval
- not-selected?
- regex-nav
- selected?
- set-elem
- srange
- srange-dynamic
- stay-then-continue
- submap
- subselect
- subset
- terminal
- terminal-val
- transformed
- traversed
- view
- walker
- with-fresh-collected
AFTER-ELEM
navigates to the 'void' element after the sequence. For transformations – if result is not NONE
, then append that value.
=> (setval AFTER-ELEM 3 [1 2])
[1 2 3]
ALL
navigates to every element in a collection. If the collection is a map, it will navigate to each key-value pair [key value]
.
=> (select ALL [0 1 2 3])
[0 1 2 3]
=> (select ALL (list 0 1 2 3))
[0 1 2 3]
=> (select ALL {:a :b, :c :d})
[[:a :b] [:c :d]]
=> (transform ALL identity {:a :b, :c :d})
{:a :b, :c :d}
ALL
can transform to NONE
to remove elements.
=> (setval [ALL nil?] NONE [1 2 nil 3 nil])
[1 2 3]
ALL-WITH-META
is the same as ALL
, except it maintains metadata on the structure in transforms. This navigator exists solely for transforms, especially for codewalker
. There's no metadata to maintain on select
, since it navigates into the subvalues.
=> (select ALL ^{:purpose "Count"} [0 1 2 3])
[0 1 2 3]
=> (meta (select ALL ^{:purpose "Count"} [0 1 2 3]))
nil
=> (select ALL-WITH-META ^{:purpose "Count"} [0 1 2 3])
[0 1 2 3]
=> (meta (select ALL-WITH-META ^{:purpose "Count"} [0 1 2 3]))
nil
=> (transform ALL-WITH-META inc ^{:purpose "Count"} [0 1 2 3])
[1 2 3 4]
=> (meta (transform ALL-WITH-META inc ^{:purpose "Count"} [0 1 2 3]))
{:purpose "Count"}
ALL-WITH-META
can transform to NONE
to remove elements.
=> (setval [ALL-WITH-META nil?] NONE ^{:purpose "Count"} [1 2 nil 3 nil])
[1 2 3]
=> (meta (setval [ALL-WITH-META nil?] NONE ^{:purpose "Count"} [1 2 nil 3 nil]))
^{:purpose "Count"}
ATOM
navigates to the value of an atom.
=> (def a (atom 0))
=> (select-one ATOM a)
0
=> (swap! a inc)
=> (select-one ATOM a)
1
=> (transform ATOM inc a)
=> @a
2
BEFORE-ELEM
navigates to the 'void' element before the sequence. For transformations – if result is not NONE
, then prepend that value.
=> (setval BEFORE-ELEM 3 [1 2])
[3 1 2]
BEGINNING
navigates to the empty subsequence before the beginning of a collection. Useful with setval
to add values onto the beginning of a sequence.
=> (setval BEGINNING '(0 1) (range 2 7))
(0 1 2 3 4 5 6)
=> (setval BEGINNING [0 1] (range 2 7))
(0 1 2 3 4 5 6)
=> (setval BEGINNING {0 1} (range 2 7))
([0 1] 2 3 4 5 6)
=> (setval BEGINNING '(0 1) [2 3 4])
[0 1 2 3 4]
=> (setval BEGINNING {:foo :baz} {:foo :bar})
([:foo :baz] [:foo :bar])
As of Specter 1.0.0, BEGINNING
can now work with strings. It navigates to or transforms substrings.
=> (select-any BEGINNING "abc")
""
=> (setval BEGINNING "b" "a")
"ba"
Added in 0.12.0
Drops all collected values for subsequent navigation.
=> (transform [ALL VAL] + (range 10))
(0 2 4 6 8 10 12 14 16 18)
=> (transform [ALL VAL DISPENSE] + (range 10))
(0 1 2 3 4 5 6 7 8 9)
END
navigates to the empty subsequence after the end of a collection. Useful with setval
to add values onto the end of a sequence.
=> (setval END '(5 6) (range 5))
(0 1 2 3 4 5 6)
=> (setval END [5 6] (range 5))
(0 1 2 3 4 5 6)
=> (setval END {5 6} (range 5))
(0 1 2 3 4 [5 6])
=> (setval END '(5 6) [1 2 3 4])
[1 2 3 4 5 6]
=> (setval END {:foo :baz} {:foo :bar})
([:foo :bar] [:foo :baz])
As of Specter 1.0.0, END
can now work with strings. It navigates to or transforms substrings.
=> (select-any END "abc")
""
=> (setval END "b" "a")
"ab"
FIRST
navigates to the first element of a collection. If the collection is a map, returns a key-value pair [key value]
. If the collection is empty, navigation stops.
=> (select-one FIRST (range 5))
0
=> (select-one FIRST (sorted-map 0 :a 1 :b))
[0 :a]
=> (select-one FIRST (sorted-set 0 1 2 3))
0
=> (select-one FIRST '())
nil
=> (select FIRST '())
nil
FIRST
can transform to NONE
to remove elements.
=> (setval FIRST NONE [:a :b :c :d :e])
[:b :c :d :e]
As of Specter 1.0.0, FIRST
can now work with strings. It navigates to or transforms characters.
=> (select-any FIRST "abc")
\a
=> (setval FIRST \q "abc")
"qbc"
INDEXED-VALS
navigates to [index elem] pairs for each element in a sequence. Transforms of index move element at that index to the new index, shifting other elements in the sequence. Indices seen during transform take into account any shifting from prior sequence elements changing indices.
=> (select [INDEXED-VALS] [1 2 3 4 5])
[[0 1] [1 2] [2 3] [3 4] [4 5]]
=> (setval [INDEXED-VALS FIRST] 0 [1 2 3 4 5])
[5 4 3 2 1]
=> (setval [INDEXED-VALS FIRST] 1 [1 2 3 4 5])
[1 5 4 3 2]
LAST
navigates to the last element of a collection. If the collection is a map, returns a key-value pair [key value]
. If the collection is empty, navigation stops.
=> (select-one LAST (range 5))
4
=> (select-one LAST (sorted-map 0 :a 1 :b))
[1 :b]
=> (select-one LAST (sorted-set 0 1 2 3))
3
=> (select-one LAST '())
nil
=> (select LAST '())
nil
LAST
can transform to NONE
to remove elements.
=> (setval LAST NONE [:a :b :c :d :e])
[:a :b :c :d]
As of Specter 1.0.0, LAST
can now work with strings. It navigates to or transforms characters.
=> (select-any LAST "abc")
\c
=> (setval LAST "q" "abc")
"abq"
MAP-KEYS
navigates to every key in a map. MAP-KEYS
is more efficient than [ALL FIRST]
.
=> (select [MAP-KEYS] {:a 3 :b 4})
[:a :b]
MAP-VALS
navigates to every value in a map. MAP-VALS
is more efficient than [ALL LAST]
.
=> (select MAP-VALS {:a :b, :c :d})
(:b :d)
=> (select [MAP-VALS MAP-VALS] {:a {:b :c}, :d {:e :f}})
(:c :f)
MAP-VALS
can transform to NONE
to remove elements.
=> (setval [MAP-VALS even?] NONE {:a 1 :b 2 :c 3 :d 4})
{:a 1 :c 3}
Added in 0.12.0
Navigates to the metadata of the structure, or nil if the structure has no metadata or may not contain metadata.
=> (select-one META (with-meta {:a 0} {:meta :data}))
{:meta :data}
=> (meta (transform META #(assoc % :meta :datum)
(with-meta {:a 0} {:meta :data})))
{:meta :datum}
NAME
navigates to the name of a keyword or symbol.
=> (select [NAME] :key)
["key"]
=> (select [MAP-KEYS NAME] {:a 3 :b 4 :c 5})
["a" "b" "c"]
=> (setval [MAP-KEYS NAME] "q" {'a/b 3 'bbb/c 4 'd 5})
{a/q 3, bbb/q 4, q 5}
NAMESPACE
navigates to the namespace of keywords or symbols.
=> (select [ALL NAMESPACE] [::test ::fun])
["playground.specter" "playground.specter"]
=> (select [ALL NAMESPACE] [::test :fun])
["playground.specter" nil]
=> (setval [ALL NAMESPACE] "a" [::test :fun])
[:a/test :a/fun]
NIL->LIST
navigates to the empty list '()
if the value is nil. Otherwise it stays at the current value.
=> (select-one NIL->LIST nil)
()
=> (select-one NIL->LIST :foo)
:foo
NIL->SET
navigates to the empty set #{}
if the value is nil. Otherwise it stays at the current value.
=> (select-one NIL->SET nil)
#{}
=> (select-one NIL->SET :foo)
:foo
NIL->VECTOR
navigates to the empty vector []
if the value is nil. Otherwise it stays at the current value.
=> (select-one NIL->VECTOR nil)
[]
=> (select-one NIL->VECTOR :foo)
:foo
NONE
is a global value used to indicate no elements selected during [[select-any]]
.
=> (select-any (before-index 0) [1 2 3])
:com.rpl.specter.impl/NONE
NONE
can also be used in transforms to remove elements:
=> (setval ALL NONE [1 2 3])
[]
NONE-ELEM
navigates to the 'void' elem in a set. For transformations - if the result is not NONE
, then add that value to the set.
=> (setval NONE-ELEM 3 #{1 2})
#{1 2 3}
=> (setval NONE-ELEM 1 nil)
#{1}
STAY
stays in place. It is the no-op navigator.
=> (select-one STAY :foo)
:foo
STOP
stops navigation. For transformation, returns the structure unchanged.
=> (select-one STOP :foo)
nil
=> (select [ALL STOP] (range 5))
[]
=> (transform [ALL STOP] inc (range 5))
(0 1 2 3 4)
VAL
collects the current structure.
See also collect, collect-one, and putval
=> (select [VAL ALL] (range 3))
[[(0 1 2) 0] [(0 1 2) 1] [(0 1 2) 2]]
;; Collected values are passed as initial arguments to the update fn.
=> (transform [VAL ALL] (fn [coll x] (+ x (count coll))) (range 5))
(5 6 7 8 9)
(before-index index)
Navigates to the empty space between the index and the prior index. Selects navigate to NONE.
=> (select-any (before-index 0) [1 2 3])
:com.rpl.specter.impl/NONE
Transforms to non-NONE insert at the index position.
=> (setval (before-index 0) :a [1 2 3])
[:a 1 2 3]
=> (setval (before-index 1) NONE [1 2 3])
[1 2 3]
=> (setval (before-index 1) :a [1 2 3])
[1 :a 2 3]
=> (setval (before-index 3) :a [1 2 3])
[1 2 3 :a]
(codewalker afn)
Using clojure.walk, codewalker
executes a depth-first search for nodes where afn
returns a truthy value. When afn
returns a truthy value, codewalker
stops
searching that branch of the tree and continues its search of the rest of the
data structure. codewalker
preserves the metadata of any forms traversed.
See also walker.
=> (select (codewalker #(and (map? %) (even? (:a %))))
(list (with-meta {:a 2} {:foo :bar}) (with-meta {:a 1} {:foo :baz})))
({:a 2})
=> (map meta *1)
({:foo :bar})
(collect & paths)
collect
adds the result of running select
with the given path on the current value to the collected vals. Note that collect
, like select
, returns a vector containing its results. If transform
is called, each collected value will be passed as an argument to the transforming function with the resulting value as the last argument.
See also VAL, collect-one, and putval
=> (select-one [(collect ALL) FIRST] (range 3))
[[0 1 2] 0]
=> (select [(collect ALL) ALL] (range 3))
[[[0 1 2] 0] [[0 1 2] 1] [[0 1 2] 2]]
=> (select [(collect ALL) (collect ALL) ALL] (range 3))
[[[0 1 2] [0 1 2] 0] [[0 1 2] [0 1 2] 1] [[0 1 2] [0 1 2] 2]]
;; Add the sum of the evens to the first element of the seq
=> (transform [(collect ALL even?) FIRST]
(fn [evens first] (reduce + first evens))
(range 5))
(6 1 2 3 4)
;; Replace the first element of the seq with the entire seq
=> (transform [(collect ALL) FIRST] (fn [all _] all) (range 3))
([0 1 2] 1 2)
(collect-one & paths)
collect-one
adds the result of running select-one
with the given path on the current value to the collected vals. Note that collect-one
, like select-one
, returns a single result. If there is more than one result, an exception will be thrown. If transform
is called, each collected value will be passed as an argument to the transforming function with the resulting value as the last argument.
See also VAL, collect, and putval
=> (select-one [(collect-one FIRST) LAST] (range 5))
[0 4]
=> (select [(collect-one FIRST) ALL] (range 3))
[[0 0] [0 1] [0 2]]
=> (transform [(collect-one :b) :a] + {:a 2, :b 3})
{:a 5, :b 3}
=> (transform [(collect-one :b) (collect-one :c) :a] * {:a 3, :b 5, :c 7})
{:a 105,, :b 5 :c 7}
(comp-paths & path)
Returns a compiled version of the given path for use with compiled-{select/transform/setval/etc.} functions.
=> (let [my-path (comp-paths :a :b :c)]
(compiled-select-one my-path {:a {:b {:c 0}}}))
0
(compact & path)
During transformation, set empty collections after specified navigations to NONE
to trigger removal. A no-op during selection operations.
=> (setval [:a (compact :b :c)] NONE {:a {:b {:c 1}}})
{}
=> (setval [:a :b (compact :c)] NONE {:a {:b {:c 1}}})
{:a {})
=> (setval [1 (compact 0)] NONE [1 [2] 3])
[1 3]
These functions operate in the same way as their uncompiled counterparts, but they require their path to be precompiled with comp-paths.
(cond-path & conds)
Takes as arguments alternating cond-path1 path1 cond-path2 path2...
Tests if selecting with cond-path on the current structure returns anything.
If so, it navigates to the corresponding path.
Otherwise, it tries the next cond-path. If nothing matches, then the structure
is not selected.
See also if-path
=> (select [ALL (cond-path (must :a) :a (must :b) :c)] [{:a 0} {:b 1 :c 2}])
[0 2]
=> (select [(cond-path (must :a) :b)] {:b 1})
()
(continue-then-stay & path)
Navigates to the provided path and then to the current element. This can be used to implement post-order traversal.
See also stay-then-continue.
=> (select (continue-then-stay MAP-VALS) {:a 0 :b 1 :c 2})
(0 1 2 {:a 0, :b 1, :c 2})
(continuous-subseqs pred)
Navigates to every continuous subsequence of elements matching pred
.
=> (select (continuous-subseqs #(< % 10)) [5 6 11 11 3 12 2 5])
([5 6] [3] [2 5])
=> (select (continuous-subseqs #(< % 10)) [12 13])
()
=> (setval (continuous-subseqs #(< % 10)) [] [3 2 5 11 12 5 20])
[11 12 20]
(eachnav navigator)
Turns a navigator that takes one argument into a navigator that takes many arguments and uses the same navigator with each argument. There is no performance cost to using this.
keypath
, must
, and nthpath
are all implemented using eachnav, making multiple arguments possible. See their documentation here, or look at their implementation in Specter core.
(filterer & path)
Navigates to a view of the current sequence that only contains elements that match the given path. An element matches the selector path if calling select on that element with the path yields anything other than an empty sequence. Returns a vector when used in a select.
See also subselect.
;; Note that clojure functions have been extended to implement the navigator protocol
=> (select-one (filterer even?) (range 10))
[0 2 4 6 8]
=> (select-one (filterer identity) ['() [] #{} {} "" true false nil])
[() [] #{} {} "" true]
(if-path cond-path then-path)
(if-path cond-path then-path else-path)
Like cond-path, but with if semantics. If no else path is supplied and cond-path is not satisfied, stops navigation.
See also cond-path
=> (select (if-path (must :d) :a) {:a 0, :d 1})
(0)
=> (select (if-path (must :d) :a :b) {:a 0, :b 1})
(1)
=> (select (if-path (must :d) :a) {:b 0, :d 1})
()
;; is equivalent to
=> (select (if-path (must :d) :a STOP) {:b 0, :d 1})
()
Navigates to the index of the sequence if within 0 and size. Transforms move element at that index to the new index, shifting other elements in the sequence.
(index-nav index)
=> (select [(index-nav 0)] [1 2 3 4 5])
[0]
=> (select [(index-nav 7)] [1 2 3 4 5])
[]
=> (setval (index-nav 2) 0 [1 2 3 4 5])
[3 1 2 4 5]
(keypath & keys)
Navigates to the specified key, navigating to nil if it does not exist. Note that this is different from stopping navigation if the key does not exist. If you want to stop navigation, use must.
See also must
=> (select-one (keypath :a) {:a 0})
0
=> (select-one (keypath :a :b) {:a {:b 1}})
1
=> (select [ALL (keypath :a)] [{:a 0} {:b 1}])
[0 nil]
;; Does not stop navigation
=> (select [ALL (keypath :a) (nil->val :boo)] [{:a 0} {:b 1}])
[0 :boo]
keypath
can now take multiple arguments, for concisely specifying multiple steps. It navigates to each key one after another.
=> (select-one (keypath "out") {"out" {"in" 3}})
{"in" 3}
=> (select-one (keypath "out" "in") {"out" {"in" 3}})
3
keypath
can transform to NONE
to remove elements.
=> (setval [(keypath :a)] NONE {:a 3 :b 4})
{:b 4}
(map-key key)
Navigates to the given key in the map (not to the value).
=> (select [(map-key :a)] {:a 2 :b 3})
[:a]
=> (setval [(map-key :a)] :c {:a 2 :b 3})
{:b 3, :c 2}
Navigates only if the key currently exists in the map.
=> (select [(map-key :z)] {:a 2 :b 3})
[]
Can transform to NONE to remove the key/value pair from the map.
=> (setval [(map-key :a)] NONE {:a 2 :b 3})
{:b 3}
(multi-path & paths)
A path that branches on multiple paths. For transforms, applies updates to the paths in order.
=> (select (multi-path :a :b) {:a 0, :b 1, :c 2})
(0 1)
=> (select (multi-path (filterer odd?) (filterer even?)) (range 10))
([1 3 5 7 9] [0 2 4 6 8])
=> (transform (multi-path :a :b) (fn [x] (println x) (dec x)) {:a 0, :b 1, :c 2})
0
1
{:a -1, :b 0, :c 2}
(must & keys)
Navigates to the key only if it exists in the map. Note that must stops navigation if the key does not exist. If you do not want to stop navigation, use keypath.
=> (select-one (must :a) {:a 0})
0
=> (select-one (must :a) {:b 1})
nil
must
can now take multiple arguments, for concisely specifying multiple steps. It navigates to each key, one after another.
=> (select-any (must :a) {:a {:b 2} :c 3})
{:b 2}
=> (select-any (must :a :b) {:a {:b 2} :c 3})
2
must
can transform to NONE
to remove elements.
=> (setval (must :a) NONE {:a 1 :b 2})
{:b 2}
(nil->val v)
Navigates to the provided val if the structure is nil. Otherwise it stays navigated at the structure.
=> (select-one (nil->val :a) nil)
:a
=> (select-one (nil->val :a) :b)
:b
(nthpath & indices)
Navigate to the specified indices (one after another). Transform to NONE to remove the element from the sequence.
=> (select [(nthpath 0)] [1 2 3])
[1]
=> (select [(nthpath 2)] [1 2 3])
[3]
=> (setval [(nthpath 2)] NONE [1 2 3])
[1 2]
nthpath
can now take multiple arguments, for concisely specifying multiple steps. It navigates to each index, one after another.
=> (select [(nthpath 0)] [1 2 3])
[1]
=> (select [(nthpath 0)] [[0 1 2] 2 3])
[[0 1 2]]
=> (select [(nthpath 0 0)] [[0 1 2] 2 3])
[0]
(parser parse-fn unparse-fn)
Navigate to the result of running parse-fn
on the value. For
transforms, the transformed value then has unparse-fn
run on
it to get the final value at this point.
=> (defn parse [address] (string/split address #"@"))
=> (defn unparse [address] (string/join "@" address))
=> (select [ALL (parser parse unparse) #(= "gmail.com" (second %))]
["test@example.com" "test@gmail.com"])
[["test" "gmail.com"]]
=> (setval [ALL (parser parse unparse) #(= "gmail.com" (second %)) FIRST END]
"+spam"
["test@example.com" "test@gmail.com"])
["test@example.com" "test+spam@gmail.com"]
(pred apred)
Keeps the element only if it matches the supplied predicate. This is the parameterized version of using a function directly in a path.
See also must.
=> (select [ALL (pred even?)] (range 10))
[0 2 4 6 8]
(pred= value)
Keeps elements only if they equal the provided value.
See also pred.
=> (select [ALL (pred= 2)] [1 2 2 3 4 0])
[2 2]
(pred< value)
Keeps elements only if they are less than the provided value.
=> (select [ALL (pred< 3)] [1 2 2 3 4 0])
[1 2 2 0]
See also pred.
(pred> value)
Keeps elements only if they are greater than the provided value.
=> (select [ALL (pred> 3)] [1 2 2 3 4 0])
[4]
See also pred.
(pred<= value)
Keeps elements only if they are less than or equal to the provided value.
=> (select [ALL (pred<= 3)] [1 2 2 3 4 0])
[1 2 2 3 0]
See also pred.
(pred>= value)
Keeps elements only if they are greater than or equal to the provided value.
=> (select [ALL (pred>= 3)] [1 2 2 3 4 0])
[3 4]
See also pred.
(putval val)
Adds an external value to the collected vals. Useful when additional arguments are required to the transform function that would otherwise require partial application or a wrapper function.
See also VAL, collect, and collect-one
;; incrementing val at path [:a :b] by 3
=> (transform [:a :b (putval 3)] + {:a {:b 0}})
{:a {:b 3}}
(not-selected? & path)
Stops navigation if the path navigator finds a result. Otherwise continues with the current structure.
See also selected?.
=> (select [ALL (not-selected? even?)] (range 10))
[1 3 5 7 9]
=> (select [ALL (not-selected? [(must :a) even?])] [{:a 0} {:a 1} {:a 2} {:a 3}])
[{:a 1} {:a 3}]
;; Path returns [0 2], so navigation stops
=> (select-one (not-selected? [ALL (must :a) even?]) [{:a 0} {:a 1} {:a 2} {:a 3}])
nil
(regex-nav regex)
Added in 1.0.5
When supplied with a regex, navigates to every match in a string, and supports replacement with a new substring.
Here are some basic examples of selecting:
=> (select (regex-nav #"t") "test")
["t" "t"]
=> (select [:a (regex-nav #"t")] {:a "test"})
["t" "t"]
You can use more advanced features of regexes like capture groups:
=> (select [(regex-nav #"(\S+):\ (\d+)") (nthpath 2)] "Mary: 1st George: 2nd Arthur: 3rd")
["1" "2" "3"]
You can replace matches with a provided value:
=> (setval (regex-nav #"t") "z" "test")
"zesz"
=> (setval [:a (regex-nav #"t")] "z" {:a "test"})
{:a "zesz"}
Or you can transform
with a function, such as the ones in the clojure.string
namespace:
=> (transform (regex-nav #"t") clojure.string/capitalize "test")
"TesT"
=> (transform [:a (regex-nav #"t")] clojure.string/capitalize {:a "test"})
{:a "TesT"}
=> (transform (regex-nav #"\s+\w") clojure.string/triml "Hello World!")
"HelloWorld!"
However, you can also provide your own function, so long as it takes and returns patterns, characters, or strings:
=> (transform (regex-nav #"aa*") (fn [s] (-> s count str)) "aadt")
"2dt"
=> (transform (regex-nav #"[Aa]+") (fn [s] (apply str (take (count s) (repeat "@")))) "Amsterdam Aardvarks")
"@msterd@m @@rdv@rks"
=> (transform (subselect (regex-nav #"\d\w+")) reverse "Mary: 1st George: 2nd Arthur: 3rd")
"Mary: 3rd George: 2nd Arthur: 1st"
Specter also implicitly converts regexes in paths to call regex-nav:
=> (setval #"t" "z" "test")
"zesz"
(selected? & path)
Stops navigation if the path navigator fails to find a result. Otherwise continues with the current structure.
See also not-selected?.
=> (select [ALL (selected? even?)] (range 10))
[0 2 4 6 8]
=> (select [ALL (selected? [(must :a) even?])] [{:a 0} {:a 1} {:a 2} {:a 3}])
[{:a 0} {:a 2}]
;; Path returns [0 2], so selected? returns the entire structure
=> (select-one (selected? [ALL (must :a) even?]) [{:a 0} {:a 1} {:a 2} {:a 3}])
[{:a 0} {:a 1} {:a 2} {:a 3}]
(set-elem element)
Navigates to the given element in the set only if it exists in the set. Can transform to NONE to remove the element from the set.
=> (select [(set-elem 3)] #{3 4 5})
[3]
=> (select [(set-elem 3)] #{4 5})
[]
=> (setval [(set-elem 3)] NONE #{3 4 5})
#{4 5}
(srange start end)
Navigates to the subsequence bound by the indexes start (inclusive) and end (exclusive).
See also srange-dynamic.
=> (select-one (srange 2 4) (range 5))
[2 3]
=> (select-one (srange 0 10) (range 5))
IndexOutOfBoundsException
=> (setval (srange 2 4) [] (range 5))
(0 1 4)
As of Specter 1.0.0, srange
can now work with strings. It navigates to or transforms substrings.
=> (select-any (srange 1 3) "abcd")
"bc"
=> (setval (srange 1 3) "" "abcd")
"ad"
=> (setval [(srange 1 3) END] "x" "abcd")
"abcxd"
(srange-dynamic start-fn end-fn)
Uses start-fn and end-fn to determine the bounds of the subsequence to select when navigating. Each function takes in the structure as input.
See also srange.
=> (select-one (srange-dynamic #(.indexOf % 2) #(.indexOf % 4)) (range 5))
[2 3]
=> (select-one (srange-dynamic (fn [_] 0) #(quot (count %) 2)) (range 10))
[0 1 2 3 4]
(stay-then-continue)
Navigates to the current element and then navigates via the provided path. This can be used to implement pre-order traversal.
See also continue-then-stay.
=> (select (stay-then-continue MAP-VALS) {:a 0 :b 1 :c 2})
({:a 0, :b 1, :c 2} 0 1 2)
(submap m-keys)
Navigates to the specified submap (using select-keys). In a transform, that submap in the original map is changed to the new value of the submap.
=> (select-one (submap [:a :b]) {:a 0, :b 1, :c 2})
{:a 0, :b 1}
=> (select-one (submap [:c]) {:a 0})
{}
;; (submap [:a :c]) returns {:a 0} with no :c
=> (transform [(submap [:a :c]) MAP-VALS]
inc
{:a 0, :b 1})
{:b 1, :a 1}
;; We replace the empty submap with {:c 2} and merge with the original
;; structure
=> (transform (submap []) #(assoc % :c 2) {:a 0, :b 1})
{:a 0, :b 1, :c 2}
(subselect & path)
Navigates to a sequence that contains the results of (select ...),
but is a view to the original structure that can be transformed.
Without subselect, we could only transform selected values individually.
subselect
lets us transform them together as a seq, much like filterer
.
Requires that the input navigators will walk the structure's children in the same order when executed on "select" and then "transform".
See also filterer.
=> (transform (subselect (walker number?) even?)
reverse
[1 [[[2]] 3] 5 [6 [7 8]] 10])
[1 [[[10]] 3] 5 [8 [7 6]] 2]
=> (select-any (subselect ALL :a even?)
[{:a 1} {:a 2} {:a 4}])
[2 4]
=> (transform (subselect ALL :a even?)
reverse
[{:a 1} {:a 2} {:a 4}])
[{:a 1} {:a 4} {:a 2}]
(subset aset)
Navigates to the specified subset (by taking an intersection). In a transform, that subset in the original set is changed to the new value of the subset.
=> (select-one (subset #{:a :b}) #{:b :c})
#{:b}
;; Replaces the #{:a} subset with #{:a :c} and unions back into
;; the original structure
=> (setval (subset #{:a}) #{:a :c} #{:a :b})
#{:c :b :a}
(terminal update-fn)
Added in 0.12.0
For usage with multi-transform
, defines an endpoint in the navigation that
will have the parameterized transform function run. The transform function works
just like it does in transform
, with collected values given as the first
arguments.
See also terminal-val and multi-transform.
=> (multi-transform [(putval 3) (terminal +)] 1)
4
=> (multi-transform [:a :b (multi-path [:c (terminal inc)]
[:d (putval 3) (terminal +)])]
{:a {:b {:c 42 :d 1}}})
{:a {:b {:c 43, :d 4}}}
(terminal-val val)
Added in 0.12.0
Like terminal
but specifies a val to set at the location regardless of
the collected values or the value at the location.
=> (multi-transform (terminal-val 2) 3)
2
See also terminal and multi-transform.
(transformed path update-fn)
Navigates to a view of the current value by transforming it with the specified path and update-fn.
See also view
=> (select-one (transformed [ALL odd?] #(* % 2)) (range 10))
(0 2 2 6 4 10 6 14 8 18)
=> (transform [(transformed [ALL odd?] #(* % 2)) ALL] #(/ % 2) (range 10))
(0 1 1 3 2 5 3 7 4 9)
(traversed path reduce-fn)
Navigates to a view of the current value by transforming with a reduction over the specified traversal.
=> (select-any (traversed ALL +) [1 2 3 4])
10
(view afn)
Navigates to result of running afn
on the currently navigated value.
See also transformed.
=> (select-one [FIRST (view inc)] (range 5))
1
(walker afn)
Using clojure.walk, walker
executes a depth-first search for nodes where afn
returns a truthy value. When afn
returns a truthy value, walker
stops
searching that branch of the tree and continues its search of the rest of the
data structure.
See also codewalker
=> (select (walker #(and (number? %) (even? %))) '(1 (3 4) 2 (6)))
(4 2 6)
;; Note that (3 4) and (6 7) are not returned because the search halted at
;; (2 (3 4) (5 (6 7))).
=> (select (walker #(and (counted? %) (even? (count %))))
'(1 (2 (3 4) 5 (6 7)) (8 9)))
((2 (3 4) 5 (6 7)) (8 9))
=> (setval (walker #(and (counted? %) (even? (count %))))
:double
'(1 (2 (3 4) 5 (6 7)) (8 9)))
(1 :double :double)
(with-fresh-collected & path)
with-fresh-collected
continues navigating on the given path with the
collected vals reset to []. Once navigation leaves the scope of
with-fresh-collected
, the collected vals revert to what they were
before.