From 6a57895e844e1ecc38e571af7b81849ebb8b5263 Mon Sep 17 00:00:00 2001 From: Sam Vente Date: Sat, 30 Sep 2023 15:57:18 +0200 Subject: [PATCH] Expand `append` examples and add `match` example (#1083) * Expand `append` examples and add `match` example Append exmaples now also include examples on how to use ++ for example, which was a bit lacking. For `match` the `str append` example is added and expanded on * fix spacing and backtick issue * capitalization * Update cookbook/pattern_matching.md Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com> * fix typos --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com> --- .vuepress/configs/sidebar/en.ts | 1 + CONTRIBUTING.md | 2 +- book/working_with_lists.md | 13 +++-- book/working_with_strings.md | 33 +++++++++++++ book/working_with_tables.md | 51 ++++++++++++++----- cookbook/pattern_matching.md | 86 +++++++++++++++++++++++++++++++++ 6 files changed, 171 insertions(+), 15 deletions(-) create mode 100644 cookbook/pattern_matching.md diff --git a/.vuepress/configs/sidebar/en.ts b/.vuepress/configs/sidebar/en.ts index fc3436cc2ed..0494d56be8b 100644 --- a/.vuepress/configs/sidebar/en.ts +++ b/.vuepress/configs/sidebar/en.ts @@ -136,6 +136,7 @@ export const sidebarEn: SidebarConfig = { 'help', 'system', 'parsing', + 'pattern_matching', 'external_completers', 'files', 'git', diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb953b71e3e..c24d08abc7c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ This website is based on Vuepress. 2. Run `npm install` 3. Run `npm run dev` -If you're adding a new page to the book, to make it appear, put it also to `.vuepress/config.js`. +If you're adding a new page to the book, to make it appear, put it also to `.vuepress/configs/sidebar/{locale}.ts`. ## Translation Guide diff --git a/book/working_with_lists.md b/book/working_with_lists.md index c45eea0d29e..2c995802bc0 100644 --- a/book/working_with_lists.md +++ b/book/working_with_lists.md @@ -23,6 +23,7 @@ We can also use [`update`](/commands/docs/update.md) to replace the 2nd element ``` ## Removing or adding items from list + In addition to [`insert`](/commands/docs/insert.md) and [`update`](/commands/docs/update.md), we also have [`prepend`](/commands/docs/prepend.md) and [`append`](/commands/docs/append.md). These let you insert to the beginning of a list or at the end of the list, respectively. For example: @@ -31,23 +32,30 @@ For example: let colors = [yellow green] let colors = ($colors | prepend red) let colors = ($colors | append purple) -$colors # [red yellow green purple] +let colors = ($colors ++ "blue") +let colors = ("black" ++ $colors) +$colors # [black red yellow green purple blue] ``` -In case you want to remove items from list, there are many ways. [`skip`](/commands/docs/skip.md) allows you skip first rows from input, while [`drop`](/commands/docs/drop.md) allows you to skip specific numbered rows from end of list. +In case you want to remove items from list, there are many ways. [`skip`](/commands/docs/skip.md) allows you skip first rows from input, while [`drop`](/commands/docs/drop.md) allows you to skip specific numbered rows from end of list. + ```bash let colors = [red yellow green purple] let colors = ($colors | skip 1) let colors = ($colors | drop 2) $colors # [yellow] ``` + We also have [`last`](/commands/docs/last.md) and [`first`](/commands/docs/first.md) which allow you to [`take`](/commands/docs/take.md) from the end or beginning of the list, respectively. + ```bash let colors = [red yellow green purple black magenta] let colors = ($colors | last 3) $colors # [purple black magenta] ``` + And from the beginning of a list, + ```bash let colors = [yellow green purple] let colors = ($colors | first 2) @@ -204,4 +212,3 @@ let zones = [UTC CET Europe/Moscow Asia/Yekaterinburg] # Show world clock for selected time zones $zones | wrap 'Zone' | upsert Time {|it| (date now | date to-timezone $it.Zone | format date '%Y.%m.%d %H:%M')} ``` - diff --git a/book/working_with_strings.md b/book/working_with_strings.md index df925f068c5..c2b76209212 100644 --- a/book/working_with_strings.md +++ b/book/working_with_strings.md @@ -134,6 +134,39 @@ You can place the `^` sigil in front of any string (including a variable) to hav You can also use the [`run-external`](/commands/docs/run-external.md) command for this purpose, which provides additional flags and options. +## Appending and Prepending to strings + +There are various ways to pre, or append strings. If you want to add something to the beginning of each string closures are a good option: + +```sh +['foo', 'bar'] | each {|s| '~/' ++ $s} # ~/foo, ~/bar +['foo', 'bar'] | each {|s| '~/' + $s} # ~/foo, ~/bar +``` + +You can also use a regex to replace the beginning or end of a string: + +```sh +['foo', 'bar'] | str replace -r '^' '~/'# ~/foo, ~/bar +['foo', 'bar'] | str replace -r '$' '~/'# foo~/, bar~/ +``` + +If you want to get one string out of the end then `str join` is your friend: + +```sh +"hello" | append "world!" | str join " " # hello world! +``` + +You can also use reduce: + +```sh +1..10 | reduce -f "" {|it, acc| $acc + ($it | into string) + " + "} # 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + +``` + + +Though in the cases of strings, especially if you don't have to operate on the strings, it's usually easier and more correct (notice the extra + at the end in the example above) to use `str join`. + +Finally you could also use string interpolation, but that is complex enough that it is covered in it's own subsection below. + ## String interpolation More complex string use cases also need a new form of string: string interpolation. This is a way of building text from both raw text and the result of running expressions. String interpolation combines the results together, giving you a new string. diff --git a/book/working_with_tables.md b/book/working_with_tables.md index ee7324297f6..cbfbbd38fa3 100644 --- a/book/working_with_tables.md +++ b/book/working_with_tables.md @@ -166,12 +166,12 @@ In addition to selecting data from a table, we can also update what the table ha ### Concatenating Tables -We can concatenate tables with identical column names using [`append`](/commands/docs/append.md): +We can concatenate tables using [`append`](/commands/docs/append.md): -``` -> let $first = [[a b]; [1 2]] -> let $second = [[a b]; [3 4]] -> $first | append $second +```nu +let first = [[a b]; [1 2]] +let second = [[a b]; [3 4]] +$first | append $second ───┬───┬─── # │ a │ b ───┼───┼─── @@ -180,14 +180,43 @@ We can concatenate tables with identical column names using [`append`](/commands ───┴───┴─── ``` +If the column names are not identical then additionally columns and values will be created as necessary: + +```sh +let first = [[a b]; [1 2]] +let second = [[a b]; [3 4]] +let second = [[a c]; [3 4]] +$first | append $second | append $third +───┬───┬────┬──── + # │ a │ b │ c +───┼───┼────┼──── + 0 │ 1 │ 2 │ ❎ + 1 │ 3 │ 4 │ ❎ + 2 │ 3 │ ❎ │ 4 +───┴───┴────┴──── +``` + +You can also use the `++` operator as an inline replacement for `append`: + +```sh +$first ++ $second ++ $third +───┬───┬────┬──── + # │ a │ b │ c +───┼───┼────┼──── + 0 │ 1 │ 2 │ ❎ + 1 │ 3 │ 4 │ ❎ + 2 │ 3 │ ❎ │ 4 +───┴───┴────┴─── +``` + ### Merging Tables We can use the [`merge`](/commands/docs/merge.md) command to merge two (or more) tables together -``` -> let $first = [[a b]; [1 2]] -> let $second = [[c d]; [3 4]] -> $first | merge $second +```nu +let first = [[a b]; [1 2]] +let second = [[c d]; [3 4]] +$first | merge $second ───┬───┬───┬───┬─── # │ a │ b │ c │ d ───┼───┼───┼───┼─── @@ -197,8 +226,8 @@ We can use the [`merge`](/commands/docs/merge.md) command to merge two (or more) Let's add a third table: -``` -> let $third = [[e f]; [5 6]] +```nu +> let third = [[e f]; [5 6]] ``` We could join all three tables together like this: diff --git a/cookbook/pattern_matching.md b/cookbook/pattern_matching.md new file mode 100644 index 00000000000..974181e3227 --- /dev/null +++ b/cookbook/pattern_matching.md @@ -0,0 +1,86 @@ +--- +title: Pattern Matching +--- + +# Pattern Matching + +## Using the `match` keyword + +Like many other languages, nu offers a [`match`](https://www.nushell.sh/commands/docs/match.html#frontmatter-title-for-core) keyword. Usually this is used as a slightly more ergonomic version of `if-else` statements if you have many branches + +```shell +> [black red yellow green purple blue indigo] | each {|c| + match $c { + "black" => "classy" + "red" | "green" | "blue" => "fundamental" + "yellow" | "purple" => "vibrant" + _ => "innovative" + } +} +───┬──────────── + 0 │ classy + 1 │ funamental + 2 │ vibrant + 3 │ funamental + 4 │ vibrant + 5 │ funamental + 6 │ innovative +───┴──────────── +``` + +The equivalent in `if-else` statements would be: + +```shell +> [black red yellow green purple blue] | each {|c| + if ($c == "black") { + "classy" + } else if ( $c in ["red", "green", "blue"]) { + "fundamental" + } else if ( $c in ['yellow', "purple"]){ + "vibrant" + } else { + "innovative" + } + } +} +``` + +As you can see you can also use command expressions in match statements (in this case used with `|`). Also notice the `_` case at the end, this is called the default arm and is used. + +## Pattern matching on types + +You can use the [`describe`](https://www.nushell.sh/commands/docs/describe.html) command to get more info about the types of values. For example: + +```sh +{one: 1 two: 2} | describe +record + +[{a: 1 b: 2} {a: 2 b:3 }] | describe +table +``` + +Together with `match` and some clever regex use you can do quite powerful type matching. For example, let's say we wanted to implement a `str append` function that would work on both strings and lists. On strings it would work as expected, on lists of strings, it should append the same string to each element of the list. Using `match` one might do that like so: + +```nu +def "str append" [tail: string]: [string -> string, list -> list] { + let input = $in + match ($input | describe | str replace --regex '<.*' '') { + "string" => { $input ++ $tail }, + "list" => { $input | each {|el| $el ++ $tail} }, + _ => $input + } +} +``` + +The `$input | describe` would output for example `string` if the input was a string, and for example `list` for a list contianing multiple different types. The regex, removes everying after the first `<` leaving us just with `list`. + +Then with the `match` statement we can handle the different types sepertately. Finally in the default case we just return the input unaltered so that other types can simply pass through this filter without issue. +Also note that we have to capture the `$in` variable on the first statement of the function to still have access to it in each `match` arm. + +With this implementation we can check that the command works as expected: + +```nu +use std assert +assert equal ("foo" | str append "/") "foo/" +assert equal (["foo", "bar", "baz"] | str append "/") ["foo/", "bar/", "baz/"] +```