Augment Option to support default as flag option
In some use cases, there is a need to have an option argument behave like a flag.
This change introduced 4 new intialiazers to Option that accept a defaultAsFlag value.
With the following usage:
struct Example: ParsableCommand {
@Option(defaultAsFlag: "default", help: "Set output format.")
var format: String?
func run() {
print("Format: \(format ?? "none")")
}
}
`
The defaultAsFlag parameter creates a hybrid that supports both patterns:
- Flag behavior:
--format(sets format to "default") - Option behavior:
--format json(sets format to "json") - No usage: format remains
nil
As a user of the command line tool, the --help output clearly distinguishes between the the hybrid and regular usages.
OPTIONS:
--format [<format>] Set output format. (default as flag: json)
Note the (default as flag: ...) text instead of regular (default: ...), and the optional value syntax [<value>] instead of required <value>.
Fixes: #829
Checklist
- [x] I've added at least one test that validates that my change is working, if appropriate
- [x] I've followed the code style of the rest of the project
- [x] I've read the Contribution Guidelines
- [x] I've updated the documentation if necessary
Would it make more sense instead to provide this functionality via Option? Like:
@Option(parsing: .scanningForValue(default: "text"))
var showBinPath: String?
You'd add/modify the following (I haven't checked the code for proper generics/types/compilation/keywords/etc.; it's just pseudo-code to illustrate the concept. I also haven't checked to see what problems adding the new SingleValueParsingStrategy to Option might cause):
public struct SingleValueParsingStrategy: Hashable {
…
// This is an addition
public static func scanningForValue<Value>(default: Value) -> SingleValueParsingStrategy {
self.init(base: .scanningForValue(default: default))
}
…
}
struct ArgumentDefinition {
…
enum ParsingStrategy {
…
// This is a modification
case scanningForValue(default: Any? = nil)
…
}
…
}
One possible issue: must ensure that the option terminator -- ensures that json in the following command line is interpreted as positional argument 1, not as a value for --show-bin-path, but that problem might exist for this any FlagOption solution, too:
cmd --show-bin-path -- json
Thanks for the feedback @rgoldberg . What you proposed makes more sense than what I implemented.
After discussing with @rauhul and @natecook1000 , we came up with the following API
New initializers
init<T>(wrappedValue: _OptionalNilComparisonType, name: NameSpecification, defaultAsFlag: T, parsing: SingleValueParsingStrategy, help: ArgumentHelp?, completion: CompletionKind?)
init<T>(wrappedValue: _OptionalNilComparisonType, name: NameSpecification, defaultAsFlag: T, parsing: SingleValueParsingStrategy, help: ArgumentHelp?, completion: CompletionKind?, transform: (String) throws -> T)
init<T>(name: NameSpecification, defaultAsFlag: T, parsing: SingleValueParsingStrategy, help: ArgumentHelp?, completion: CompletionKind?)
init<T>(name: NameSpecification, defaultAsFlag: T, parsing: SingleValueParsingStrategy, help: ArgumentHelp?, completion: CompletionKind?, transform: (String) throws -> T)
API usage looks as follows
@Option(name: .long("bin-path"), defaultAsFlag: FilePath("/default/path"))
var showBinPath: FilePath?
And the help dump looks like:
OVERVIEW: cli overview
USAGE: myBin [--bin-path [<path>]]
OPTIONS:
-b, --bin-path [<path>] argument help text. (default as flag: "/default/path")
-h, --help Show help information.