1
Fork 0
mirror of https://github.com/RGBCube/nu_scripts synced 2025-08-01 06:37:46 +00:00

RFC: add a command to help parsing arguments in scripts (#875)

the other day, i was writing a script and wanted to pass a `list<int>`
to it which is not possible because there is no such things as _types_
for externals 🤔

i ended up writing an "arg parsing" command to help in that task and
thought it could be useful to people 😇

in this MR, i add `std-rfc parse-arg` in the `script-parsing.nu` module
and add associated tests which all pass.

i invite the reader to have a look at the docstring of `parse-arg` which
should contain a full example explaining the usage of this new command
😉

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
This commit is contained in:
Antoine Stevan 2024-07-21 13:58:34 +02:00 committed by GitHub
parent 6aa2700730
commit 71f5736d93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 100 additions and 0 deletions

View file

@ -6,3 +6,4 @@ export module math/
export use bulk-rename.nu *
export use set-env.nu *
export use bench.nu
export use script-parsing.nu [ parse-arg ]

View file

@ -0,0 +1,61 @@
# helps parsing CLI arguments for Nushell scripts
#
# the following Nushell script does not make sense to be used as an external
# command because there is no such thing as a `list<string>` in Bash for
# instance.
# ```nushell
# def main [x: list<int>] {
# print $x
# }
# ```
#
# one needs to write something less strict at parse-time and thus looses type
# information...
# ```nushell
# def main [
# x: string, # list<int>
# ] {
# print $x
# }
# ```
#
# it's possible to write a much stronger script whith `parse-arg`
# ```nushell
# def main [
# x: string, # list<int>
# ] {
# let x = $x | parse-arg (metadata $x).span "list<int>" # the script would crash if either
# # `$x: string` is not valid NUON or if
# # the resulting value is not a `list<int>`
# print $x # here, `$x` is a `list<int>` as intended
# }
# ```
export def parse-arg [
span: record<start: int, end: int>, # the span of the input variable
expected_type: string, # the expected type for the input variable
]: [ string -> any ] {
let val = try {
$in | from nuon
} catch {
error make {
msg: $"(ansi red_bold)invalid NUON(ansi reset)",
label: {
text: "invalid NUON",
span: $span,
},
}
}
if ($val | describe) != $expected_type {
error make {
msg: $"(ansi red_bold)bad type(ansi reset)",
label: {
text: $"type: ($val | describe)",
span: $span,
},
help: $"expected ($expected_type)",
}
}
$val
}

View file

@ -3,4 +3,5 @@ export module record.nu
export module str_xpend.nu
export module math.nu
export module bench.nu
export module script-parsing.nu
export module str_dedent.nu

View file

@ -0,0 +1,37 @@
use std assert
use ../std-rfc parse-arg
const SPAN = { start: 0, end: 0 }
export def "test parse-arg ok" [] {
const TEST_CASES = [
[ input, type, expected ];
[ "123", "int", 123 ],
[ "[1, 2, 3]", "list<int>", [1, 2, 3] ],
[ "'spam'", "string", "spam" ],
[
"{ a: 1, b: 'egg', c: false }",
"record<a: int, b: string, c: bool>",
{ a: 1, b: 'egg', c: false },
],
]
for t in $TEST_CASES {
assert equal ($t.input | parse-arg $SPAN $t.type) $t.expected
}
}
export def "test parse-arg err" [] {
const TEST_CASES = [
[ input, type ];
[ "{ invalid NUON", "" ],
[ "[1, 2, 3]", "string" ],
]
for t in $TEST_CASES {
let msg = $"test case: input: '($t.input)', type: ($t.type)"
assert error { $t.input | parse-arg $SPAN $t.type } $msg
}
}