Skip to content

Commit

Permalink
Fix help display for non-String RawRepresentables (#494)
Browse files Browse the repository at this point in the history
RawRepresentable types that have a non-String raw value are having
values displayed in the help screen by converting the RawRep value
into a string. However, these values are by default parsed by their
raw value, so we should use that for display instead.

This is accomplished by adding a defaultValueDescription
implementation for all ExpressibleByArgument-conforming RawValue
types, and then basing the allValues implementation on that.
This generalizes the existing overloads for String-based RawRep types,
while also allowing users who customize their ExpressibleByArgument
implementation to provide the correct help value for clients.
  • Loading branch information
natecook1000 committed Sep 20, 2022
1 parent 841b853 commit 774de9c
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 6 deletions.
Expand Up @@ -54,15 +54,15 @@ extension ExpressibleByArgument where Self: CaseIterable {
}
}

extension ExpressibleByArgument where Self: CaseIterable, Self: RawRepresentable, RawValue == String {
extension ExpressibleByArgument where Self: CaseIterable, Self: RawRepresentable, RawValue: ExpressibleByArgument {
public static var allValueStrings: [String] {
self.allCases.map { $0.rawValue }
self.allCases.map(\.rawValue.defaultValueDescription)
}
}

extension ExpressibleByArgument where Self: RawRepresentable, RawValue == String {
extension ExpressibleByArgument where Self: RawRepresentable, RawValue: ExpressibleByArgument {
public var defaultValueDescription: String {
rawValue
rawValue.defaultValueDescription
}
}

Expand Down
14 changes: 14 additions & 0 deletions Tests/ArgumentParserUnitTests/ErrorMessageTests.swift
Expand Up @@ -80,6 +80,11 @@ fileprivate enum Name: String, Equatable, Decodable, ExpressibleByArgument, Case
case tony
}

fileprivate enum Counter: Int, ExpressibleByArgument, CaseIterable {
case one = 1
case two, three, four
}

fileprivate struct Foo: ParsableArguments {
@Option(name: [.short, .long])
var format: Format
Expand All @@ -97,6 +102,10 @@ fileprivate struct EnumWithManyCasesArrayArgument: ParsableArguments {
var names: [Name]
}

fileprivate struct EnumWithIntRawValue: ParsableArguments {
@Option var counter: Counter
}

extension ErrorMessageTests {
func testWrongEnumValue() {
AssertErrorMessage(Foo.self, ["--format", "png"], "The value 'png' is invalid for '--format <format>'. Please provide one of 'text', 'json' or 'csv'.")
Expand Down Expand Up @@ -135,6 +144,11 @@ extension ErrorMessageTests {
- thor
- tony
""")

AssertErrorMessage(EnumWithIntRawValue.self, ["--counter", "one"], """
The value 'one' is invalid for '--counter <counter>'. \
Please provide one of '1', '2', '3' or '4'.
""")
}
}

Expand Down
4 changes: 2 additions & 2 deletions Tests/ArgumentParserUnitTests/HelpGenerationTests.swift
Expand Up @@ -211,7 +211,7 @@ extension HelpGenerationTests {
--degree <degree> Your degree.
--directory <directory> Directory. (default: current directory)
--manual <manual> Manual Option. (default: default-value)
--unspecial <unspecial> Unspecialized Synthesized (default: one)
--unspecial <unspecial> Unspecialized Synthesized (default: 0)
--special <special> Specialized Synthesized (default: Apple)
-h, --help Show help information.
Expand Down Expand Up @@ -633,7 +633,7 @@ extension HelpGenerationTests {

func testAllValueStrings() throws {
XCTAssertEqual(AllValues.Manual.allValueStrings, ["bar"])
XCTAssertEqual(AllValues.UnspecializedSynthesized.allValueStrings, ["one", "two"])
XCTAssertEqual(AllValues.UnspecializedSynthesized.allValueStrings, ["0", "1"])
XCTAssertEqual(AllValues.SpecializedSynthesized.allValueStrings, ["Apple", "Banana"])
}

Expand Down

0 comments on commit 774de9c

Please sign in to comment.