Crate rags_rs

Source
Expand description

§Introduction

rags is an easy to use argument parsing library that provides pretty help-printing.

The library allows defining arguments in the same tree-like manner that users and developers expect. This leads to efficient parsing as we can efficiently eliminate work based on the state of the parsing. Once an argument has been matched it will never be inspected again.

rags also makes liberal use of the From<String> trait so that arguments can be parsed into any complex type. This means, for example, that an argument naming a file can be constructed directly into a struct wrapping std::fs::File. This leads to re-usable code between subcommands and developers can spend less time and effort inspecting args.

Arguments in the same level (it’s tree-like) are parsed in the order in which they are defined. This means that global args are easy and provides both argument and semantic isolation between subcommands. Once a branch in the parse tree is taken (subcommand), the parser will not consider arguments defined “after” that branch in a higher scope. Because nested subcommands always lead to a lower scope, all arguments along that parse path are considered. This leads to 2 basic rules of usage:

  1. global arguments should always be declared first
  2. positional arguments should be defined within a subcommand scope even if shared betwwen subcommands

§Example Usage

Below is an example of usage that tries to capture most features an concepts. While this had to be edited to match Rust’s doctest requirements, the examples directory contains examples which follow best practices in a “real” application such as defining descriptions as static, not returning errors from main, etc.

extern crate rags_rs as rags;

#[derive(Debug)]
pub struct Options {
    debug: bool,
    verbosity: usize,

    subcmds: Vec<String>,

    build_release: bool,
    build_link: Vec<String>,
    package: String,

    dry_run: bool,

    initial_file: String,
    additional_files: Vec<String>,
}
impl Default for Options {
    fn default() -> Options {
        Options {
            debug: false,
            verbosity: 0,

            subcmds: vec!(),

            build_release: false,
            build_link: vec!(),
            package: "main".to_string(),

            dry_run: false,

            initial_file: "".to_string(),
            additional_files: vec!(),
        }
    }
}

fn main() -> Result<(), rags::Error> {
    let long_desc: &'static str =
    "This example aims to show beginner to intermediate options on the parser
    as well as good practices.

    As such, the usefulness of the binary is minimal but it will show you how
    an application should be structured, options passed, errors handled, and
    using parser state to control execution flow (print_help+exit, subcommands, etc).";


    let mut opts = Options::default();
    let mut parser = rags::Parser::from_args();
    parser
        .app_desc("example using most rags features")
        .app_long_desc(long_desc)
        .group("logging", "adjust logging output")?
            .flag('D', "debug", "enter debug mode", &mut opts.debug, false)?
            .count('v', "verbose", "increase vebosity (can be given multiple times)",
                &mut opts.verbosity, 1)?
            .done()?
        .subcommand("build", "build a target", &mut opts.subcmds, None)?
            .arg('p', "package", "rename the package", &mut opts.package, Some("PKG"), true)?
            .list('l', "lib", "libraries to link", &mut opts.build_link, Some("LIB"), false)?
            .long_flag("release", "do a release build", &mut opts.build_release, false)?
            .positional("file", "file to build", &mut opts.initial_file, true)?
            .positional_list("files", "additional files to build",
                &mut opts.additional_files, false)?
            .done()?
        .subcommand("clean", "clean all build artifacts", &mut opts.subcmds, None)?
            .flag('p', "print-only", "print what files would be cleaned, but do not clean",
                &mut opts.dry_run, false)?
            .done()?
    ;

    if parser.wants_help() {
        parser.print_help();
    } else {
        println!("final config: {:?}", opts);
    }

    Ok(())
}

§Example Help Dialog

The above example prints the following under various help requests:

§Root Command Help

$ rags --help
rags - 0.1.0 - example using most rags features

usage: rags {subcommand} [-Dv]

This example aims to show beginner to intermediate options on the parser
as well as good practices.

As such, the usefulness of the binary is minimal but it will show you how
an application should be structured, options passed, errors handled, and
using parser state to control execution flow (print_help+exit, subcommands, etc).

subcommands:
    build                build a target
    clean                clean all build artifacts

logging:                 adjust logging output
    -D, --debug          enter debug mode [default: false]
    -v, --verbose        increase vebosity (can be given multiple times) [default: 0]

§Subcommand Help

Notice that in the subcommand help we still see the global arguments.

$ rags build --help
rags build - 0.1.0 - build a target

usage: rags build [-Dv -l LIB --release] -p PKG file [files...]

logging:                     adjust logging output
    -D, --debug              enter debug mode [default: false]
    -v, --verbose            increase vebosity (can be given multiple times) [default: 0]

options:
    -p, --package PKG        rename the package [required, default: main]
    -l, --lib LIB            libraries to link
        --release            do a release build [default: false]

positionals:
    file                     file to build [required]
    files...                 additional files to build

Re-exports§

Modules§

Macros§

  • Helper macro to populate the application name, version, and description from the Cargo manifest. Metadata setter functions can be called multiple times if only some of this information is specified in the manifest.

Structs§

  • Parser holds the state required for parsing. The methods provided here define how arguments should be treated as well as where they are constructed.
  • Unused carries information about arguments which go unmatched. Used both in delineating short-code runs as well as passing back all unmatched arguments to the user (when requested via Parser::unused).

Enums§

  • Defines the types of arguments we can handle, and when matched, our best guess as to what kind of arg that is until we can verify with more context.