Skip to content

Commit

Permalink
Expand append examples and add match example (#1083)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* fix typos

---------

Co-authored-by: Darren Schroeder <[email protected]>
Co-authored-by: Antoine Stevan <[email protected]>
  • Loading branch information
3 people committed Sep 30, 2023
1 parent 8ab327f commit 6a57895
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 15 deletions.
1 change: 1 addition & 0 deletions .vuepress/configs/sidebar/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const sidebarEn: SidebarConfig = {
'help',
'system',
'parsing',
'pattern_matching',
'external_completers',
'files',
'git',
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
13 changes: 10 additions & 3 deletions book/working_with_lists.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
Expand Down Expand Up @@ -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')}
```
33 changes: 33 additions & 0 deletions book/working_with_strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
51 changes: 40 additions & 11 deletions book/working_with_tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
───┼───┼───
Expand All @@ -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
───┼───┼───┼───┼───
Expand All @@ -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:
Expand Down
86 changes: 86 additions & 0 deletions cookbook/pattern_matching.md
Original file line number Diff line number Diff line change
@@ -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<one: int, two: int>
[{a: 1 b: 2} {a: 2 b:3 }] | describe
table<a: int, b: int>
```
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<string> -> list<string>] {
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<any>` 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/"]
```

0 comments on commit 6a57895

Please sign in to comment.