Skip to content
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

Provides initial initializer parameter for input property wrappers #557

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions Sources/ArgumentParser/Parsable Properties/Argument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,11 @@ extension Argument where Value: ExpressibleByArgument {
/// - Parameters:
/// - help: Information about how to use this argument.
/// - completion: Kind of completion provided to the user for this option.
/// - initial: An `Optional` initial value.
public init(
help: ArgumentHelp? = nil,
completion: CompletionKind? = nil
completion: CompletionKind? = nil,
initial: Value? = nil
) {
self.init(_parsedValue: .init { key in
let arg = ArgumentDefinition(
Expand All @@ -346,7 +348,7 @@ extension Argument where Value: ExpressibleByArgument {
kind: .positional,
help: help,
parsingStrategy: .default,
initial: nil,
initial: initial,
completion: completion)

return ArgumentSet(arg)
Expand Down Expand Up @@ -407,10 +409,12 @@ extension Argument {
/// - completion: Kind of completion provided to the user for this option.
/// - transform: A closure that converts a string into this property's
/// element type or throws an error.
/// - initial: An `Optional` initial value.
public init(
help: ArgumentHelp? = nil,
completion: CompletionKind? = nil,
transform: @escaping (String) throws -> Value
transform: @escaping (String) throws -> Value,
initial: Value? = nil
) {
self.init(_parsedValue: .init { key in
let arg = ArgumentDefinition(
Expand All @@ -420,7 +424,7 @@ extension Argument {
help: help,
parsingStrategy: .default,
transform: transform,
initial: nil,
initial: initial,
completion: completion)

return ArgumentSet(arg)
Expand Down
25 changes: 17 additions & 8 deletions Sources/ArgumentParser/Parsable Properties/Option.swift
Original file line number Diff line number Diff line change
Expand Up @@ -299,11 +299,13 @@ extension Option where Value: ExpressibleByArgument {
/// - parsingStrategy: The behavior to use when looking for this option's value.
/// - help: Information about how to use this option.
/// - completion: Kind of completion provided to the user for this option.
/// - initial: An `Optional` initial value.
public init(
name: NameSpecification = .long,
parsing parsingStrategy: SingleValueParsingStrategy = .next,
help: ArgumentHelp? = nil,
completion: CompletionKind? = nil
completion: CompletionKind? = nil,
initial: Value? = nil
) {
self.init(_parsedValue: .init { key in
let arg = ArgumentDefinition(
Expand All @@ -312,7 +314,7 @@ extension Option where Value: ExpressibleByArgument {
kind: .name(key: key, specification: name),
help: help,
parsingStrategy: parsingStrategy.base,
initial: nil,
initial: initial,
completion: completion)

return ArgumentSet(arg)
Expand Down Expand Up @@ -373,12 +375,15 @@ extension Option {
/// - parsingStrategy: The behavior to use when looking for this option's value.
/// - help: Information about how to use this option.
/// - completion: Kind of completion provided to the user for this option.
/// - transform: A closure that converts a string into this property's type
/// - initial: An `Optional` initial value.
public init(
name: NameSpecification = .long,
parsing parsingStrategy: SingleValueParsingStrategy = .next,
help: ArgumentHelp? = nil,
completion: CompletionKind? = nil,
transform: @escaping (String) throws -> Value
transform: @escaping (String) throws -> Value,
initial: Value? = nil
) {
self.init(_parsedValue: .init { key in
let arg = ArgumentDefinition(
Expand All @@ -388,7 +393,7 @@ extension Option {
help: help,
parsingStrategy: parsingStrategy.base,
transform: transform,
initial: nil,
initial: initial,
completion: completion)

return ArgumentSet(arg)
Expand Down Expand Up @@ -466,11 +471,13 @@ extension Option {
/// value.
/// - help: Information about how to use this option.
/// - completion: Kind of completion provided to the user for this option.
/// - initial: An `Optional` initial value.
public init<T>(
name: NameSpecification = .long,
parsing parsingStrategy: SingleValueParsingStrategy = .next,
help: ArgumentHelp? = nil,
completion: CompletionKind? = nil
completion: CompletionKind? = nil,
initial: T? = nil
) where T: ExpressibleByArgument, Value == Optional<T> {
self.init(_parsedValue: .init { key in
let arg = ArgumentDefinition(
Expand All @@ -479,7 +486,7 @@ extension Option {
kind: .name(key: key, specification: name),
help: help,
parsingStrategy: parsingStrategy.base,
initial: nil,
initial: initial,
completion: completion)

return ArgumentSet(arg)
Expand Down Expand Up @@ -507,13 +514,15 @@ extension Option {
/// - completion: Kind of completion provided to the user for this option.
/// - transform: A closure that converts a string into this property's type
/// or throws an error.
/// - initial: An `Optional` initial value.
public init<T>(
wrappedValue _value: _OptionalNilComparisonType,
name: NameSpecification = .long,
parsing parsingStrategy: SingleValueParsingStrategy = .next,
help: ArgumentHelp? = nil,
completion: CompletionKind? = nil,
transform: @escaping (String) throws -> T
transform: @escaping (String) throws -> T,
initial: T? = nil
) where Value == Optional<T> {
self.init(_parsedValue: .init { key in
let arg = ArgumentDefinition(
Expand All @@ -523,7 +532,7 @@ extension Option {
help: help,
parsingStrategy: parsingStrategy.base,
transform: transform,
initial: nil,
initial: initial,
completion: completion)

return ArgumentSet(arg)
Expand Down
100 changes: 96 additions & 4 deletions Tests/ArgumentParserEndToEndTests/DefaultsEndToEndTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,27 @@ fileprivate struct OptionPropertyInitArguments_Default: ParsableArguments {
var transformedData: String = "test"
}

fileprivate struct OptionPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
fileprivate struct RequiredOptionPropertyInitArguments_Initial: ParsableArguments {
@Option(initial: "test")
var data: String
}

fileprivate struct OptionalOptionPropertyInitArguments_Initial: ParsableArguments {
@Option(initial: "test")
var data: String?
}

fileprivate struct RequiredOptionPropertyInitArguments_Transform_Initial: ParsableArguments {
@Option(transform: exclaim, initial: "test")
var data: String
}

fileprivate struct OptionalOptionPropertyInitArguments_Transform_Initial: ParsableArguments {
@Option(transform: exclaim, initial: "test")
var data: String?
}

fileprivate struct RequiredOptionPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
@Option()
var data: String
}
Expand All @@ -412,12 +432,57 @@ extension DefaultsEndToEndTests {

/// Tests that *not* providing a default value still parses the argument correctly from the command-line.
/// This test is almost certainly duplicated by others in the repository, but allows for quick use of test filtering during development on the initialization functionality.
func testParsing_OptionPropertyInit_NoDefault_NoTransform() throws {
AssertParse(OptionPropertyInitArguments_NoDefault_NoTransform.self, ["--data", "test"]) { arguments in
func testParsing_RequiredOptionPropertyInit_NoDefault_NoTransform() throws {
AssertParse(RequiredOptionPropertyInitArguments_NoDefault_NoTransform.self, ["--data", "test"]) { arguments in
XCTAssertEqual(arguments.data, "test")
}
}

func testParsing_RequiredOptionPropertyInit_NoDefault_NoTransform_NoInput_Fails() throws {
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_NoDefault_NoTransform.parse([]))
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_NoDefault_NoTransform.parse(["--data"]))
}

func testParsing_RequiredOptionPropertyInitArguments_Initial_UsesInitialValue() {
AssertParse(RequiredOptionPropertyInitArguments_Initial.self, []) { arguments in
XCTAssertEqual(arguments.data, "test")
}
}

func testParsing_RequiredOptionPropertyInitArguments_Initial_IncompleteInput_Fails() throws {
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_Initial.parse(["--data"]))
}

func testParsing_OptionalOptionPropertyInitArguments_Initial_UsesInitialValue() {
AssertParse(OptionalOptionPropertyInitArguments_Initial.self, []) { arguments in
XCTAssertEqual(arguments.data, "test")
}
}

func testParsing_OptionalOptionPropertyInitArguments_Initial_IncompleteInput_Fails() throws {
XCTAssertThrowsError(try OptionalOptionPropertyInitArguments_Initial.parse(["--data"]))
}

func testParsing_RequiredOptionPropertyInitArguments_Transform_Initial_UsesInitialValue() {
AssertParse(RequiredOptionPropertyInitArguments_Transform_Initial.self, []) { arguments in
XCTAssertEqual(arguments.data, "test")
}
}

func testParsing_RequiredOptionPropertyInitArguments_Transform_Initial_IncompleteInput_Fails() throws {
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_Transform_Initial.parse(["--data"]))
}

func testParsing_OptionalOptionPropertyInitArguments_Transform_Initial_UsesInitialValue() {
AssertParse(OptionalOptionPropertyInitArguments_Transform_Initial.self, []) { arguments in
XCTAssertEqual(arguments.data, "test")
}
}

func testParsing_OptionalOptionPropertyInitArguments_Transform_Initial_IncompleteInput_Fails() throws {
XCTAssertThrowsError(try OptionalOptionPropertyInitArguments_Transform_Initial.parse(["--data"]))
}

/// Tests that using default property initialization syntax on a property with a `transform` function provided parses the default value for the argument when nothing is provided from the command-line.
func testParsing_OptionPropertyInit_Default_Transform_UseDefault() throws {
AssertParse(OptionPropertyInitArguments_Default.self, []) { arguments in
Expand All @@ -439,6 +504,11 @@ extension DefaultsEndToEndTests {
XCTAssertEqual(arguments.transformedData, "test!")
}
}

func testParsing_OptionPropertyInit_NoDefault_Transform_NoInput_Fails() throws {
XCTAssertThrowsError(try OptionPropertyInitArguments_NoDefault_Transform.parse([]))
XCTAssertThrowsError(try OptionPropertyInitArguments_NoDefault_Transform.parse(["--transformed-data"]))
}
}


Expand All @@ -447,14 +517,24 @@ fileprivate struct ArgumentPropertyInitArguments_Default_NoTransform: ParsableAr
var data: String = "test"
}

fileprivate struct ArgumentPropertyInitArguments_Initial_NoTransform: ParsableArguments {
@Argument(initial: "test")
var data: String
}

fileprivate struct ArgumentPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
@Argument()
var data: String
}

fileprivate struct ArgumentPropertyInitArguments_Default_Transform: ParsableArguments {
@Argument(transform: exclaim)
var transformedData: String = "test"
var transformedData: String = "test"
}

fileprivate struct ArgumentPropertyInitArguments_Transform_Initial: ParsableArguments {
@Argument(transform: exclaim, initial: "test")
var transformedData: String
}

fileprivate struct ArgumentPropertyInitArguments_NoDefault_Transform: ParsableArguments {
Expand All @@ -470,6 +550,12 @@ extension DefaultsEndToEndTests {
}
}

func testParsing_ArgumentPropertyInit_Initial_NoTransform_UseDefault() throws {
AssertParse(ArgumentPropertyInitArguments_Initial_NoTransform.self, []) { arguments in
XCTAssertEqual(arguments.data, "test")
}
}

/// Tests that using default property initialization syntax parses the command-line-provided value for the argument when provided.
func testParsing_ArgumentPropertyInit_Default_NoTransform_OverrideDefault() throws {
AssertParse(ArgumentPropertyInitArguments_Default_NoTransform.self, ["test2"]) { arguments in
Expand All @@ -492,6 +578,12 @@ extension DefaultsEndToEndTests {
}
}

func testParsing_ArgumentPropertyInit_Transform_Initial_UseDefault() throws {
AssertParse(ArgumentPropertyInitArguments_Transform_Initial.self, []) { arguments in
XCTAssertEqual(arguments.transformedData, "test")
}
}

/// Tests that using default property initialization syntax on a property with a `transform` function provided parses and transforms the command-line-provided value for the argument when provided.
func testParsing_ArgumentPropertyInit_Default_Transform_OverrideDefault() throws {
AssertParse(ArgumentPropertyInitArguments_Default_Transform.self, ["test2"]) { arguments in
Expand Down