Clap
前言
狠狠狠好用的庫介紹。如果你對控制臺情有獨鐘磺陡,必然會接觸到命令行傳參兢交。 對使用者而言,一份優(yōu)雅的命令列表锭沟,錯誤提示能增進(jìn)軟件的好感抽兆。 但對開發(fā)者而言,維護(hù)一份復(fù)雜的命令列表是頭疼的族淮。重復(fù)的命令行參數(shù)辫红,隨著子參數(shù)增多凭涂,不會規(guī)范管理,都會是代碼難以閱讀厉熟。
為了提升效率导盅,減輕負(fù)擔(dān),我強烈推薦clap
庫揍瑟。
介紹
clap
是一個簡單易用白翻,功能強大的命令行參數(shù)解析庫。
使用
clap
允許多中方式指定我們的命令行绢片。支持常規(guī)的 Rust 方法調(diào)用滤馍、宏或者YAML配置。
常規(guī)調(diào)用模式
首先介紹的是Rust代碼控制命令行底循。
extern crate clap;
use clap::{Arg, App};
fn main() {
let matches = App::new("MayApp")
.version("0.1")
.author("kayryu")
.about("Learn use Rust Crate!")
.arg(Arg::with_name("verbose")
.short("v")
.multiple(true)
.help("verbosity level"))
.args_from_usage("-p, --path=[FILE] 'Target file you want to change'")
.get_matches();
if let Some(f) = matches.value_of("path") {
println!("path : {}", f);
}
}
我們使用version()
巢株,author()
和 about()
方法,提供程序的的一般信息熙涤。clap
會自動添加兩個參數(shù):--help和--version(或他們的簡短形式-h和-V)阁苞。
運行你的可執(zhí)行文件,并在跟隨--help
參數(shù)祠挫∧遣郏控制臺輸出:
MayApp 0.1
kayryu
Learn use Rust Crate!
USAGE:
u-clap.exe [FLAGS] [OPTIONS]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
-v verbosity level
OPTIONS:
-p, --path <FILE> Target file you want to change
通過Arg::with_name()
調(diào)用創(chuàng)建一個簡單的命名參數(shù)。此結(jié)構(gòu)有一些有用的方法等舔,例如:
-
short()
: 提供一個簡短的單字母表格 -
required()
: 指示參數(shù)是可選的還是必需的 -
takes_value()
和default_value()
從--option=foo
類似的參數(shù)讀取值骚灸。 -
multiple()
允許重復(fù)發(fā)生;
在參數(shù)中傳入-v
,獲得詳細(xì)的輸出慌植,或者-vv更加詳細(xì)甚牲。
cargo run --bin u-clap --
zero
cargo run --bin u-clap -- -vv
more
對Arg::with_name()
方式創(chuàng)建命令行參數(shù)顯得啰嗦,也可以用args_from_usage
函數(shù)直接從文本信息中解析蝶柿。參考代碼中的Path
例子丈钙。
clap
也支持命令分級,如下例子(來源于clap
提供的例子):
//
// Top Level App (git) TOP
// |
// -----------------------------------------
// / | \ \
// clone push add commit LEVEL 1
// | / \ / \ |
// url origin remote ref name message LEVEL 2
// / /\
// path remote local LEVEL 3
//
接下去我們在前面代碼的基礎(chǔ)上動手使用子命令交汤。
extern crate clap;
use clap::{Arg, App, SubCommand};
fn main() {
let matches = App::new("MayApp")
.version("0.1")
.author("kayryu")
.about("Learn use Rust Crate!")
.arg(Arg::with_name("verbose")
.short("v")
.multiple(true)
.help("verbosity level"))
.args_from_usage("-p, --path=[FILE] 'Target file you want to change'")
.subcommand(SubCommand::with_name("test")
.about("does testing things")
.arg_from_usage("-l, --list 'lists test values'"))
.get_matches();
if let Some(f) = matches.value_of("path") {
println!("path : {}", f);
}
if let Some(matches) = matches.subcommand_matches("test") {
if matches.is_present("list") {
println!("Printing testing lists...");
} else {
println!("Not printing testing lists...");
}
}
}
通過.subcommand()
方法傳入SubCommand
對象著恩。 子命令的參數(shù)構(gòu)造方式和主命令一致。構(gòu)造好參數(shù)后通過.subcommand_matches()
來獲取匹配的子參數(shù)蜻展。進(jìn)一步,我們按照相同的方式創(chuàng)建多層級的命令行邀摆。
宏模式
如果覺得上述構(gòu)建命令行的方式還不夠簡潔纵顾,clap
還提供了宏構(gòu)建。
#[macro_use]
extern crate clap;
let matches = clap_app!(myapp =>
(version: "1.0")
(author: "Kayryu")
(about: "Learn use Rust Crate!")
(@arg CONFIG: -c --config +takes_value "Sets a custom config file")
(@arg debug: -d ... "Sets the level of debugging information")
(@subcommand test =>
(about: "controls testing features")
(@arg verbose: -v --verbose "Print test information verbosely")
)
).get_matches();
let config = matches.value_of("CONFIG").unwrap_or("default.conf");
println!("Value for config: {}", config);
if let Some(matches) = matches.subcommand_matches("test") {
if matches.is_present("verbose") {
println!("Printing verbosely...");
} else {
println!("Printing normally...");
}
}
yaml配置模式
如果你覺得這部分命令行配置住在代碼中顯示影響了代碼閱讀栋盹,clap
也支持YAML讀取施逾,就是把命令行配置放在單獨文件中管理。
在使用它前,需要在依賴中開啟yaml
特性汉额。
[dependencies]
clap = { version = "2.32.0", features = ["yaml"] }
編寫命令行配置文件yaml.yml
:
name: MyApp
version: "1.0"
about: Learn use Rust Crate!
author: Kayryu
args:
- verbose:
help: verbosity level
short: v
multiple: true
- path:
help: Target file you want to change
short: p
takes_value: true
subcommands:
- test:
about: does testing things
args:
- list:
help: lists test values
short: l
調(diào)用代碼:
let yml = load_yaml!("yaml.yml");
let matches = App::from_yaml(yml).get_matches();
let _ = match matches.occurrences_of("verbose") {
0 => println!("zero"),
1 => println!("one"),
_ => println!("more")
};
if let Some(matches) = matches.subcommand_matches("test") {
if matches.is_present("list") {
println!("Printing testing lists...");
} else {
println!("Not printing testing lists...");
}
}
通過load_yaml!
宏導(dǎo)入先前配置好的yaml
文件曹仗,該文件和測試代碼在同一目錄。
錯誤提示
在使用中難免會輸錯參數(shù)蠕搜,但你不用擔(dān)心怎茫,clap
會友好地提示你正確的命令用例。如果僅是命令行的個別字母打錯了妓灌,它還能做到關(guān)聯(lián)提示轨蛤,這點庫做得實在貼心。
>>>>>>
cargo run --bin u-clap test
>>>>>>
error: The subcommand 'testt' wasn't recognized
Did you mean 'test'?
If you believe you received this message in error, try re-running with 'u-clap.exe -- testt'
USAGE:
u-clap.exe [FLAGS] [OPTIONS] [SUBCOMMAND]
For more information try --help