Swift Digest
Blog | Swift.org Blog

ArgumentParser の発表

Announcing ArgumentParser

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

この記事の要点

何が発表されたのか

ArgumentParser は、Swift でコマンドライン引数を解析するためのオープンソースライブラリです。引数の解析は多くのコマンドラインツールに共通して必要になりますが、従来は手作業で書くことが多く、定型コードや記述ミスの温床になりがちでした。ArgumentParser は、Swift の型システムやプロパティラッパー、リフレクションといった機能を活用し、利用者が宣言した型から自動的にインターフェースを組み立てることで、この手間を取り除きます。

設計にあたっては次の目標が掲げられています。

何に使えるのか

たとえば、1 から指定した値までの乱数を表示する random というツールを考えます。ParsableCommand に適合する型を定義し、引数にしたいプロパティに @Argument を付けるだけで実装できます。

import ArgumentParser

struct Random: ParsableCommand {
    @Argument() var highValue: Int

    func run() {
        print(Int.random(in: 1...highValue))
    }
}

Random.main()
> random 20
17
> random ZZZ
Error: The value 'ZZZ' is invalid for '<high-value>'
Usage: random <high-value>

バリデーションとヘルプのカスタマイズ

CommandConfiguration で説明文を加え、validate() メソッドを実装すると、入力の検証と豊富なドキュメントを備えられます。

struct Random: ParsableCommand {
    static let configuration = CommandConfiguration(
        abstract: "Chooses a random number between 1 and your input.")

    @Argument(help: "The highest value to pick.")
    var highValue: Int

    func validate() throws {
        guard highValue >= 1 else {
            throw ValidationError("'<high-value>' must be at least 1.")
        }
    }

    func run() {
        print(Int.random(in: 1...highValue))
    }
}

これにより、不正な値を弾きつつ、--help で次のような整形済みのヘルプ画面が自動表示されます。

> random --help
OVERVIEW: Chooses a random number between 1 and your input.

USAGE: random <high-value>

ARGUMENTS:
  <high-value>            The highest value to pick.

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

サブコマンド

Git や Swift Package Manager のように、関連する機能をサブコマンドとしてコマンドツリーにまとめることもできます。各サブコマンドを個別の型として宣言し、ルートコマンドの configurationsubcommands に列挙します。

たとえば乱数生成のロジックを Number 型に移し、入力した一覧から要素を選ぶ Pick 型を追加します。@Option プロパティラッパーは、プロパティ名をキーとしてキーと値のペアの形で引数を読み取ることを示します。

struct Random: ParsableCommand {
    static let configuration = CommandConfiguration(
        abstract: "Randomness utilities.",
        subcommands: [Number.self, Pick.self])

    // ...

    struct Pick: ParsableCommand {
        static let configuration = CommandConfiguration(
            abstract: "Picks random elements from your input.")

        @Option(default: 1, help: "The number of elements to choose.")
        var count: Int

        @Argument(help: "The elements to choose from.")
        var elements: [String]

        func validate() throws {
            guard !elements.isEmpty else {
                throw ValidationError("Must provide at least one element.")
            }
        }

        func run() {
            let picks = elements.shuffled().prefix(count)
            print(picks.joined(separator: "\n"))
        }
    }
}

ArgumentParser はユーザーが指定したサブコマンドを自動で判別し、その引数を解析して run() を呼び出します。サブコマンドを省略した場合は、ルートコマンドの既定の run() 実装が呼ばれ、ヘルプ画面が表示されます。

> random number 100
79
> random pick --count 3 Fuji Gala Cameo Honeycrisp McIntosh Braeburn
Honeycrisp
Cameo
Braeburn

このほか、ArgumentParser は真偽値や列挙型のプロパティに対する --flag 形式の引数、オプションやフラグへの複数名の付与、引数グループのカプセル化なども備えています。

今後の位置づけ

Swift プロジェクトには Swift で書かれたコマンドラインツールがいくつもあり、その引数解析は SwiftPM の TSCUtility ライブラリ内のパーサーなどが担ってきました。これは SwiftPM の必要に応じて育ってきたもので、広く使われることを意図したものではありませんでした。今後は ArgumentParser を Swift プロジェクト全体に採用していく計画で、SwiftPM での採用が完了したら、Swift コンパイラドライバの Swift による書き直しでの採用も予定されています。

あわせて、サーバーや Windows など多様な環境での広範な採用に向けて、1.0 リリースに必要な要件をコミュニティとともに定義していくことが目指されています。

関連リンク