diff --git a/book/custom_commands.md b/book/custom_commands.md index 8c38843c3bb..5d1ae85c24d 100644 --- a/book/custom_commands.md +++ b/book/custom_commands.md @@ -3,6 +3,7 @@ prev: text: Programming in Nu link: /book/programming_in_nu.md --- + # Custom Commands As with any programming language, you'll quickly want to save longer pipelines and expressions so that you can call them again easily when needed. @@ -158,7 +159,7 @@ In this case, the final expression is the `match` statement which can return: - `null` if the directory is empty - Otherwise, a `record` representing the randomly chosen file -::: + ::: ## Custom Commands and Pipelines @@ -490,6 +491,9 @@ The following [types](./types_of_data.html) can be used for parameter annotation - `record` - `string` - `table` +- `oneof` + +See [Type signatures](/lang-guide/chapters/types/type_signatures.html) in the Language Reference Guide for more information. ::: diff --git a/lang-guide/chapters/types/type_signatures.md b/lang-guide/chapters/types/type_signatures.md index ca4103ef79b..b18caf6fcb5 100644 --- a/lang-guide/chapters/types/type_signatures.md +++ b/lang-guide/chapters/types/type_signatures.md @@ -45,7 +45,145 @@ There are 3 forms of valid type signatures in Nu: - Basic: E.g. `int`, `bool`, `string`, etc. - Compound: - `list`, - `record` + `record`, + `table` +- Sum types (aka type alternatives): E.g. `oneof` + +### List types + +- `list` - Read as `list of elements of type something` + +For example, `list` would specify a list of integers: + +```nu +def sum_two []: list -> int { $in.0 + $in.1 } + +[1 11 111 1111] | sum_two +# => 12 + +["abc" "def" "ghi"] | sum_two +# error: command doesn't support list input +``` + +- `list` - If no element type is specified, this is equivalent to `list`. + +```nu +def second []: list -> any { $in.1 } + +[1 11 111 1111] | second +# => 11 + +["abc" "def" "ghi"] | second +# => def +``` + +### Record types + +- `record` - Read as `record containing a key key_name with value of type value_type` + +```nu +def greet [person: record] { + $"Hello, ($person.name)!" +} + +greet { name: Ellie } +# => Hello, Ellie! + +greet "Who" +# error: a string is not a record + +greet { given_name: Bob } +# error: the record is missing a "name" key + +greet { name: [] } +# error: the record's "name" value can't be coerced to string + +# The record may contain more keys besides the specified ones though: +greet { name: Bob, age: 32 } +# => Hello, Bob! +``` + +We may also specify multiple keys that a record must possess as a comma separated `name: value_type` list. E.g.: + +```nu +def greet [person: record] { + print $"Hello, ($person.name) the ($person.job)!" + if ($person.birthday | format date "%m-%d") == (date now | format date "%m-%d") { + print "Happy birthday!" + } +} + +greet { name: Bob, job: Builder, birthday: 1998-11-28 } +# => Hello, Bob the Builder! +``` + +Similar to lists, `record` or `record<>` specifies a record with any keys (or even an empty record): + +```nu +def first_key []: record -> string { + columns | first +} + +{ name: Ellie } | first_key +# => name + +{ given_name: Bob } | first_key +# => given_name + +# this will pass type checking (but produce a runtime error) +{} | first_key +``` + +### Table types + +- `table` - Read as `table containing a column column_name with values of type value_type` + +Tables are just lists of records, so table types work very similarly to record types: + +```nu +let data: table, condition: string> = [ + [date temps condition ]; + [2022-02-01T14:30:00+05:00, [38.24, 38.50, 37.99, 37.98, 39.10], 'sunny' ], + [2022-02-02T14:30:00+05:00, [35.24, 35.94, 34.91, 35.24, 36.65], 'sunny' ], + [2022-02-03T14:30:00+05:00, [35.17, 36.67, 34.42, 35.76, 36.52], 'cloudy' ], + [2022-02-04T14:30:00+05:00, [39.24, 40.94, 39.21, 38.99, 38.80], 'rain' ] +] + +def temp_avg [] : table> -> table { + insert avg_temp {|record| $record.temps | math avg} + | reject temps +} + +# Note that both the input and output table contain a column "condition", which +# is not mentioned in the type signature of temp_avg. This is fine. +$data | temp_avg +# => ╭───┬─────────────┬───────────┬──────────╮ +# => │ # │ date │ condition │ avg_temp │ +# => ├───┼─────────────┼───────────┼──────────┤ +# => │ 0 │ 3 years ago │ sunny │ 38.36 │ +# => │ 1 │ 3 years ago │ sunny │ 35.60 │ +# => │ 2 │ 3 years ago │ cloudy │ 35.71 │ +# => │ 3 │ 3 years ago │ rain │ 39.44 │ +# => ╰───┴─────────────┴───────────┴──────────╯ +``` + +### Sum types + +- `oneof` - Read: one of `a`, `b` or `c` + +Example: + +```nu +def foo [ + param: oneof +] { + if ($param | describe) == "binary" { + $param | first 3 + } else { + $param | str substring 0..<3 + } +} +``` ## Custom command parameters and flags