1 个不稳定版本

0.1.0 2021年12月12日

#172 in #handler


用于 clapi

Apache-2.0

19KB
492

Clapi

Clapi (Command-Line API) 是一个用于创建命令行应用程序的Rust框架。

Apache-2.0

目前,clapi提供了创建命令行应用程序的几种方法

  • 解析参数
  • 函数处理器
  • 宏属性

以下示例展示了使用4种方法创建相同应用程序。

解析参数

use clapi::{Command, CommandOption, Argument, CommandLine};
use clapi::validator::validate_type;
use std::num::NonZeroUsize;

fn main() -> clapi::Result<()> {
    let command = Command::new("echo")
        .version("1.0")
        .description("outputs the given values on the console")
        .arg(Argument::one_or_more("values"))
        .option(
            CommandOption::new("times")
                .alias("t")
                .description("number of times to repeat")
                .arg(
                    Argument::new()
                        .validator(validate_type::<NonZeroUsize>())
                        .validation_error("expected number greater than 0")
                        .default(NonZeroUsize::new(1).unwrap()),
                ),
        ).handler(|opts, args| {
        let times = opts.convert::<usize>("times").unwrap();
        let values = args.get_raw_args()
            .map(|s| s.to_string())
            .collect::<Vec<String>>()
            .join(" ") as String;

        for _ in 0..times {
            println!("{}", values);
        }

        Ok(())
    });

    CommandLine::new(command)
        .use_default_help()
        .use_default_suggestions()
        .run()
        .map_err(|e| e.exit())
}

函数处理器

use clapi::validator::validate_type;
use clapi::{Argument, Command, CommandLine, CommandOption};

fn main() -> clapi::Result<()> {
    let command = Command::new("MyApp")
        .subcommand(
            Command::new("repeat")
                .arg(Argument::one_or_more("values"))
                .option(
                    CommandOption::new("times").alias("t").arg(
                        Argument::with_name("times")
                            .validator(validate_type::<u64>())
                            .default(1),
                    ),
                )
                .handler(|opts, args| {
                    let times = opts.get_arg("times").unwrap().convert::<u64>()?;
                    let values = args
                        .get("values")
                        .unwrap()
                        .convert_all::<String>()?
                        .join(" ");
                    for _ in 0..times {
                        println!("{}", values);
                    }
                    Ok(())
                }),
        );

    CommandLine::new(command)
        .use_default_suggestions()
        .use_default_help()
        .run()
}

use std::num::NonZeroUsize;

fn main() -> clapi::Result<()> {
    let cli = clapi::app!{ echo =>
        (version => "1.0")
        (description => "outputs the given values on the console")
        (@option times =>
            (alias => "t")
            (description => "number of times to repeat")
            (@arg =>
                (type => NonZeroUsize)
                (default => NonZeroUsize::new(1).unwrap())
                (error => "expected number greater than 0")
            )
        )
        (@arg values => (count => 1..))
        (handler (times: usize, ...args: Vec<String>) => {
            let values = args.join(" ");
            for _ in 0..times {
                println!("{}", values);
            }
        })
    };

    cli.use_default_suggestions()
        .use_default_help()
        .run()
        .map_err(|e| e.exit())
}

宏属性

需要启用 macros 功能。

use clapi::macros::*;
use std::num::NonZeroUsize;

#[command(name="echo", description="outputs the given values on the console", version="1.0")]
#[arg(values, min=1)]
#[option(times,
    alias="t",
    description="number of times to repeat",
    default=1,
    error="expected number greater than 0"
)]
fn main(times: NonZeroUsize, values: Vec<String>) {
    let values = values.join(" ");

    for _ in 0..times.get() {
        println!("{}", values);
    }
}

Serde

任何 CommandCommandOptionArgument 都可以使用 serde 功能进行序列化和反序列化。

这允许您将命令行应用程序读入或写入文件。

use clapi::Command;

fn main(){
    let command = serde_json::from_str::<Command>(r#"
    {
        "name" : "MyApp",
        "description" : "An app to sum numbers",
        "options" : [
            {
                "name" : "times",
                "description" : "Number of times to sum the values",
                "args" : [
                    {
                        "name" : "times",
                        "type" : "u64"
                    }
                ]
            }
        ],
        "args" : [
            {
                "name" : "numbers",
                "description" : "Numbers to sum",
                "type" : "i64",
                "min_count" : 1
            }
        ]
    }
    "#).unwrap();

    assert_eq!(command.get_name(), "MyApp");
    assert_eq!(command.get_description(), Some("An app to sum numbers"));
    assert!(command.get_options().get("times").is_some());
    assert!(command.get_args().get("numbers").is_some());
}

依赖项

~1.5MB
~35K SLoC