🔥 사용 가능한 값 열거하기

338자
4분

특정 인자나 옵션이 가질 수 있는 값이 고정된 경우, 도움말 화면에 이러한 값을 나열하면 도구 사용이 간단해집니다. 사용자 정의 ExpressibleByArgument 타입에 대해 표시되는 값 집합을 allValueStrings을 구현하여 사용자 정의할 수 있습니다. 이름과 달리 allValueStrings은 가능한 모든 값을 나열할 필요가 없습니다.

swift
enum Fruit: String, ExpressibleByArgument {
    case apple
    case banana
    case coconut
    case dragonFruit = "dragon-fruit"
 
    static var allValueStrings: [String] {
        ["apple", "banana", "coconut", "dragon-fruit"]
    }
}
 
struct FruitStore: ParsableCommand {
    @Argument(help: "The fruit to purchase")
    var fruit: Fruit
 
    @Option(help: "The number of fruit to purchase")
    var quantity: Int = 1
}
 
swift
enum Fruit: String, ExpressibleByArgument {
    case apple
    case banana
    case coconut
    case dragonFruit = "dragon-fruit"
 
    static var allValueStrings: [String] {
        ["apple", "banana", "coconut", "dragon-fruit"]
    }
}
 
struct FruitStore: ParsableCommand {
    @Argument(help: "The fruit to purchase")
    var fruit: Fruit
 
    @Option(help: "The number of fruit to purchase")
    var quantity: Int = 1
}
 

도움말 화면에는 <fruit> 인자에 대한 설명에 값 목록이 포함됩니다:

text
USAGE: fruit-store <fruit> [--quantity <quantity>]

ARGUMENTS:
  <fruit>                 The fruit to purchase (values: apple, banana,
                          coconut, dragon-fruit)

OPTIONS:
  --quantity <quantity>   The number of fruit to purchase (default: 1)
  -h, --help              Show help information.
text
USAGE: fruit-store <fruit> [--quantity <quantity>]

ARGUMENTS:
  <fruit>                 The fruit to purchase (values: apple, banana,
                          coconut, dragon-fruit)

OPTIONS:
  --quantity <quantity>   The number of fruit to purchase (default: 1)
  -h, --help              Show help information.

가능한 값 추론하기

CaseIterable을 준수하는 ExpressibleByArgument 타입은 allValueStrings을 수동으로 지정할 필요가 없습니다. 대신 다음 예제와 같이 타입의 case에서 가능한 값 목록이 추론됩니다:

swift
enum Fruit: String, CaseIterable, ExpressibleByArgument {
    case apple
    case banana
    case coconut
    case dragonFruit = "dragon-fruit"
}
 
struct FruitStore: ParsableCommand {
    @Argument(help: "The fruit to purchase")
    var fruit: Fruit
 
    @Option(help: "The number of fruit to purchase")
    var quantity: Int = 1
}
 
swift
enum Fruit: String, CaseIterable, ExpressibleByArgument {
    case apple
    case banana
    case coconut
    case dragonFruit = "dragon-fruit"
}
 
struct FruitStore: ParsableCommand {
    @Argument(help: "The fruit to purchase")
    var fruit: Fruit
 
    @Option(help: "The number of fruit to purchase")
    var quantity: Int = 1
}
 

도움말 화면에는 여전히 가능한 모든 값이 포함됩니다.

text
USAGE: fruit-store <fruit> [--quantity <quantity>]

ARGUMENTS:
  <fruit>                 The fruit to purchase (values: apple, banana,
                          coconut, dragon-fruit)

OPTIONS:
  --quantity <quantity>   The number of fruit to purchase (default: 1)
  -h, --help              Show help information.
text
USAGE: fruit-store <fruit> [--quantity <quantity>]

ARGUMENTS:
  <fruit>                 The fruit to purchase (values: apple, banana,
                          coconut, dragon-fruit)

OPTIONS:
  --quantity <quantity>   The number of fruit to purchase (default: 1)
  -h, --help              Show help information.

많은 case를 가진 ExpressibleByArgument이면서 CaseIterable 타입의 경우, 도움말 화면에 지나치게 긴 값 목록이 나타나는 것을 피하기 위해 여전히 allValueStrings을 구현할 수 있습니다. 이러한 타입의 경우 가장 일반적인 가능한 값을 포함하는 것이 좋습니다.

가능한 값을 열거하는 것은 명령줄 도구의 사용성을 크게 향상시켜 줍니다. 사용자가 어떤 값을 제공해야 하는지 명확히 알 수 있고, 잘못된 값을 입력할 가능성도 줄어들죠. 특히 값의 개수가 제한적인 경우 더욱 유용합니다.

하지만 가능한 모든 값을 나열하는 것이 항상 좋은 것은 아닙니다. 값이 너무 많으면 오히려 도움말이 복잡해 보일 수 있거든요. 이런 경우에는 대표적인 몇 가지 값만 제시하는 것도 좋은 방법이에요.

YouTube 영상

채널 보기
곱, 프로덕트 | 프로그래머를 위한 카테고리 이론
동적 모듈 이해하기 | NestJS 가이드
합타입 + 곱타입 = 강력한 타입 시스템? 대수적 데이터 타입의 비밀 | 프로그래머를 위한 카테고리 이론
쌍대성과 비대칭성 | 프로그래머를 위한 카테고리 이론
피처 모듈은 무엇이고 왜 필요할까? | NestJS 가이드
합타입 - Either, Maybe, List | 프로그래머를 위한 카테고리 이론
NestJS 미들웨어 기초 - 클래스 기반 미들웨어와 DI | NestJS 가이드
쌍대곱, 코프로덕트 | 프로그래머를 위한 카테고리 이론