Skip to content

Allow normal Swift default property initialization syntax #170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f918b83
Allow normal Swift default property initialization syntax
MPLew-is May 30, 2020
7517781
Merge branch 'master' into default-property-initialization
MPLew-is Jun 14, 2020
caa77a5
Add simple tests for default property initialization
MPLew-is Jun 14, 2020
07fd64f
Centralize some constructor logic into a private `init`
MPLew-is Jun 14, 2020
60ed36f
Deprecate previous `Option.init` with `default` parameter
MPLew-is Jun 14, 2020
b70dbf1
Document added test cases
MPLew-is Jun 14, 2020
3e32345
Correct punctuation
MPLew-is Jun 14, 2020
79f4fb6
Extend standard default initialization syntax to `Option`s with `tran…
MPLew-is Jun 14, 2020
83cd53f
Actually replace previous `init` with private version
MPLew-is Jun 16, 2020
28d7179
Clean up usage of default parameter values
MPLew-is Jun 16, 2020
a8e2a7d
Clean up documentation
MPLew-is Jun 16, 2020
5c7dba0
Extend standard default initialization to `Argument`s
MPLew-is Jun 16, 2020
f3a6b00
Extend standard default initialization to `Flag`s
MPLew-is Jun 16, 2020
83a70e4
Default flags with inversions to nil/required
MPLew-is Jun 19, 2020
e7397e9
Extend standard default initialization to no-inversion boolean `Flags`
MPLew-is Jun 21, 2020
a371be6
Eliminate deprecation spam from default value initialization
MPLew-is Jun 21, 2020
d41e4f2
Add source compatibility tests for new default syntax and associated …
MPLew-is Jun 21, 2020
e05678f
Update top-level documentation
MPLew-is Jun 21, 2020
8c573a5
Merge branch 'master' into default-property-initialization
MPLew-is Jun 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions Documentation/02 Arguments, Options, and Flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ The three preceding examples could be calls of this `Example` command:
```swift
struct Example: ParsableCommand {
@Argument() var files: [String]

@Option() var count: Int?
@Option(default: 0) var index: Int

@Option var index: Int = 0

@Flag() var verbose: Bool

@Flag() var stripWhitespace: Bool
}
```
Expand All @@ -51,7 +51,7 @@ Users must provide values for all properties with no implicit or specified defau
struct Example: ParsableCommand {
@Option()
var userName: String

@Argument()
var value: Int
}
Expand Down Expand Up @@ -105,13 +105,13 @@ You can override this default by specifying one or more name specifications in t
struct Example: ParsableCommand {
@Flag(name: .long) // Same as the default
var stripWhitespace: Bool

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

@Option(name: .customLong("count"))
var iterationCount: Int

@Option(name: [.customShort("I"), .long])
var inputFile: String
}
Expand Down Expand Up @@ -147,7 +147,7 @@ You can make your own custom types conform to `ExpressibleByArgument` by impleme
```swift
struct Path: ExpressibleByArgument {
var pathString: String

init?(argument: String) {
self.pathString = argument
}
Expand All @@ -167,7 +167,7 @@ enum ReleaseMode: String, ExpressibleByArgument {

struct Example: ParsableCommand {
@Option() var mode: ReleaseMode

mutating func run() throws {
print(mode)
}
Expand All @@ -189,7 +189,7 @@ To use a non-`ExpressibleByArgument` type for an argument or option, you can ins
enum Format {
case text
case other(String)

init(_ string: String) throws {
if string == "text" {
self = .text
Expand All @@ -209,23 +209,23 @@ Throw an error from the `transform` function to indicate that the user provided

## Using flag inversions, enumerations, and counts

Flags are most frequently used for `Bool` properties, with a default value of `false`. You can generate a `true`/`false` pair of flags by specifying a flag inversion:
Flags are most frequently used for `Bool` properties. You can generate a `true`/`false` pair of flags by specifying a flag inversion:

```swift
struct Example: ParsableCommand {
@Flag(default: true, inversion: .prefixedNo)
var index: Bool
@Flag(inversion: .prefixedNo)
var index: Bool = true

@Flag(default: nil, inversion: .prefixedEnableDisable)
@Flag(inversion: .prefixedEnableDisable)
var requiredElement: Bool

mutating func run() throws {
print(index, requiredElement)
}
}
```

When providing a flag inversion, you can pass your own default as the `default` parameter. If you want to require that the user specify one of the two inversions, pass `nil` as the `default` parameter.
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.

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 @@ -252,23 +252,23 @@ enum Color: EnumerableFlag {

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

@Flag() var colors: [Color]

mutating func run() throws {
print(cacheMethod)
print(colors)
}
}
```
```

The flag names in this case are drawn from the raw values — for information about customizing the names and help text, see the [`EnumerableFlag` documentation](../Sources/ArgumentParser/Parsable%20Types/EnumerableFlag.swift).

```
% example --in-memory-cache --pink --silver
.inMemoryCache
[.pink, .silver]
% example
% example
Error: Missing one of: '--in-memory-cache', '--persistent-cache'
```

Expand All @@ -278,7 +278,7 @@ Finally, when a flag is of type `Int`, the value is parsed as a count of the num
struct Example: ParsableCommand {
@Flag(name: .shortAndLong)
var verbose: Int

mutating func run() throws {
print("Verbosity level: \(verbose)")
}
Expand All @@ -305,7 +305,7 @@ struct Example: ParsableCommand {
@Flag() var verbose: Bool
@Option() var name: String
@Argument() var file: String?

mutating func run() throws {
print("Verbose: \(verbose), name: \(name), file: \(file ?? "none")")
}
Expand Down Expand Up @@ -351,7 +351,7 @@ The default strategy for parsing options as arrays is to read each value from a
struct Example: ParsableCommand {
@Option() var file: [String]
@Flag() var verbose: Bool

mutating func run() throws {
print("Verbose: \(verbose), files: \(file)")
}
Expand Down Expand Up @@ -402,7 +402,7 @@ The default strategy for parsing arrays of positional arguments is to ignore al
struct Example: ParsableCommand {
@Flag() var verbose: Bool
@Argument() var files: [String]

mutating func run() throws {
print("Verbose: \(verbose), files: \(files)")
}
Expand Down
28 changes: 14 additions & 14 deletions Documentation/03 Commands and Subcommands.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,25 @@ It's time to define our first two subcommands: `Add` and `Multiply`. Both of the
```swift
extension Math {
struct Add: ParsableCommand {
static var configuration
static var configuration
= CommandConfiguration(abstract: "Print the sum of the values.")

@OptionGroup()
var options: Math.Options

mutating func run() {
let result = options.values.reduce(0, +)
print(format(result: result, usingHex: options.hexadecimalOutput))
}
}

struct Multiply: ParsableCommand {
static var configuration
static var configuration
= CommandConfiguration(abstract: "Print the product of the values.")

@OptionGroup()
var options: Math.Options

mutating func run() {
let result = options.values.reduce(1, *)
print(format(result: result, usingHex: options.hexadecimalOutput))
Expand All @@ -98,7 +98,7 @@ extension Math {
Next, we'll define `Statistics`, the third subcommand of `Math`. The `Statistics` command specifies a custom command name (`stats`) in its configuration, overriding the default derived from the type name (`statistics`). It also declares two additional subcommands, meaning that it acts as a forked branch in the command tree, and not a leaf.

```swift
extension Math {
extension Math {
struct Statistics: ParsableCommand {
static var configuration = CommandConfiguration(
commandName: "stats",
Expand All @@ -115,21 +115,21 @@ extension Math.Statistics {
struct Average: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Print the average of the values.")

enum Kind: String, ExpressibleByArgument {
case mean, median, mode
}

@Option(default: .mean, help: "The kind of average to provide.")
var kind: Kind
@Option(help: "The kind of average to provide.")
var kind: Kind = .mean

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

func calculateMean() -> Double { ... }
func calculateMedian() -> Double { ... }
func calculateMode() -> [Double] { ... }

mutating func run() {
switch kind {
case .mean:
Expand All @@ -144,15 +144,15 @@ extension Math.Statistics {
}
}
}

struct StandardDeviation: ParsableCommand {
static var configuration = CommandConfiguration(
commandName: "stdev",
abstract: "Print the standard deviation of the values.")

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

mutating func run() {
if values.isEmpty {
print(0.0)
Expand Down
40 changes: 20 additions & 20 deletions Documentation/04 Customizing Help.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

Support your users (and yourself) by providing rich help for arguments and commands.

You can provide help text when declaring any `@Argument`, `@Option`, or `@Flag` by passing a string literal as the `help` parameter:
You can provide help text when declaring any `@Argument`, `@Option`, or `@Flag` by passing a string literal as the `help` parameter:

```swift
struct Example: ParsableCommand {
@Flag(help: "Display extra information while processing.")
var verbose: Bool
@Option(default: 0, help: "The number of extra lines to show.")
var extraLines: Int

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

@Argument(help: "The input file.")
var inputFile: String?
}
Expand All @@ -24,10 +24,10 @@ Users see these strings in the automatically-generated help screen, which is tri
USAGE: example [--verbose] [--extra-lines <extra-lines>] <input-file>

ARGUMENTS:
<input-file> The input file.
<input-file> The input file.

OPTIONS:
--verbose Display extra information while processing.
--verbose Display extra information while processing.
--extra-lines <extra-lines>
The number of extra lines to show. (default: 0)
-h, --help Show help information.
Expand All @@ -43,12 +43,12 @@ Here's the same command with some extra customization:
struct Example: ParsableCommand {
@Flag(help: "Display extra information while processing.")
var verbose: Bool
@Option(default: 0, help: ArgumentHelp(

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

@Argument(help: ArgumentHelp(
"The input file.",
discussion: "If no input file is provided, the tool reads from stdin.",
Expand All @@ -63,11 +63,11 @@ struct Example: ParsableCommand {
USAGE: example [--verbose] [--extra-lines <n>] [<file>]

ARGUMENTS:
<file> The input file.
<file> The input file.
If no input file is provided, the tool reads from stdin.

OPTIONS:
--verbose Display extra information while processing.
--verbose Display extra information while processing.
--extra-lines <n> The number of extra lines to show. (default: 0)
-h, --help Show help information.
```
Expand All @@ -83,10 +83,10 @@ struct Repeat: ParsableCommand {
discussion: """
Prints to stdout forever, or until you halt the program.
""")

@Argument(help: "The phrase to repeat.")
var phrase: String

mutating func run() throws {
while true { print(phrase) }
}
Expand All @@ -104,7 +104,7 @@ Prints to stdout forever, or until you halt the program.
USAGE: repeat <phrase>

ARGUMENTS:
<phrase> The phrase to repeat.
<phrase> The phrase to repeat.

OPTIONS:
-h, --help Show help information.
Expand All @@ -127,10 +127,10 @@ Users can see the help screen for a command by passing either the `-h` or the `-
struct Example: ParsableCommand {
static let configuration = CommandConfiguration(
helpNames: [.long, .customShort("?")])

@Option(name: .shortAndLong, help: "The number of history entries to show.")
var historyDepth: Int

mutating func run() throws {
printHistory(depth: historyDepth)
}
Expand All @@ -146,7 +146,7 @@ When running the command, `-h` matches the short name of the `historyDepth` prop
USAGE: example --history-depth <history-depth>

ARGUMENTS:
<phrase> The phrase to repeat.
<phrase> The phrase to repeat.

OPTIONS:
-h, --history-depth The number of history entries to show.
Expand All @@ -155,7 +155,7 @@ OPTIONS:

## Hiding Arguments and Commands

You may want to suppress features under development or experimental flags from the generated help screen. You can hide an argument or a subcommand by passing `shouldDisplay: false` to the property wrapper or `CommandConfiguration` initializers, respectively.
You may want to suppress features under development or experimental flags from the generated help screen. You can hide an argument or a subcommand by passing `shouldDisplay: false` to the property wrapper or `CommandConfiguration` initializers, respectively.

`ArgumentHelp` includes a `.hidden` static property that makes it even simpler to hide arguments:

Expand Down
Loading