2016-06-11 00:42:36 +00:00
# List of Navigators with Example(s)
## The All Caps Ones
### ALL
2016-06-11 14:42:15 +00:00
`ALL` navigates to every element in a collection. If the collection is a map, it will navigate to each key-value pair `[key value]` .
2016-06-11 00:42:36 +00:00
```clojure
2016-06-11 14:55:45 +00:00
=> (select ALL [0 1 2 3])
2016-06-11 00:42:36 +00:00
[0 1 2 3]
2016-06-11 14:55:45 +00:00
=> (select ALL (list 0 1 2 3))
2016-06-11 00:42:36 +00:00
[0 1 2 3]
2016-06-11 14:55:45 +00:00
=> (select ALL {:a :b, :c :d})
[[:a :b] [:c :d]]
=> (transform ALL identity {:a :b, :c :d})
{:a :b, :c :d}
2016-06-11 02:53:31 +00:00
```
### ATOM
`ATOM` navigates to the value of an atom.
```clojure
=> (def a (atom 0))
2016-06-11 14:55:45 +00:00
=> (select-one ATOM a)
2016-06-11 02:53:31 +00:00
0
=> (swap! a inc)
2016-06-11 14:55:45 +00:00
=> (select-one ATOM a)
2016-06-11 02:53:31 +00:00
1
```
### BEGINNING
2016-06-11 05:09:30 +00:00
`BEGINNING` navigates to the empty subsequence before the beginning of a collection. Useful with `setval` to add values onto the beginning of a sequence. Returns a lazy sequence.
2016-06-11 02:53:31 +00:00
```clojure
2016-06-11 14:55:45 +00:00
=> (setval BEGINNING '(0 1) (range 2 7))
2016-06-11 02:53:31 +00:00
(0 1 2 3 4 5 6)
2016-06-11 14:55:45 +00:00
=> (setval BEGINNING [0 1] (range 2 7))
2016-06-11 02:53:31 +00:00
(0 1 2 3 4 5 6)
2016-06-11 14:55:45 +00:00
=> (setval BEGINNING {0 1} (range 2 7))
2016-06-11 02:53:31 +00:00
([0 1] 2 3 4 5 6)
2016-06-11 14:55:45 +00:00
=> (setval BEGINNING {:foo :baz} {:foo :bar})
2016-06-11 02:53:31 +00:00
([:foo :baz] [:foo :bar])
```
### END
2016-06-11 05:09:30 +00:00
`END` navigates to the empty subsequence after the end of a collection. Useful with `setval` to add values onto the end of a sequence. Returns a lazy sequence.
2016-06-11 02:53:31 +00:00
```clojure
2016-06-11 14:55:45 +00:00
=> (setval END '(5 6) (range 5))
2016-06-11 02:53:31 +00:00
(0 1 2 3 4 5 6)
2016-06-11 14:55:45 +00:00
=> (setval END [5 6] (range 5))
2016-06-11 02:53:31 +00:00
(0 1 2 3 4 5 6)
2016-06-11 14:55:45 +00:00
=> (setval END {5 6} (range 5))
2016-06-11 02:53:31 +00:00
(0 1 2 3 4 [5 6])
2016-06-11 14:55:45 +00:00
=> (setval END {:foo :baz} {:foo :bar})
2016-06-11 02:53:31 +00:00
([:foo :bar] [:foo :baz])
```
### FIRST
`FIRST` navigates to the first element of a collection. If the collection is a map, returns the key-value pair `[key value]` . If the collection is empty, navigation stops.
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one FIRST (range 5))
2016-06-11 02:53:31 +00:00
0
2016-06-11 14:55:45 +00:00
=> (select-one FIRST (sorted-map 0 :a 1 :b))
2016-06-11 02:53:31 +00:00
[0 :a]
2016-06-11 14:55:45 +00:00
=> (select-one FIRST (sorted-set 0 1 2 3))
2016-06-11 02:53:31 +00:00
0
2016-06-11 14:55:45 +00:00
=> (select-one FIRST '())
2016-06-11 02:53:31 +00:00
nil
2016-06-11 14:55:45 +00:00
=> (select FIRST '())
2016-06-11 02:53:31 +00:00
nil
```
### LAST
`LAST` navigates to the last element of a collection. If the collection is a map, returns the key-value pair `[key value]` . If the collection is empty, navigation stops.
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one LAST (range 5))
2016-06-11 02:53:31 +00:00
4
2016-06-11 14:55:45 +00:00
=> (select-one LAST (sorted-map 0 :a 1 :b))
2016-06-11 02:53:31 +00:00
[1 :b]
2016-06-11 14:55:45 +00:00
=> (select-one LAST (sorted-set 0 1 2 3))
2016-06-11 02:53:31 +00:00
3
2016-06-11 14:55:45 +00:00
=> (select-one LAST '())
2016-06-11 02:53:31 +00:00
nil
2016-06-11 14:55:45 +00:00
=> (select LAST '())
2016-06-11 02:53:31 +00:00
nil
```
### MAP-VALS
`MAP-VALS` navigates to every value in a map. `MAP-VALS` is more efficient than `[ALL LAST]` . Note that `MAP-VALS` returns a lazy seq.
```clojure
2016-06-11 14:55:45 +00:00
=> (select MAP-VALS {:a :b, :c :d})
2016-06-11 02:53:31 +00:00
(:b :d)
2016-06-11 14:18:59 +00:00
=> (select [MAP-VALS MAP-VALS] {:a {:b :c}, :d {:e :f}})
2016-06-11 02:53:31 +00:00
(:c :f)
```
### NIL->LIST
`NIL->LIST` navigates to the empty list `'()` if the value is nil. Otherwise it stays at the current value.
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one NIL->LIST nil)
2016-06-11 02:53:31 +00:00
()
2016-06-11 14:55:45 +00:00
=> (select-one NIL->LIST :foo)
2016-06-11 02:53:31 +00:00
:foo
```
### NIL->SET
`NIL->SET` navigates to the empty set `#{}` if the value is nil. Otherwise it stays at the current value.
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one NIL->LIST nil)
2016-06-11 02:53:31 +00:00
#{}
2016-06-11 14:55:45 +00:00
=> (select-one NIL->LIST :foo)
2016-06-11 02:53:31 +00:00
:foo
```
### NIL->VECTOR
`NIL->VECTOR` navigates to the empty vector `[]` if the value is nil. Otherwise it stays at the current value.
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one NIL->LIST nil)
2016-06-11 02:53:31 +00:00
[]
2016-06-11 14:55:45 +00:00
=> (select-one NIL->LIST :foo)
2016-06-11 02:53:31 +00:00
:foo
```
### STAY
`STAY` stays in place. It is the no-op navigator.
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one STAY :foo)
2016-06-11 02:53:31 +00:00
:foo
```
### STOP
`STOP` stops navigation. For selection, returns nil. For transformation, returns the structure unchanged.
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one STOP :foo)
2016-06-11 02:53:31 +00:00
nil
=> (select [ALL STOP] (range 5))
[]
=> (transform [ALL STOP] inc (range 5))
(0 1 2 3 4)
```
2016-06-11 04:55:58 +00:00
## the lower case ones
### bind-params*
Binds late binding params. Write this one later.
### codewalker
Walks code? Let's do this one later.
### collect
`(collect & paths)`
`collect` adds the result of running `collect` 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 in as an argument to the transforming function, with the resulting value as the last argument.
```clojure
=> (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
2016-06-11 04:58:17 +00:00
=> (transform [(collect ALL even?) FIRST]
(fn [evens first] (reduce + first evens))
(range 5))
2016-06-11 04:55:58 +00:00
(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
`(collect-one & paths)`
`collect-one` adds the result of running `collect` 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 in as an argument to the transforming function, with the resulting value as the last argument.
```clojure
=> (select-one [(collect-one FIRST) LAST] (range 5))
[0 4]
=> (select [(collect-one FIRST) ALL] (range 3))
[[0 0] [0 1] [0 2]]
2016-06-11 14:18:59 +00:00
=> (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}
2016-06-11 12:37:19 +00:00
```
### comp-paths
`(comp-paths & path)`
Returns a compiled version of the given path for use with compiled-{select/transform/setval/etc.} functions. This can compile navigators (defined with `defnav` ) without their parameters, and the resulting compiled
2016-06-11 14:18:59 +00:00
path will require parameters for all such navigators in the order in which they were declared. Provides a speed improvement of about 2-15% over the inline caching introduced with version 0.11.2.
2016-06-11 12:37:19 +00:00
```clojure
=> (let [my-path (comp-paths :a :b :c)]
(compiled-select-one my-path {:a {:b {:c 0}}}))
0
=> (let [param-path (comp-paths :a :b keypath))]
2016-06-11 14:18:59 +00:00
(compiled-transform (param-path :c) inc {:a {:b {:c 0, :d 1}}})
{:a {:b {:c 1, :d 1}}}
=> (let [range-path (comp-paths srange)]
(compiled-select-one (range-path 1 4) (range 4)))
[1 2 3]
2016-06-11 12:37:19 +00:00
```
### compiled-*
2016-06-11 14:42:15 +00:00
These functions operate in the same way as their uncompiled counterparts, but they require their path to be precompiled with [comp-paths ](#comp-paths ).
2016-06-11 14:18:59 +00:00
### cond-path
`(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.
The input paths may be parameterized, in which case the result of cond-path
will be parameterized in the order of which the parameterized navigators
were declared.
```clojure
2016-06-11 14:55:45 +00:00
=> (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})
()
2016-06-11 14:18:59 +00:00
```
### continue-then-stay
`(continue-then-stay & path)`
Navigates to the provided path and then to the current element. This can be used
to implement post-order traversal.
```clojure
2016-06-11 14:55:45 +00:00
=> (select (continue-then-stay MAP-VALS) {:a 0 :b 1 :c 2})
2016-06-11 14:18:59 +00:00
(0 1 2 {:a 0, :b 1, :c 2})
```
### continuous-subseqs
`(continuous-subseqs pred)`
Navigates to every continuous subsequence of elements matching `pred` .
```clojure
2016-06-11 14:55:45 +00:00
=> (select (continuous-subseqs #(< % 10)) [5 6 11 11 3 12 2 5])
2016-06-11 14:18:59 +00:00
([5 6] [3] [2 5])
2016-06-11 14:55:45 +00:00
=> (select (continuous-subseqs #(< % 10)) [12 13])
2016-06-11 14:18:59 +00:00
()
```
### filterer
`(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.
The input path may be parameterized, in which case the result of filterer
will be parameterized in the order of which the parameterized selectors
were declared. Note that filterer is a function which returns a navigator. It is the arguments to filterer that can be parametrized, not filterer.
```clojure
;; Note that clojure functions have been extended to implement the navigator protocol
2016-06-11 14:55:45 +00:00
=> (select-one (filterer even?) (range 10))
2016-06-11 14:18:59 +00:00
[0 2 4 6 8]
2016-06-11 14:55:45 +00:00
=> (select-one (filterer identity) ['() [] #{} {} "" true false nil])
2016-06-11 14:18:59 +00:00
[() [] #{} {} "" true]
=> (let [pred-path (comp-paths (filterer pred))]
(select-one (pred-path even?) (range 10)))
[0 2 4 6 8]
=> (let [pred-path (comp-paths filterer)]
(select-one (pred-path even?) (range 10)))
ClassCastException com.rpl.specter.impl.CompiledPath cannot be cast to clojure.lang.IFn
```
### if-path
`(if-path cond-path then-path)`
`(if-path cond-path then-path else-path)`
Like [cond-path ](#cond-path ), but with if semantics. If no else path is supplied and cond-path is not satisfied, stops navigation.
```clojure
2016-06-11 14:55:45 +00:00
=> (select (if-path (must :d) :a) {:a 0, :d 1})
2016-06-11 14:18:59 +00:00
(0)
2016-06-11 14:55:45 +00:00
=> (select (if-path (must :d) :a :b) {:a 0, :b 1})
2016-06-11 14:18:59 +00:00
(1)
2016-06-11 14:55:45 +00:00
=> (select (if-path (must :d) :a) {:b 0, :d 1})
2016-06-11 14:18:59 +00:00
()
;; is equivalent to
2016-06-11 14:55:45 +00:00
=> (select (if-path (must :d) :a STOP) {:b 0, :d 1})
2016-06-11 14:18:59 +00:00
()
```
### keypath
`(keypath key)`
2016-06-11 14:42:15 +00:00
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 ](#must ).
2016-06-11 14:18:59 +00:00
```clojure
2016-06-11 14:55:45 +00:00
=> (select-one (keypath :a) {:a 0})
2016-06-11 14:18:59 +00:00
0
;; Only one key allowed
2016-06-11 14:55:45 +00:00
=> (select-one (keypath :a :b) {:a {:b 1}})
2016-06-11 14:18:59 +00:00
{:b 1}
2016-06-11 14:55:45 +00:00
=> (select [ALL (keypath :a) [{:a 0} {:b 1}])
2016-06-11 14:18:59 +00:00
[0 nil]
2016-06-11 14:42:15 +00:00
;; Does not stop navigation
=> (select [ALL (keypath :a) (nil->val :boo)] [{:a 0} {:b 1}])
[0 :boo]
```
### multi-path
`(multi-path & paths)`
A path that branches on multiple paths. For updates,
applies updates to the paths in order.
```clojure
2016-06-11 14:55:45 +00:00
=> (select (multi-path :a :b) {:a 0, :b 1, :c 2})
2016-06-11 14:42:15 +00:00
(0 1)
2016-06-11 14:55:45 +00:00
=> (select (multi-path (filterer odd?) (filterer even?)) (range 10))
2016-06-11 14:42:15 +00:00
([1 3 5 7 9] [0 2 4 6 8])
2016-06-11 14:55:45 +00:00
=> (transform (multi-path :a :b) (fn [x] (println x) (dec x)) {:a 0, :b 1, :c 2})
2016-06-11 14:42:15 +00:00
0
1
{:a -1, :b 0, :c 2}
```
### must
`(must key)`
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 ](#keypath ).
```clojure
=> (select-one (must :a) {:a 0})
0
=> (select-one (must :a) {:b 1})
nil
;; Only follows one key
=> (select-one (must :a :b) {:a {:b 1}})
{:b 1}
2016-06-11 14:18:59 +00:00
```