From 573c3b81cdb7c5d612f4ee8d075561945ba3d040 Mon Sep 17 00:00:00 2001 From: Chris O'Donnell Date: Thu, 16 Jun 2016 16:38:39 -0400 Subject: [PATCH 1/3] Add descriptions and examples for 0.12.0 macros. --- List-of-Macros.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/List-of-Macros.md b/List-of-Macros.md index 651f20e..d039425 100644 --- a/List-of-Macros.md +++ b/List-of-Macros.md @@ -33,6 +33,31 @@ # Core Macros +## collected? + +`(collected? params & body)` + +_Added in 0.12.0_ + +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. + +`collected?` operates in the same fashion as [pred](List-of-Navigators#pred), but it takes the collected values as its arguments rather than the structure. + +```clojure +=> (select [ALL (collect-one FIRST) LAST (collected? [k] (= k :a))] {:a 0 :b 1}) +[[:a 0]] +=> (select [ALL (collect-one FIRST) LAST (collected? [k] (< k 2))] + (zipmap (range 5) ["a" "b" "c" "d" "e"])) +[[0 "a"] [1 "b"]] +=> (transform [ALL (collect-one FIRST) LAST (collected? [k] (< k 2)) DISPENSE] + string/upper-case + (zipmap (range 5) ["a" "b" "c" "d" "e"])) +{0 "A", 1 "B", 2 "c", 3 "d", 4 "e"} +``` + ## replace-in `(replace-in apath transform-fn structure & args)` @@ -78,6 +103,49 @@ factor/cache the path. [[:a 0] [:b 1]] ``` +## select-any + +`(select-any apath structure)` + +_Added in 0.12.0_ + +Returns any element found or `com.rpl.specter/NONE` if nothing selected. This is the most +efficient of the various selection operations. +This macro will attempt to do inline factoring and caching of the path, falling +back to compiling the path on every invocation if it's not possible to +factor/cache the path. + +```clojure +=> (select-any STAY :a) +:a +=> (select-any even? 3) +:com.rpl.specter.impl/NONE ; Implementation detail +=> (= com.rpl.specter/NONE :com.rpl.specter.impl/NONE) +true +``` + +## selected-any? + +`(selected-any? apath structure)` + +_Added in 0.12.0_ + +Returns true if any element was selected, false otherwise. +This macro will attempt to do inline factoring and caching of the path, falling +back to compiling the path on every invocation if it's not possible to +factor/cache the path. + +```clojure +=> (selected-any? STAY :a) +true +=> (selected-any? even? 3) +false +=> (selected-any? ALL (range 10)) +true +=> (selected-any? ALL []) +false +``` + ## select-first `(select-first apath structure)` @@ -172,6 +240,29 @@ Note that `transform` takes as its initial arguments any collected values. Its l {:a {:key :a, :val 0}, :b {:key :b, :val 1}} ``` +## traverse + +`(traverse apath structure)` + +_Added in 0.12.0_ + +Return a reducible object that traverses over `structure` to every element +specified by the path. +This macro will attempt to do inline factoring and caching of the path, falling +back to compiling the path on every invocation if it's not possible to +factor/cache the path. + +`(reduce afn init (traverse apath structure))` will always return the same thing as `(reduce afn init (select apath structure))`, but more efficiently. The return value of `traverse` is only useful as an argument to `reduce`; for all other uses, prefer `select`. + +```clojure +=> (reduce + 0 (traverse ALL (range 10))) +45 +=> (reduce + 0 (traverse (walker integer?) [[[1 2]] 3 [4 [[5 6 7]] 8] 9])) +45 +=> (traverse (walker integer?) [[[1 2]] 3 [4 [[5 6 7]] 8] 9]) +;; returns object implementing clojure.lang.IReduce +``` + # Path Macros ## declarepath @@ -303,7 +394,7 @@ The arguments to `path` cannot include local symbols (defined in a `let`), dynam Any higher order navigators passed to `path` must include their arguments, even if their arguments will be evaluated at runtime. `path` cannot be passed late bound parameters. -**Note:** In general, you should prefer using `comp-paths` and `select` over `path` and `compiled-select`. `comp-paths` allows late bound parameters, and `path` does not, so `comp-paths` is more flexible. `select` automatically calls `path` on its path arguments, so you do not lose the speed of inline caching (unless you pass a local symbol, dynamic var, or special form). You can ensure you do not do this by calling `(must-cache-paths!)`. You can find a more detailed discussion of inline caching [here](https://github.com/nathanmarz/specter/wiki/Specter-0.11.0:-Performance-without-the-tradeoffs). +**Note:** In general, you should prefer using `comp-paths` and `select` over `path` and `compiled-select`. `comp-paths` allows late bound parameters, and `path` does not, so `comp-paths` is more flexible. `select` automatically applies `path` to its path arguments, so you do not lose the speed of inline caching (unless you pass a local symbol, dynamic var, or special form). You can ensure you do not do this by calling `(must-cache-paths!)`. You can find a more detailed discussion of inline caching [here](https://github.com/nathanmarz/specter/wiki/Specter-0.11.0:-Performance-without-the-tradeoffs). ```clojure => (def p (path even?)) From a44a5070648054384028bf1f8ad1015c576323a4 Mon Sep 17 00:00:00 2001 From: Chris O'Donnell Date: Thu, 16 Jun 2016 16:39:37 -0400 Subject: [PATCH 2/3] Update macros table of contents. --- List-of-Macros.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/List-of-Macros.md b/List-of-Macros.md index d039425..68d829b 100644 --- a/List-of-Macros.md +++ b/List-of-Macros.md @@ -2,13 +2,17 @@ **Table of Contents** - [Core Macros](#core-macros) + - [collected?](#collected) - [replace-in](#replace-in) - [select](#select) + - [select-any](#select-any) + - [selected-any?](#selected-any) - [select-first](#select-first) - [select-one](#select-one) - [select-one!](#select-one) - [setval](#setval) - [transform](#transform) + - [traverse](#traverse) - [Path Macros](#path-macros) - [declarepath](#declarepath) - [defpathedfn](#defpathedfn) From 11fa033f9429df173bdf5535923213f6d4005f9f Mon Sep 17 00:00:00 2001 From: Chris O'Donnell Date: Thu, 16 Jun 2016 16:53:47 -0400 Subject: [PATCH 3/3] Add table of contents, DISPENSE, and META to navigator list. --- List-of-Navigators.md | 180 ++++++++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 59 deletions(-) diff --git a/List-of-Navigators.md b/List-of-Navigators.md index b45fbf2..0e44b70 100644 --- a/List-of-Navigators.md +++ b/List-of-Navigators.md @@ -1,24 +1,58 @@ -# List of Navigators with Examples - **Note:** Many of the descriptions and a couple of the examples are lightly edited from those found on the [Codox documentation](http://nathanmarz.github.io/specter/com.rpl.specter.html). -[ALL](#all) [ATOM](#atom) [BEGINNING](#beginning) [END](#end) [FIRST](#first) [LAST](#last) -[MAP-VALS](#map-vals) [NIL->LIST](#nil-list) [NIL->SET](#nil-set) [NIL->VECTOR](#nil-vector) -[STAY](#stay) [STOP](#stop) [VAL](#val) +**Table of Contents** -[codewalker](#codewalker) [collect](#collect) [collect-one](collect-one) [comp-paths](#comp-paths) -[compiled-replace-in](#compiled-*) [compiled-select](#compiled-*) [compiled-select-first](#compiled-*) -[compiled-select-one](#compiled-*) [compiled-select-one!](#compiled-*) [compiled-setval](#compiled-*) -[compiled-transform](#compiled-*) [cond-path](#cond-path) [continue-then-stay](#continue-then-stay) -[continuous-subseqs](#continuous-subseqs) [filterer](#filterer) [if-path](#if-path) -[keypath](#keypath) [multi-path](#multi-path) [must](#must) [nil->val](#nil-val) [params-reset](#params-reset) -[parser](#parser) [pred](#pred) [putval](#putval) [not-selected?](#not-selected) -[selected?](#selected) [srange](#srange) [srange-dynamic](#srange-dynamic) -[stay-then-continue](#stay-then-continue) [submap](#submap) [subselect](#subselect) [subset](#subset) -[transformed](#transformed) [view](#view) [walker](#walker) -## Unparameterized Navigators +- [Unparameterized Navigators](#unparameterized-navigators) + - [ALL](#all) + - [ATOM](#atom) + - [BEGINNING](#beginning) + - [END](#end) + - [FIRST](#first) + - [LAST](#last) + - [MAP-VALS](#map-vals) + - [NIL->LIST](#nil-list) + - [NIL->SET](#nil-set) + - [NIL->VECTOR](#nil-vector) + - [STAY](#stay) + - [STOP](#stop) + - [VAL](#val) +- [Parameterized Navigators (and Functions)](#parameterized-navigators-and-functions) + - [codewalker](#codewalker) + - [collect](#collect) + - [collect-one](#collect-one) + - [comp-paths](#comp-paths) + - [compiled-*](#compiled-) + - [cond-path](#cond-path) + - [continue-then-stay](#continue-then-stay) + - [continuous-subseqs](#continuous-subseqs) + - [filterer](#filterer) + - [if-path](#if-path) + - [keypath](#keypath) + - [multi-path](#multi-path) + - [must](#must) + - [nil->val](#nil-val) + - [params-reset](#params-reset) + - [parser](#parser) + - [pred](#pred) + - [putval](#putval) + - [not-selected?](#not-selected) + - [selected?](#selected) + - [srange](#srange) + - [srange-dynamic](#srange-dynamic) + - [stay-then-continue](#stay-then-continue) + - [submap](#submap) + - [subselect](#subselect) + - [subset](#subset) + - [transformed](#transformed) + - [view](#view) + - [walker](#walker) -### ALL + + + +# Unparameterized Navigators + +## ALL `ALL` navigates to every element in a collection. If the collection is a map, it will navigate to each key-value pair `[key value]`. @@ -33,7 +67,7 @@ {:a :b, :c :d} ``` -### ATOM +## ATOM `ATOM` navigates to the value of an atom. @@ -49,7 +83,7 @@ 2 ``` -### BEGINNING +## BEGINNING `BEGINNING` navigates to the empty subsequence before the beginning of a collection. Useful with `setval` to add values onto the beginning of a sequence. @@ -66,7 +100,20 @@ ([:foo :baz] [:foo :bar]) ``` -### END +## DISPENSE + +_Added in 0.12.0_ + +Drops all collected values for subsequent navigation. + +```clojure +=> (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 `END` navigates to the empty subsequence after the end of a collection. Useful with `setval` to add values onto the end of a sequence. @@ -83,7 +130,7 @@ ([:foo :bar] [:foo :baz]) ``` -### FIRST +## FIRST `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. @@ -100,7 +147,7 @@ nil nil ``` -### LAST +## LAST `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. @@ -117,7 +164,7 @@ nil nil ``` -### MAP-VALS +## MAP-VALS `MAP-VALS` navigates to every value in a map. `MAP-VALS` is more efficient than `[ALL LAST]`. @@ -128,7 +175,22 @@ nil (:c :f) ``` -### NIL->LIST +## META + +_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. + +```clojure +=> (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} +``` + +## NIL->LIST `NIL->LIST` navigates to the empty list `'()` if the value is nil. Otherwise it stays at the current value. @@ -139,7 +201,7 @@ nil :foo ``` -### NIL->SET +## NIL->SET `NIL->SET` navigates to the empty set `#{}` if the value is nil. Otherwise it stays at the current value. @@ -150,7 +212,7 @@ nil :foo ``` -### NIL->VECTOR +## NIL->VECTOR `NIL->VECTOR` navigates to the empty vector `[]` if the value is nil. Otherwise it stays at the current value. @@ -161,7 +223,7 @@ nil :foo ``` -### STAY +## STAY `STAY` stays in place. It is the no-op navigator. @@ -170,7 +232,7 @@ nil :foo ``` -### STOP +## STOP `STOP` stops navigation. For transformation, returns the structure unchanged. @@ -183,7 +245,7 @@ nil (0 1 2 3 4) ``` -### VAL +## VAL Collects the current structure. @@ -197,9 +259,9 @@ See also [collect](#collect), [collect-one](#collect-one), and [putval](#putval) (5 6 7 8 9) ``` -## Parameterized Navigators (and Functions) +# Parameterized Navigators (and Functions) -### codewalker +## codewalker `(codewalker afn)` @@ -218,7 +280,7 @@ See also [walker](#walker). ({:foo :bar}) ``` -### collect +## collect `(collect & paths)` @@ -243,7 +305,7 @@ See also [VAL](#val), [collect-one](#collect-one), and [putval](#putval) ([0 1 2] 1 2) ``` -### collect-one +## collect-one `(collect-one & paths)` @@ -262,7 +324,7 @@ See also [VAL](#val), [collect](#collect), and [putval](#putval) {:a 105,, :b 5 :c 7} ``` -### comp-paths +## comp-paths `(comp-paths & path)` @@ -281,11 +343,11 @@ path will require parameters for all such navigators in the order in which they [1 2 3] ``` -### compiled-* +## compiled-* These functions operate in the same way as their uncompiled counterparts, but they require their path to be precompiled with [comp-paths](#comp-paths). -### cond-path +## cond-path `(cond-path & conds)` @@ -308,7 +370,7 @@ See also [if-path](#if-path) () ``` -### continue-then-stay +## continue-then-stay `(continue-then-stay & path)` @@ -322,7 +384,7 @@ See also [stay-then-continue](#stay-then-continue). (0 1 2 {:a 0, :b 1, :c 2}) ``` -### continuous-subseqs +## continuous-subseqs `(continuous-subseqs pred)` @@ -337,7 +399,7 @@ Navigates to every continuous subsequence of elements matching `pred`. [11 12 20] ``` -### filterer +## filterer `(filterer & path)` @@ -365,7 +427,7 @@ See also [subselect](#subselect). ClassCastException com.rpl.specter.impl.CompiledPath cannot be cast to clojure.lang.IFn ``` -### if-path +## if-path `(if-path cond-path then-path)` `(if-path cond-path then-path else-path)` @@ -386,7 +448,7 @@ See also [if-path](#if-path) () ``` -### keypath +## keypath `(keypath key)` @@ -407,7 +469,7 @@ See also [must](#must) [0 :boo] ``` -### multi-path +## multi-path `(multi-path & paths)` @@ -425,7 +487,7 @@ applies updates to the paths in order. {:a -1, :b 0, :c 2} ``` -### must +## must `(must key)` @@ -443,7 +505,7 @@ nil {:b 1} ``` -### nil->val +## nil->val `(nil->val v)` @@ -457,7 +519,7 @@ navigated at the structure. :b ``` -### params-reset +## params-reset `(params-reset params-path)` @@ -478,7 +540,7 @@ Instructs the provided navigator to backtrack in the params array by the number ({:a {:a {:b 2}}} {:a {:b 2}} {:b 2}) ``` -### parser +## parser `(parser parse-fn unparse-fn)` @@ -498,7 +560,7 @@ it to get the final value at this point. ["test@example.com" "test+spam@gmail.com"] ``` -### pred +## pred `(pred apred)` @@ -515,7 +577,7 @@ See also [must](#must). [0 2 4 6 8] ``` -### putval +## putval `(putval val)` @@ -531,7 +593,7 @@ See also [VAL](#val), [collect](#collect), and [collect-one](#collect-one) {:a {:b 3}} ``` -### not-selected? +## not-selected? `(not-selected? & path)` @@ -553,7 +615,7 @@ See also [selected?](#selected?). nil ``` -### selected? +## selected? `(selected? & path)` @@ -576,7 +638,7 @@ See also [not-selected?](#not-selected?). nil ``` -### srange +## srange `(srange start end)` @@ -594,7 +656,7 @@ IndexOutOfBoundsException (0 1 4) ``` -### srange-dynamic +## srange-dynamic `(srange-dynamic start-fn end-fn)` @@ -610,7 +672,7 @@ See also [srange](#srange). [0 1 2 3 4] ``` -### stay-then-continue +## stay-then-continue `(stay-then-continue)` @@ -624,7 +686,7 @@ See also [continue-then-stay](#continue-then-stay). ({:a 0, :b 1, :c 2} 0 1 2) ``` -### submap +## submap `(submap m-keys)` @@ -648,7 +710,7 @@ value of the submap. {:a 0, :b 1, :c 2} ``` -### subselect +## subselect `(subselect & path)` @@ -670,7 +732,7 @@ See also [filterer](#filterer). [1 [[[10]] 3] 5 [8 [7 6]] 2] ``` -### subset +## subset `(subset aset)` @@ -687,7 +749,7 @@ new value of the subset. #{:c :b :a} ``` -### transformed +## transformed `(transformed path update-fn)` @@ -707,7 +769,7 @@ See also [view](#view) (0 1 1 3 2 5 3 7 4 9) ``` -### view +## view `(view afn)` @@ -720,7 +782,7 @@ See also [transformed](#transformed). 1 ``` -### walker +## walker `(walker afn)`