-
Notifications
You must be signed in to change notification settings - Fork 221
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]>
- Loading branch information
Showing
4 changed files
with
100 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
} |