RustのClapクレートがメチャクチャ良かった話
私事
プライベートでRustを勉強しているのですが、
エンジニアとしてもRustasianとしてもまだまだ未熟であるため、技術評論社から出ている実践Rust入門[言語仕様から開発手法まで]をここ数ヶ月ほど写経していました
自分は買うまで気付かなかったんですが(笑)、こちらの書籍が2~3年前のものになります
当然ですが、中で使わているクレートなどが色々とアップデートされていて、
書き換えながら読み進めている感じです
新参者にはなかなか厳しい戦いです😫
しかしながら、書籍は良書で、すごく勉強になってます!
そんな中でも、
この書籍で紹介されているClap
というクレートが、個人的にはいい意味でバージョンアップしていたので、自分と同じようなことをしている人のために書籍版とバージョンアップで書き換えた版で比較を載せておこうと思います
そもそもClapについてですが
RustでCLIパーサーを簡単に書くためのクレートです
書籍では、11章『Webアプリケーション, データベース接続』で登場します
このClapのv3から新しくDerive API
というのがサポートされるようになったようで、
それがRustのDerive
をフル活用して、元々のBuilder API
を使うよりシンプルに書けたので、個人的にかなり気に入りました
実際のコード
こちらは書籍で公開されているサンプルコードになります
そして、こちらの内容がDerive APIで書き換えたものになります
use clap::{Parser, Subcommand, ArgEnum};
use reqwest::{blocking};
use std::io;
#[derive(Debug, Parser)]
#[clap(
name = env!("CARGO_PKG_NAME"),
version = env!("CARGO_PKG_VERSION"),
author = env!("CARGO_PKG_AUTHORS"),
about = env!("CARGO_PKG_DESCRIPTION"),
arg_required_else_help = true,
)]
struct Cli {
#[clap(subcommand)]
subcommand: SubCommands,
/// server url
#[clap(short = 's', long = "server", value_name = "URL", default_value = "localhost:3000")]
server: String,
}
#[derive(Debug, Subcommand)]
enum SubCommands {
/// get logs
#[clap(arg_required_else_help = true)]
Get {
/// log format
#[clap(
short = 'f',
long = "format",
required = true,
ignore_case = true,
arg_enum,
)]
format: Format,
},
/// post logs, taking input from stdin
Post,
}
#[derive(Debug, Clone, ArgEnum)]
enum Format {
Csv,
Json,
}
fn main() {
let cli = Cli::parse();
let client = blocking::Client::new();
let api_client = ApiClient { server: cli.server, client };
match cli.subcommand {
SubCommands::Get { format } => {
match format {
Format::Csv => unimplemented!(),
Format::Json => do_get_json(&api_client)
}
},
SubCommands::Post => do_post_csv(&api_client)
}
}
記述量はそんなに変わりませんが、
メソッドチェーンで書いていたオプション(.short
, .long
)やコマンドの説明(.about
)などが移動して、main関数の中はかなりシンプルになったかと思います
これだけで以下のようなきれいなヘルプ表示を確認することができます
cli 0.1.0
CLI for web server requests.
USAGE:
cli [OPTIONS] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-s, --server <URL> server url [default: localhost:3000]
-V, --version Print version information
SUBCOMMANDS:
get get logs
help Print this message or the help of the given subcommand(s)
post post logs, taking input from stdin
オプションやサブコマンドを受け取るためのStruct
やEnum
が新たに増え、
これらに対して#[derive]
アトリビュートと#[clap]
アトリビュートでコマンドやオプションを設定していきます
アトリビュートについて(ざっくり)
#[derive]
と#[clap]
を対で書いていく感じです
struct
のフィールドに#[clap(subcommand)]
でサブコマンドであることを明示したら、
サブコマンドとして扱うstruct
には#[derive(Subcommand)]
でサブコマンドとしての実装をするように明記する
#[derive(Parser)]
Clapでパーサーを作成するための大元になります
~::parse()
でオブジェクトを作成したらオプションに当たるstructなどを呼び出すことができます
#[clap(name = env!("CARGO_PKG_NAME"),version = env!("CARGO_PKG_VERSION"),author = env!("CARGO_PKG_AUTHORS"),about = env!("CARGO_PKG_DESCRIPTION"),arg_required_else_help = true)]
CLIのhelp
などに作成者やCLIのバージョンなどを表示してくれます
env!("CARGO_PKG_~")
でCargo.toml
から環境変数を呼び出しています
#[clap(short = 's', long = "server", value_name = "URL", default_value = "localhost:3000")]
オプションについて記述するものになります
short
は省略時、long
は非省略時のオプションになります
value_name
はどういった値を書くかを示します
#[clap(subcommand)]
と#[derive(Subcommand)]
サブコマンドについて記述するものになります
#[clap(arg_enum)]
と#[derive(ArgEnum)]
列挙要素に関して記述するものになります
OPTIONS:
-f, --format <FORMAT> log format [possible values: csv, json]
上記のようにヘルプ表示で分かる通り、入力できるパラメータなどについて制限できます
あれ?ヘルプ表示のコメントはどこへ?
と思った方もいるかも知れません
自分は公式のExampleを見た時、2,3回コードと表示例を見比べました
なんと、
このDerive API
はフィールドに書いたコメントをそのままヘルプ表示に表示してくれます(すごい!!)
cargo doc
もそうですが、Rustのこういう所すごく好きです
最後に
いかがでしたでしょうか?
自分の理解力不足で間違っていることや説明不足なところ、大いにあると思います
その時はコメント頂ければと思います
ここで説明してないことなどに関しても、
公式のExampleがとにかく充実しているので、Exampleを見れば大体のことが分かると思います
(自分は現在、書籍に関しては一通り読み終わったのですが、
actixが提供するactix-multipartを使ってのCSVアップロードをどうするのかで詰まっているので、そのへんもご教授いただけると助かります🙇)
Rustasianの人口が増えることと自社でRustのプロダクトが発足される日を切に願ってます😆
Discussion
こんにちは。『実践Rust入門』の共著者の一人です。前半を執筆しました。
書籍の方をじっくり読んでいただけたようで、ありがとうございます 😊
『はじめに』の最後の節『困ったときは』のところに書いたのですが、Slackに『rust-jp』という日本語コミュニティーがあります。もしよかったら、そちらで質問してみてください。
#actix-web
というチャネル(channel)がありますので、そこで質問するのが良いでしょう。ここから登録できます。 http://rust-jp.herokuapp.com
(すでにご登録済みでしたら無視してください)
私自身はWeb系は詳しくないのですが、
#actix-web
にはActix-Webを業務で使われている方も何人かいらっしゃるようです。actix-multipartについても何か情報が得られるかもしれません。(書籍の後半を執筆されたκeenさんもいらっしゃいます)著者であるtatsuya6502さんにコメントいただけるとはありがとうございます!
励みになります🙏
Slackのチャンネルには入っているのですが、
質問したことや
#actix-web
チャンネルがあることは知らなかったので、質問してみようと思います
アウトプットを意識して始めた記事ですが、
Rustコミュニティの活性化のために、今後も何かあれば書いていこうと思います
通りすがりです。今はArgEnumはリネームされてValueEnumになっているようです(浅はかながらサンプルコードをコピペしてそのまま動かそうとしました)。
情報ありがとうございます!
最近追えてなかったので助かります