1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#![warn(missing_docs)]
//! 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;
//!
//! # type Result = std::result::Result<(), Box<dyn std::error::Error>>;
//!
//! #[derive(StructOpt)]
//! struct HelloCLI {
//!     /// The name we're going to greet
//!     name: Input
//! }
//!
//! # impl HelloCLI {
//! #   fn from_args() -> Self {
//! #       Self::from_iter(vec!["hello", "John"])
//! #   }
//! # }
//!
//! # fn main() -> Result {
//!     // 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);
//! #   Ok(())
//! # }
//! ```
//!
//! Just by using [grab::Input] we can now respond to user input three ways:
//!
//! ```bash
//! # 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 structopt::StructOpt;
//! # use std::str::FromStr;
//! 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)!

mod builder;
mod input;

pub mod error;
pub mod parsers;

pub use input::{Input, InputReader};

pub use builder::{Builder, Config};