Skip to content

Commit

Permalink
Nate/continue default initialization (apple#193)
Browse files Browse the repository at this point in the history
* Use type inference for flags / options

* Use default value syntax for arg/option arrays

* Allow a default for flag arrays

* Fix some whitespace

* Allow arguments validations to warn instead of fail

* Move nonsense flag warning to argument validation

* Update guides/readme with default literal syntax
  • Loading branch information
natecook1000 authored Jun 23, 2020
1 parent c0f9a5f commit 35ceb59
Show file tree
Hide file tree
Showing 29 changed files with 462 additions and 265 deletions.
8 changes: 4 additions & 4 deletions Documentation/01 Getting Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ struct Count: ParsableCommand {
var outputFile: String

@Flag()
var verbose: Bool
var verbose = false

mutating func run() throws {
if verbose {
Expand Down Expand Up @@ -175,7 +175,7 @@ struct Count: ParsableCommand {
var outputFile: String

@Flag(name: .shortAndLong)
var verbose: Bool
var verbose = false

mutating func run() throws { ... }
}
Expand Down Expand Up @@ -209,7 +209,7 @@ struct Count: ParsableCommand {
var outputFile: String

@Flag(name: .shortAndLong, help: "Print status updates while counting.")
var verbose: Bool
var verbose = false

mutating func run() throws { ... }
}
Expand Down Expand Up @@ -244,7 +244,7 @@ struct Count: ParsableCommand {
var outputFile: String

@Flag(name: .shortAndLong, help: "Print status updates while counting.")
var verbose: Bool
var verbose = false

mutating func run() throws {
if verbose {
Expand Down
44 changes: 22 additions & 22 deletions Documentation/02 Arguments, Options, and Flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,24 @@ The three preceding examples could be calls of this `Example` command:

```swift
struct Example: ParsableCommand {
@Argument() var files: [String]
@Argument() var files: [String] = []

@Option() var count: Int?

@Option var index: Int = 0
@Option() var index = 0

@Flag() var verbose: Bool
@Flag() var verbose = false

@Flag() var stripWhitespace: Bool
@Flag() var stripWhitespace = false
}
```

This example shows how `ArgumentParser` provides defaults that speed up your initial development process:

- Option and flag names are derived from the names of your command's properties.
- Whether arguments are required and what kinds of inputs are valid is based on your properties' types.
- What kinds of inputs are valid, and whether arguments are required, is based on your properties' types and default values.

In this example, all of the properties have default values — Boolean flags always default to `false`, optional properties default to `nil`, and arrays default to an empty array. An option, flag, or argument with a `default` parameter can also be omitted by the user.
In this example, all of the properties have default values (optional properties default to `nil`).

Users must provide values for all properties with no implicit or specified default. For example, this command would require one integer argument and a string with the key `--user-name`.

Expand All @@ -70,12 +70,12 @@ Usage: example --user-name <user-name> <value>
See 'example --help' for more information.
```

When using the `default` parameter for an array property, the default values will not be included if additional values are passed on the command line.
When providing a default value for an array property, any user-supplied values replace the entire default.

```
```swift
struct Lucky: ParsableCommand {
@Argument(default: [7, 14, 21])
var numbers: [Int]
@Argument()
var numbers = [7, 14, 21]

mutating func run() throws {
print("""
Expand Down Expand Up @@ -104,10 +104,10 @@ You can override this default by specifying one or more name specifications in t
```swift
struct Example: ParsableCommand {
@Flag(name: .long) // Same as the default
var stripWhitespace: Bool
var stripWhitespace = false

@Flag(name: .short)
var verbose: Bool
var verbose = false

@Option(name: .customLong("count"))
var iterationCount: Int
Expand Down Expand Up @@ -214,7 +214,7 @@ Flags are most frequently used for `Bool` properties. You can generate a `true`/
```swift
struct Example: ParsableCommand {
@Flag(inversion: .prefixedNo)
var index: Bool = true
var index = true

@Flag(inversion: .prefixedEnableDisable)
var requiredElement: Bool
Expand All @@ -225,7 +225,7 @@ struct Example: ParsableCommand {
}
```

When providing a flag inversion, you can pass your own default with normal property initialization syntax (`@Flag var foo: Bool = true`). If you want to require that the user specify one of the two inversions, use a non-Optional type and do not pass a default value.
When declaring a flag with an inversion, set the default by specifying `true` or `false` as the property's initial value. If you want to require that the user specify one of the two inversions, leave off the default value.

In the `Example` command defined above, a flag is required for the `requiredElement` property. The specified prefixes are prepended to the long names for the flags:

Expand All @@ -241,19 +241,19 @@ Error: Missing one of: '--enable-required-element', '--disable-required-element'
To create a flag with custom names for a Boolean value, to provide an exclusive choice between more than two names, or for collecting multiple values from a set of defined choices, define an enumeration that conforms to the `EnumerableFlag` protocol.

```swift
enum CacheMethod: EnumerableFlag {
enum CacheMethod: String, EnumerableFlag {
case inMemoryCache
case persistentCache
}

enum Color: EnumerableFlag {
enum Color: String, EnumerableFlag {
case pink, purple, silver
}

struct Example: ParsableCommand {
@Flag() var cacheMethod: CacheMethod

@Flag() var colors: [Color]
@Flag() var colors: [Color] = []

mutating func run() throws {
print(cacheMethod)
Expand Down Expand Up @@ -302,7 +302,7 @@ For example, this command defines a `--verbose` flag, a `--name` option, and an

```swift
struct Example: ParsableCommand {
@Flag() var verbose: Bool
@Flag() var verbose = false
@Option() var name: String
@Argument() var file: String?

Expand Down Expand Up @@ -349,8 +349,8 @@ The default strategy for parsing options as arrays is to read each value from a

```swift
struct Example: ParsableCommand {
@Option() var file: [String]
@Flag() var verbose: Bool
@Option() var file: [String] = []
@Flag() var verbose = false

mutating func run() throws {
print("Verbose: \(verbose), files: \(file)")
Expand Down Expand Up @@ -400,8 +400,8 @@ The default strategy for parsing arrays of positional arguments is to ignore al

```swift
struct Example: ParsableCommand {
@Flag() var verbose: Bool
@Argument() var files: [String]
@Flag() var verbose = false
@Argument() var files: [String] = []

mutating func run() throws {
print("Verbose: \(verbose), files: \(files)")
Expand Down
6 changes: 3 additions & 3 deletions Documentation/03 Commands and Subcommands.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ In this case, the `Options` type accepts a `--hexadecimal-output` flag and expec
```swift
struct Options: ParsableArguments {
@Flag(name: [.long, .customShort("x")], help: "Use hexadecimal notation for the result.")
var hexadecimalOutput: Bool
var hexadecimalOutput = false

@Argument(help: "A group of integers to operate on.")
var values: [Int]
Expand Down Expand Up @@ -124,7 +124,7 @@ extension Math.Statistics {
var kind: Kind = .mean

@Argument(help: "A group of floating-point values to operate on.")
var values: [Double]
var values: [Double] = []

func calculateMean() -> Double { ... }
func calculateMedian() -> Double { ... }
Expand All @@ -151,7 +151,7 @@ extension Math.Statistics {
abstract: "Print the standard deviation of the values.")

@Argument(help: "A group of floating-point values to operate on.")
var values: [Double]
var values: [Double] = []

mutating func run() {
if values.isEmpty {
Expand Down
8 changes: 4 additions & 4 deletions Documentation/04 Customizing Help.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ You can provide help text when declaring any `@Argument`, `@Option`, or `@Flag`
```swift
struct Example: ParsableCommand {
@Flag(help: "Display extra information while processing.")
var verbose: Bool
var verbose = false

@Option(help: "The number of extra lines to show.")
var extraLines: Int = 0
var extraLines = 0

@Argument(help: "The input file.")
var inputFile: String?
Expand Down Expand Up @@ -42,12 +42,12 @@ Here's the same command with some extra customization:
```swift
struct Example: ParsableCommand {
@Flag(help: "Display extra information while processing.")
var verbose: Bool
var verbose = false

@Option(help: ArgumentHelp(
"The number of extra lines to show.",
valueName: "n"))
var extraLines: Int = 0
var extraLines = 0

@Argument(help: ArgumentHelp(
"The input file.",
Expand Down
5 changes: 2 additions & 3 deletions Documentation/05 Validation and Errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct Select: ParsableCommand {
var count: Int = 1

@Argument()
var elements: [String]
var elements: [String] = []

mutating func validate() throws {
guard count >= 1 else {
Expand Down Expand Up @@ -127,12 +127,11 @@ struct ExampleDataModel: Codable {
}

struct Example: ParsableCommand {

// Reads in the argument string and attempts to transform it to
// an `ExampleDataModel` object using the `JSONDecoder`. If the
// string is not valid JSON, `decode` will throw an error and
// parsing will halt.
@Argument(transform: ExampleDataModel.dataModel )
@Argument(transform: ExampleDataModel.dataModel)
var inputJSON: ExampleDataModel

// Specifiying this option will always cause the parser to exit
Expand Down
4 changes: 2 additions & 2 deletions Documentation/06 Manual Parsing and Testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ Let's implement the `Select` command discussed in [Validation and Errors](05%20V

```swift
struct SelectOptions: ParsableArguments {
@Option
@Option()
var count: Int = 1

@Argument()
var elements: [String]
var elements: [String] = []
}
```

Expand Down
16 changes: 8 additions & 8 deletions Examples/math/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ struct Math: ParsableCommand {
struct Options: ParsableArguments {
@Flag(name: [.customLong("hex-output"), .customShort("x")],
help: "Use hexadecimal notation for the result.")
var hexadecimalOutput: Bool = false
var hexadecimalOutput = false

@Argument(
help: "A group of integers to operate on.")
var values: [Int]
var values: [Int] = []
}

extension Math {
Expand Down Expand Up @@ -103,7 +103,7 @@ extension Math.Statistics {
var kind: Kind = .mean

@Argument(help: "A group of floating-point values to operate on.")
var values: [Double]
var values: [Double] = []

func validate() throws {
if (kind == .median || kind == .mode) && values.isEmpty {
Expand Down Expand Up @@ -166,7 +166,7 @@ extension Math.Statistics {
abstract: "Print the standard deviation of the values.")

@Argument(help: "A group of floating-point values to operate on.")
var values: [Double]
var values: [Double] = []

mutating func run() {
if values.isEmpty {
Expand All @@ -189,15 +189,15 @@ extension Math.Statistics {
abstract: "Print the quantiles of the values (TBD).")

@Argument(help: "A group of floating-point values to operate on.")
var values: [Double]
var values: [Double] = []

// These args and the validation method are for testing exit codes:
@Flag(help: .hidden)
var testSuccessExitCode: Bool = false
var testSuccessExitCode = false
@Flag(help: .hidden)
var testFailureExitCode: Bool = false
var testFailureExitCode = false
@Flag(help: .hidden)
var testValidationExitCode: Bool = false
var testValidationExitCode = false
@Option(help: .hidden)
var testCustomExitCode: Int32?

Expand Down
2 changes: 1 addition & 1 deletion Examples/repeat/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct Repeat: ParsableCommand {
var count: Int?

@Flag(help: "Include a counter with each repetition.")
var includeCounter: Bool = false
var includeCounter = false

@Argument(help: "The phrase to repeat.")
var phrase: String
Expand Down
6 changes: 3 additions & 3 deletions Examples/roll/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ import ArgumentParser

struct RollOptions: ParsableArguments {
@Option(help: ArgumentHelp("Rolls the dice <n> times.", valueName: "n"))
var times: Int = 1
var times = 1

@Option(help: ArgumentHelp(
"Rolls an <m>-sided dice.",
discussion: "Use this option to override the default value of a six-sided die.",
valueName: "m"))
var sides: Int = 6
var sides = 6

@Option(help: "A seed to use for repeatable random generation.")
var seed: Int?

@Flag(name: .shortAndLong, help: "Show all roll results.")
var verbose: Bool = false
var verbose = false
}

// If you prefer writing in a "script" style, you can call `parseOrExit()` to
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import ArgumentParser

struct Repeat: ParsableCommand {
@Flag(help: "Include a counter with each repetition.")
var includeCounter: Bool
var includeCounter = false

@Option(name: .shortAndLong, help: "The number of times to repeat 'phrase'.")
var count: Int?
Expand Down
Loading

0 comments on commit 35ceb59

Please sign in to comment.