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};