Crate grab[][src]

This library contains types for supercharging and streamlining grabbing input from the command line. Gone are the days needing to messily handle whether the user wants you to read their input from stdin, or a file, or directly from the argument. Welcome to the future.

But as they say, “An example is worth a thousand words”. Consider then, the following super simple rust CLI program:

use structopt::StructOpt;
use grab::Input;


#[derive(StructOpt)]
struct HelloCLI {
    /// The name we're going to greet
    name: Input
}


    // Parse our argument(s)
    let args = HelloCLI::from_args();

    // Access the user's input, reading it to a string
    let name = args.name.access()?.read_to_string()?;

    // Say hello!
    println!("Hello, {}!", &name);

Just by using [grab::Input] we can now respond to user input three ways:

# The basics, read the argument directly from the command line
$ hello John
Hello, John!

# Read from stdin... in unixy fashion!
$ echo Bob | hello -
Hello, Bob!

# Or even from a file!
$ echo Fred >name.txt; hello @name.txt
Hello, Fred!

Couldn’t be simpler right?

“Okay, okay” you say, “this is great and all… but I want my CLI’s users to refer to stdin as ‘<–’ and files as ‘…’! Anything less just won’t do. So thanks but no th…”. Whoa, whoa! No problem (you psychopath) we can accommodate your (insane) needs. Simply modify the parser configuration to suit your needs!

use grab::{Input, Builder, parsers::{Stdin, File}, error::input::InputError};

// Build our custom stdin parser
fn my_stdin() -> Stdin {
    Stdin::new().with(|this| this.marker("<--"))
}

// And our custom file parser
fn my_file() -> File {
    File::new().with(|this| this.marker("..."))
}

// Then we define our newtype wrapper and implement FromStr
struct MyCustomParser(Input);

impl FromStr for MyCustomParser {
    type Err = InputError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let cfg = Builder::new().with(|this| {
            this
                .text()
                .with_stdin(my_stdin())
                .with_file(my_file())
        });

        let input = cfg.build().parse(s)?;

        Ok(Self(input))
    }
}

// And use it in our CLI!
#[derive(StructOpt)]
struct MyCLI {
    user_input: MyCustomParser
}

There we have it. A custom parser which you can use however you like (you monster)!

Modules

error

Contains all errors exposed by this crate.

parsers

This module contains the individual parsers that the high level API uses for actually processing raw input into a well understood Input. Under the hood, each of the parsers use nom combinators for driving the parsing. See the exposed parsers themselves for details on how each works.

Structs

Builder

A Config builder, you can use this struct to customize which parsers are available to be called when attempting to parse input.

Config

Represents a set of parsers that will be called in ascending order according to their weight until the list is exhausted or a parser returns successfully.

Input

Represents some kind of input source which can be read from.

InputReader

An opaque handle that implements std::io::Read