Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ extension Math.Statistics {
abstract: "Print the average of the values.",
aliases: ["avg"])

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

Expand Down
4 changes: 2 additions & 2 deletions Sources/ArgumentParser/Usage/HelpGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ internal struct HelpGenerator {
} else {
var usage = UsageGenerator(toolName: toolName, definition: [currentArgSet])
.synopsis
if !currentCommand.configuration.subcommands.isEmpty {
if !currentCommand.configuration.subcommands.isEmpty {
if usage.last != " " { usage += " " }
usage += "<subcommand>"
usage += "<subcommand>"
}
self.usage = usage
}
Expand Down
7 changes: 6 additions & 1 deletion Sources/ArgumentParser/Usage/UsageGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,12 @@ extension ArgumentDefinition {

switch update {
case .unary:
return "\(name.synopsisString) <\(valueName)>"
let joinedValues = help.allValueStrings.joined(separator: "|")
if help.allValueStrings.count > 1 && joinedValues.count <= 40 {
return "\(name.synopsisString) <\(joinedValues)>"
} else {
return "\(name.synopsisString) <\(valueName)>"
}
case .nullary:
return name.synopsisString
}
Expand Down
26 changes: 24 additions & 2 deletions Tests/ArgumentParserExampleTests/MathExampleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,33 @@ final class MathExampleTests: XCTestCase {
try AssertExecuteCommand(command: "math help add --help", expected: helpText)
}

func testMath_StatsHelp() throws {
let helpText = """
OVERVIEW: Calculate descriptive statistics.

USAGE: math stats <subcommand>

OPTIONS:
--version Show the version.
-h, --help Show help information.

SUBCOMMANDS:
average, avg Print the average of the values.
stdev Print the standard deviation of the values.
quantiles Print the quantiles of the values (TBD).

See 'math help stats <subcommand>' for detailed help.
"""
try AssertExecuteCommand(command: "math stats -h", expected: helpText)
try AssertExecuteCommand(command: "math stats --help", expected: helpText)
try AssertExecuteCommand(command: "math help stats", expected: helpText)
}

func testMath_StatsMeanHelp() throws {
let helpText = """
OVERVIEW: Print the average of the values.

USAGE: math stats average [--kind <kind>] [<values> ...]
USAGE: math stats average [--kind <mean|median|mode>] [<values> ...]

ARGUMENTS:
<values> A group of floating-point values to operate on.
Expand Down Expand Up @@ -128,7 +150,7 @@ final class MathExampleTests: XCTestCase {
command: "math stats average --kind mode",
expected: """
Error: Please provide at least one value to calculate the mode.
Usage: math stats average [--kind <kind>] [<values> ...]
Usage: math stats average [--kind <mean|median|mode>] [<values> ...]
See 'math stats average --help' for more information.
""",
exitCode: .validationFailure)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift Argument Parser open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import XCTest
import ArgumentParserTestHelpers
@testable import ArgumentParser

extension HelpGenerationTests {
enum Fruit: String, ExpressibleByArgument, CaseIterable {
case apple, banana, coconut, dragonFruit = "dragon-fruit", elderberry, fig, grape, honeydew
}

enum Action: String, ExpressibleByArgument, CaseIterable {
case purchase, sample, refund = "return"
}

enum Count: Int, ExpressibleByArgument, CaseIterable {
case zero, one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty
}

enum Ripeness: String, ExpressibleByArgument, CaseIterable {
case under, perfect, over
}

struct FruitStore: ParsableArguments {
@Argument(help: "The transaction type")
var action: Action = .purchase

@Argument(help: "The fruit to purchase")
var fruit: Fruit

@Option(help: "The number of fruit to purchase")
var quantity: Count = .one

@Option(help: "The desired ripeness of fruit")
var ripeness: Ripeness = .perfect
}

func testFruitStoreHelp() {
AssertHelp(.default, for: FruitStore.self, equals: """
USAGE: fruit_store [<action>] <fruit> [--quantity <quantity>] [--ripeness <under|perfect|over>]

ARGUMENTS:
<action> The transaction type (values: purchase, sample,
return; default: purchase)
<fruit> The fruit to purchase (values: apple, banana,
coconut, dragon-fruit, elderberry, fig, grape,
honeydew)

OPTIONS:
--quantity <quantity> The number of fruit to purchase (values: 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20; default: 1)
--ripeness <ripeness> The desired ripeness of fruit (values: under,
perfect, over; default: perfect)
-h, --help Show help information.

""")
}
}
2 changes: 1 addition & 1 deletion Tests/ArgumentParserUnitTests/HelpGenerationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ extension HelpGenerationTests {

func testHelpWithDefaultValues() {
AssertHelp(.default, for: D.self, equals: """
USAGE: d [<occupation>] [--name <name>] [--age <age>] [--logging <logging>] [--lucky <numbers> ...] [--optional] [--required] [--degree <degree>] [--directory <directory>] [--manual <manual>] [--unspecial <unspecial>] [--special <special>]
USAGE: d [<occupation>] [--name <name>] [--age <age>] [--logging <logging>] [--lucky <numbers> ...] [--optional] [--required] [--degree <degree>] [--directory <directory>] [--manual <manual>] [--unspecial <0|1>] [--special <Apple|Banana>]

ARGUMENTS:
<occupation> Your occupation. (default: --)
Expand Down