clap v3 のdriveベースのパースのサンプル

Rustの定番コマンドラインパーサー clap が2022-01-01にバージョン3になり、deriveベースのコマンドラインのパースが正式実装された。 この機能は、従来は structopt が提供していた構造体を用いたコマンドライン引数の定義や、列挙型を用いたサブコマンドの定義を行う機能である。 この記事では、この derive ベースのパースのうち、よく使うであろうものを紹介する。

なお、すべての機能については clapのGitHub上のリポジトリにあるexamples を参照してほしい。

Cargo.toml での指定

今回のサンプルコードを実行するには、Cargo.tomlに以下の指定が必要である。

[dependencies]

clap = {version = "3.0.7", features = ["derive", "env"]}

コマンドライン引数の定義

まずは、コマンドライン引数の指定のパターンをサンプルコードで示す。

use std::path::PathBuf;

  

use clap::{ArgEnum, Parser};

  

fn main() {

 let args = Args::parse();

 println!("{:#?}", args);

}

  

#[derive(Debug, Parser)]

#[clap(name = "struct", author, about, version)]

struct Args {

 /// boolフラグ。

 ///

 /// `short` を指定すると、 自動で変数名の頭文字を使用する。

 /// `long` を指定すると、 自動で変数名を使用する。

 ///

 /// `help` を指定していないため、 短いヘルプ(`-h`のとき) はこのコメントの冒頭が表示される。

 /// `long_help` を指定していないため、 長いヘルプ(`--help`のとき) はこのコメントの全体が表示される。

 #[clap(short, long)]

 bool_flag: bool,

  

 /// 整数を引数に取る必須フラグ。

 ///

 /// 整数型を直接指定しているため、このフラグは必須である。

 #[clap(short, long)]

 count: u64,

  

 /// 整数を引数に取るフラグ。

 ///

 /// デフォルト値が指定されているため、コマンドラインでは省略可能である。

 #[clap(short, long, default_value = "1")]

 default_value: u64,

  

 /// 文字列を引数に取るオプションのフラグ。

 ///

 /// `Option<T>` を指定すると、このフラグを指定しない事が可能。

 ///

 /// `help = "..."` でヘルプテキストを明に指定する。

 #[clap(short, long, help = "オプションのテキスト")]

 text: Option<String>,

  

 /// 複数指定可能なフラグ。

 #[clap(short, long)]

 multiple: Vec<String>,

  

 /// 複数指定可能なフラグのOption版。

 ///

 /// こちらは、指定が0個の場合は `None` になる。

 #[clap(short, long)]

 optional_multiple: Option<Vec<String>>,

  

 /// 出現回数を数えるタイプのフラグ。

 ///

 /// verbosity の `-vvvv` のような指定で多用される。

 #[clap(short, parse(from_occurrences))]

 verbose: usize,

  

 /// フラグの文字列を明に指定しているフラグ。

 ///

 /// `default_value = ".."` でデフォルト値を指定できる。

 #[clap(short = 'x', long = "xxx", default_value = "2")]

 renamed: u64,

  

 /// 列挙型のフラグ。

 ///

 /// [`ArgEnum`] 経由でのパースの場合は、 `arg_enum` を指定する。

 #[clap(short = 'M', arg_enum)]

 mode: Mode,

  

 /// 環境変数を読むフラグ。

 ///

 /// `env` feature を有効にする必要がある。

 #[clap(short, long, env)]

 username: Option<String>,

  

 /// 必須の位置引数。

 arg1: String,

  

 /// オプションの位置引数。

 ///

 /// この引数はオプションなので省略できる。

 arg2: Option<PathBuf>,

}

  

/// モード指定用の列挙型。

///

/// [`ArgEnum`] でコマンドラインオプション用の列挙型にできる。

#[derive(Debug, Clone, ArgEnum)]

enum Mode {

 Single,

 Multi,

}
> struct.exe -h
struct 1.0.0
Igaguri <igagurimk@gmail.com>
clap v3 のサンプルプログラム集

USAGE:
    struct.exe [OPTIONS] --count <COUNT> -M <MODE> <ARG1> [ARG2]

ARGS:
    <ARG1>    必須の位置引数。
    <ARG2>    オプションの位置引数。

OPTIONS:
    -b, --bool-flag
            boolフラグ。

    -c, --count <COUNT>
            整数を引数に取る必須フラグ。

    -d, --default-value <DEFAULT_VALUE>
            整数を引数に取るフラグ。 [default: 1]

    -h, --help
            Print help information

    -m, --multiple <MULTIPLE>
            複数指定可能なフラグ。

    -M <MODE>
            列挙型のフラグ。 [possible values: single, multi]

    -o, --optional-multiple <OPTIONAL_MULTIPLE>
            複数指定可能なフラグのOption版。

    -t, --text <TEXT>
            オプションのテキスト

    -u, --username <USERNAME>
            環境変数を読むフラグ。 [env: USERNAME=kawasaki]

    -v
            出現回数を数えるタイプのフラグ。

    -V, --version
            Print version information

    -x, --xxx <RENAMED>
            フラグの文字列を明に指定しているフラグ。 [default: 2]
> struct.exe
error: The following required arguments were not provided:
    --count <COUNT>
    -M <MODE>
    <ARG1>

USAGE:
    struct.exe --count <COUNT> -M <MODE> --username <USERNAME> <ARG1>

For more information try --help
> struct.exe --count 42 -M single -m a -m 2 -m 6 foo
Args {
    bool_flag: false,
    count: 42,
    default_value: 1,
    text: None,
    multiple: [
        "a",
        "2",
        "6",
    ],
    optional_multiple: None,
    verbose: 0,
    renamed: 2,
    mode: Single,
    username: Some(
        "kawasaki",
    ),
    arg1: "foo",
    arg2: None,
}

サブコマンドの実装

clap v3 では、列挙型を用いたサブコマンド実装をサポートしている。

use clap::{Parser, Subcommand};

  

fn main() {

 let args = Args::parse();

 println!("{:#?}", args);

}

  

/// サブコマンドを持つコマンドライン引数の構造体。

#[derive(Debug, Parser)]

#[clap(name = "subcommand", author, about, version)]

struct Args {

 #[clap(subcommand)]

 command: Commands,

}

  

/// サブコマンドの定義

#[derive(Debug, Subcommand)]

enum Commands {

 /// コマンドライン引数をその場で指定しているサブコマンド。

 Add { x: i64, y: i64 },

  

 /// 指定を別構造体に切り出したサブコマンド。

 ///

 /// 実際には中の構造体を別モジュールで定義する際などに有用。

 Complex(Complex),

}

  

#[derive(Debug, clap::Args)]

struct Complex {

 u: u64,

 v: u64,

 x: u64,

 y: u64,

}
> subcommand.exe help
subcommand 1.0.0
Igaguri <igagurimk@gmail.com>
clap v3 のサンプルプログラム集

USAGE:
    subcommand.exe <SUBCOMMAND>

OPTIONS:
    -h, --help       Print help information
    -V, --version    Print version information

SUBCOMMANDS:
    add        コマンドライン引数をその場で指定しているサブコマンド。
    complex    指定を別構造体に切り出したサブコマンド。
    help       Print this message or the help of the given subcommand(s)
> subcommand.exe help add
subcommand.exe-add
コマンドライン引数をその場で指定しているサブコマンド。

USAGE:
    subcommand.exe add <X> <Y>

ARGS:
    <X>
    <Y>

OPTIONS:
    -h, --help    Print help informatio
> subcommand.exe add 1 2
Args {
    command: Add {
        x: 1,
        y: 2,
    },
}