Skip to content

Commit ff43a17

Browse files
committed
Provides initial initializer parameter for Argument and Option property wrappers
This allows using `Optional` initial values in addition to non-`Optional`, e.g. environment variables.
1 parent c5050aa commit ff43a17

File tree

3 files changed

+83
-12
lines changed

3 files changed

+83
-12
lines changed

Sources/ArgumentParser/Parsable Properties/Argument.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,11 @@ extension Argument where Value: ExpressibleByArgument {
335335
/// - Parameters:
336336
/// - help: Information about how to use this argument.
337337
/// - completion: Kind of completion provided to the user for this option.
338+
/// - initial: An `Optional` initial value.
338339
public init(
339340
help: ArgumentHelp? = nil,
340-
completion: CompletionKind? = nil
341+
completion: CompletionKind? = nil,
342+
initial: Value? = nil
341343
) {
342344
self.init(_parsedValue: .init { key in
343345
let arg = ArgumentDefinition(
@@ -346,7 +348,7 @@ extension Argument where Value: ExpressibleByArgument {
346348
kind: .positional,
347349
help: help,
348350
parsingStrategy: .default,
349-
initial: nil,
351+
initial: initial,
350352
completion: completion)
351353

352354
return ArgumentSet(arg)
@@ -407,10 +409,12 @@ extension Argument {
407409
/// - completion: Kind of completion provided to the user for this option.
408410
/// - transform: A closure that converts a string into this property's
409411
/// element type or throws an error.
412+
/// - initial: An `Optional` initial value.
410413
public init(
411414
help: ArgumentHelp? = nil,
412415
completion: CompletionKind? = nil,
413-
transform: @escaping (String) throws -> Value
416+
transform: @escaping (String) throws -> Value,
417+
initial: Value? = nil
414418
) {
415419
self.init(_parsedValue: .init { key in
416420
let arg = ArgumentDefinition(
@@ -420,7 +424,7 @@ extension Argument {
420424
help: help,
421425
parsingStrategy: .default,
422426
transform: transform,
423-
initial: nil,
427+
initial: initial,
424428
completion: completion)
425429

426430
return ArgumentSet(arg)

Sources/ArgumentParser/Parsable Properties/Option.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,13 @@ extension Option where Value: ExpressibleByArgument {
299299
/// - parsingStrategy: The behavior to use when looking for this option's value.
300300
/// - help: Information about how to use this option.
301301
/// - completion: Kind of completion provided to the user for this option.
302+
/// - initial: An `Optional` initial value.
302303
public init(
303304
name: NameSpecification = .long,
304305
parsing parsingStrategy: SingleValueParsingStrategy = .next,
305306
help: ArgumentHelp? = nil,
306-
completion: CompletionKind? = nil
307+
completion: CompletionKind? = nil,
308+
initial: Value? = nil
307309
) {
308310
self.init(_parsedValue: .init { key in
309311
let arg = ArgumentDefinition(
@@ -312,7 +314,7 @@ extension Option where Value: ExpressibleByArgument {
312314
kind: .name(key: key, specification: name),
313315
help: help,
314316
parsingStrategy: parsingStrategy.base,
315-
initial: nil,
317+
initial: initial,
316318
completion: completion)
317319

318320
return ArgumentSet(arg)
@@ -373,12 +375,15 @@ extension Option {
373375
/// - parsingStrategy: The behavior to use when looking for this option's value.
374376
/// - help: Information about how to use this option.
375377
/// - completion: Kind of completion provided to the user for this option.
378+
/// - transform: A closure that converts a string into this property's type
379+
/// - initial: An `Optional` initial value.
376380
public init(
377381
name: NameSpecification = .long,
378382
parsing parsingStrategy: SingleValueParsingStrategy = .next,
379383
help: ArgumentHelp? = nil,
380384
completion: CompletionKind? = nil,
381-
transform: @escaping (String) throws -> Value
385+
transform: @escaping (String) throws -> Value,
386+
initial: Value? = nil
382387
) {
383388
self.init(_parsedValue: .init { key in
384389
let arg = ArgumentDefinition(
@@ -388,7 +393,7 @@ extension Option {
388393
help: help,
389394
parsingStrategy: parsingStrategy.base,
390395
transform: transform,
391-
initial: nil,
396+
initial: initial,
392397
completion: completion)
393398

394399
return ArgumentSet(arg)

Tests/ArgumentParserEndToEndTests/DefaultsEndToEndTests.swift

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,17 @@ fileprivate struct OptionPropertyInitArguments_Default: ParsableArguments {
385385
var transformedData: String = "test"
386386
}
387387

388-
fileprivate struct OptionPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
388+
fileprivate struct RequiredOptionPropertyInitArguments_Initial: ParsableArguments {
389+
@Option(initial: "test")
390+
var data: String
391+
}
392+
393+
fileprivate struct RequiredOptionPropertyInitArguments_Transform_Initial: ParsableArguments {
394+
@Option(transform: exclaim, initial: "test")
395+
var data: String
396+
}
397+
398+
fileprivate struct RequiredOptionPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
389399
@Option()
390400
var data: String
391401
}
@@ -412,12 +422,37 @@ extension DefaultsEndToEndTests {
412422

413423
/// Tests that *not* providing a default value still parses the argument correctly from the command-line.
414424
/// 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.
415-
func testParsing_OptionPropertyInit_NoDefault_NoTransform() throws {
416-
AssertParse(OptionPropertyInitArguments_NoDefault_NoTransform.self, ["--data", "test"]) { arguments in
425+
func testParsing_RequiredOptionPropertyInit_NoDefault_NoTransform() throws {
426+
AssertParse(RequiredOptionPropertyInitArguments_NoDefault_NoTransform.self, ["--data", "test"]) { arguments in
417427
XCTAssertEqual(arguments.data, "test")
418428
}
419429
}
420430

431+
func testParsing_RequiredOptionPropertyInit_NoDefault_NoTransform_NoInput_Fails() throws {
432+
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_NoDefault_NoTransform.parse([]))
433+
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_NoDefault_NoTransform.parse(["--data"]))
434+
}
435+
436+
func testParsing_RequiredOptionPropertyInitArguments_Initial_UsesInitialValue() {
437+
AssertParse(RequiredOptionPropertyInitArguments_Initial.self, []) { arguments in
438+
XCTAssertEqual(arguments.data, "test")
439+
}
440+
}
441+
442+
func testParsing_RequiredOptionPropertyInitArguments_Initial_IncompleteInput_Fails() throws {
443+
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_Initial.parse(["--data"]))
444+
}
445+
446+
func testParsing_RequiredOptionPropertyInitArguments_Transform_Initial_UsesInitialValue() {
447+
AssertParse(RequiredOptionPropertyInitArguments_Transform_Initial.self, []) { arguments in
448+
XCTAssertEqual(arguments.data, "test")
449+
}
450+
}
451+
452+
func testParsing_RequiredOptionPropertyInitArguments_Transform_Initial_IncompleteInput_Fails() throws {
453+
XCTAssertThrowsError(try RequiredOptionPropertyInitArguments_Transform_Initial.parse(["--data"]))
454+
}
455+
421456
/// 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.
422457
func testParsing_OptionPropertyInit_Default_Transform_UseDefault() throws {
423458
AssertParse(OptionPropertyInitArguments_Default.self, []) { arguments in
@@ -439,6 +474,11 @@ extension DefaultsEndToEndTests {
439474
XCTAssertEqual(arguments.transformedData, "test!")
440475
}
441476
}
477+
478+
func testParsing_OptionPropertyInit_NoDefault_Transform_NoInput_Fails() throws {
479+
XCTAssertThrowsError(try OptionPropertyInitArguments_NoDefault_Transform.parse([]))
480+
XCTAssertThrowsError(try OptionPropertyInitArguments_NoDefault_Transform.parse(["--transformed-data"]))
481+
}
442482
}
443483

444484

@@ -447,14 +487,24 @@ fileprivate struct ArgumentPropertyInitArguments_Default_NoTransform: ParsableAr
447487
var data: String = "test"
448488
}
449489

490+
fileprivate struct ArgumentPropertyInitArguments_Initial_NoTransform: ParsableArguments {
491+
@Argument(initial: "test")
492+
var data: String
493+
}
494+
450495
fileprivate struct ArgumentPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
451496
@Argument()
452497
var data: String
453498
}
454499

455500
fileprivate struct ArgumentPropertyInitArguments_Default_Transform: ParsableArguments {
456501
@Argument(transform: exclaim)
457-
var transformedData: String = "test"
502+
var transformedData: String = "test"
503+
}
504+
505+
fileprivate struct ArgumentPropertyInitArguments_Transform_Initial: ParsableArguments {
506+
@Argument(transform: exclaim, initial: "test")
507+
var transformedData: String
458508
}
459509

460510
fileprivate struct ArgumentPropertyInitArguments_NoDefault_Transform: ParsableArguments {
@@ -470,6 +520,12 @@ extension DefaultsEndToEndTests {
470520
}
471521
}
472522

523+
func testParsing_ArgumentPropertyInit_Initial_NoTransform_UseDefault() throws {
524+
AssertParse(ArgumentPropertyInitArguments_Initial_NoTransform.self, []) { arguments in
525+
XCTAssertEqual(arguments.data, "test")
526+
}
527+
}
528+
473529
/// Tests that using default property initialization syntax parses the command-line-provided value for the argument when provided.
474530
func testParsing_ArgumentPropertyInit_Default_NoTransform_OverrideDefault() throws {
475531
AssertParse(ArgumentPropertyInitArguments_Default_NoTransform.self, ["test2"]) { arguments in
@@ -492,6 +548,12 @@ extension DefaultsEndToEndTests {
492548
}
493549
}
494550

551+
func testParsing_ArgumentPropertyInit_Transform_Initial_UseDefault() throws {
552+
AssertParse(ArgumentPropertyInitArguments_Transform_Initial.self, []) { arguments in
553+
XCTAssertEqual(arguments.transformedData, "test")
554+
}
555+
}
556+
495557
/// 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.
496558
func testParsing_ArgumentPropertyInit_Default_Transform_OverrideDefault() throws {
497559
AssertParse(ArgumentPropertyInitArguments_Default_Transform.self, ["test2"]) { arguments in

0 commit comments

Comments
 (0)