mirror of
https://github.com/Noratrieb/badargs.git
synced 2026-01-16 12:45:13 +01:00
documentation and tests
This commit is contained in:
parent
92628dfbbe
commit
d2788c133c
3 changed files with 108 additions and 14 deletions
|
|
@ -5,7 +5,7 @@ arg!(Force: "force", 'f' -> bool);
|
||||||
arg!(OLevel: "optimize" -> usize);
|
arg!(OLevel: "optimize" -> usize);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = badargs::badargs::<(OutFile, (Force, OLevel))>().unwrap();
|
let args = badargs::badargs!(OutFile, Force, OLevel);
|
||||||
|
|
||||||
let _outfile = args.get::<OutFile>();
|
let _outfile = args.get::<OutFile>();
|
||||||
let _force = args.get::<Force>();
|
let _force = args.get::<Force>();
|
||||||
|
|
|
||||||
55
src/lib.rs
55
src/lib.rs
|
|
@ -1,3 +1,35 @@
|
||||||
|
//!
|
||||||
|
//! # badargs
|
||||||
|
//!
|
||||||
|
//! A fully type-safe argument parser without any proc macros!
|
||||||
|
//!
|
||||||
|
//! Declare your arguments with structs. You probably want to use the macro for that
|
||||||
|
//! ```
|
||||||
|
//! # use badargs::arg;
|
||||||
|
//! arg!(Force: "force", 'f' -> bool);
|
||||||
|
//! arg!(OutFile: "output", 'o' -> String);
|
||||||
|
//! ```
|
||||||
|
//! Then you call the [`badargs`] function with all of your declared arguments. You probably
|
||||||
|
//! want to use a macro for that too.
|
||||||
|
//!
|
||||||
|
//! You can also use the [`badargs!`] macro if you have many arguments and don't want to nest
|
||||||
|
//! the tuples manually
|
||||||
|
//! ```
|
||||||
|
//! # use badargs::arg;
|
||||||
|
//! # arg!(Force: "force", 'f' -> bool);
|
||||||
|
//! # arg!(OutFile: "output", 'o' -> String);
|
||||||
|
//! let args = badargs::badargs!(Force, OutFile);
|
||||||
|
//! ```
|
||||||
|
//! You can then get values using your declared arguments
|
||||||
|
//! ```
|
||||||
|
//! # use badargs::arg;
|
||||||
|
//! # arg!(Force: "force", 'f' -> bool);
|
||||||
|
//! # arg!(OutFile: "output", 'o' -> String);
|
||||||
|
//! # let args = badargs::badargs!(Force, OutFile);
|
||||||
|
//! let force: Option<&bool> = args.get::<Force>();
|
||||||
|
//! let out_file: Option<&String> = args.get::<OutFile>();
|
||||||
|
//! ```
|
||||||
|
|
||||||
mod macros;
|
mod macros;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod schema;
|
mod schema;
|
||||||
|
|
@ -13,15 +45,20 @@ pub type Result<T> = std::result::Result<T, SchemaError>;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Parses the command line arguments based on the provided schema S
|
/// Parses the command line arguments based on the provided schema S
|
||||||
pub fn badargs<S>() -> Result<BadArgs>
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This function panics if an invalid schema is entered
|
||||||
|
///
|
||||||
|
pub fn badargs<S>() -> BadArgs
|
||||||
where
|
where
|
||||||
S: IntoSchema,
|
S: IntoSchema,
|
||||||
{
|
{
|
||||||
let arg_schema = Schema::create::<S>()?;
|
let arg_schema = Schema::create::<S>().expect("Invalid schema!");
|
||||||
|
|
||||||
let args = CliArgs::from_args(&arg_schema, std::env::args()).expect("todo");
|
let args = CliArgs::from_args(&arg_schema, std::env::args()).expect("todo");
|
||||||
|
|
||||||
Ok(BadArgs { args })
|
BadArgs { args }
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
@ -29,12 +66,6 @@ where
|
||||||
///
|
///
|
||||||
/// This is mostly done using unit structs and the `arg!` macro
|
/// This is mostly done using unit structs and the `arg!` macro
|
||||||
///
|
///
|
||||||
/// ```
|
|
||||||
/// # use badargs::arg;
|
|
||||||
/// arg!(Force: "force", 'f' -> bool);
|
|
||||||
/// arg!(OutFile: "output", 'o' -> String);
|
|
||||||
/// // OutFile now implements CliArg
|
|
||||||
/// ```
|
|
||||||
// This trait requires any because some dynamic typing is done in the background
|
// This trait requires any because some dynamic typing is done in the background
|
||||||
pub trait CliArg: Any {
|
pub trait CliArg: Any {
|
||||||
type Content: CliReturnValue;
|
type Content: CliReturnValue;
|
||||||
|
|
@ -51,14 +82,12 @@ pub struct BadArgs {
|
||||||
|
|
||||||
impl BadArgs {
|
impl BadArgs {
|
||||||
/// Get the content of an argument by providing the type of the argument
|
/// Get the content of an argument by providing the type of the argument
|
||||||
pub fn get<T>(&self) -> &T::Content
|
pub fn get<T>(&self) -> Option<&T::Content>
|
||||||
where
|
where
|
||||||
T: CliArg,
|
T: CliArg,
|
||||||
{
|
{
|
||||||
let long_name = T::long();
|
let long_name = T::long();
|
||||||
self.args
|
self.args.get::<T::Content>(long_name)
|
||||||
.get::<T::Content>(long_name)
|
|
||||||
.expect("it has been validated")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,26 @@
|
||||||
|
///
|
||||||
|
/// Declare your arguments using this macro.
|
||||||
|
/// ```
|
||||||
|
/// # use badargs::arg;
|
||||||
|
/// arg!(Force: "force", 'f' -> bool);
|
||||||
|
/// ```
|
||||||
|
/// is a shorthand for
|
||||||
|
/// ```
|
||||||
|
/// # use badargs::{arg, CliArg};
|
||||||
|
/// struct Force;
|
||||||
|
///
|
||||||
|
/// impl CliArg for Force {
|
||||||
|
/// type Content = bool;
|
||||||
|
///
|
||||||
|
/// fn long() -> &'static str {
|
||||||
|
/// "force"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn short() -> Option<char> {
|
||||||
|
/// Some('f')
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! arg {
|
macro_rules! arg {
|
||||||
// implicit optional
|
// implicit optional
|
||||||
|
|
@ -24,3 +47,45 @@ macro_rules! arg {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A shorthand for calling the [`badargs::badargs`] main function
|
||||||
|
/// This macro lets you specify your arguments in a flat list, and then converts them into
|
||||||
|
/// nested tuples for you, since that's what's internally used.
|
||||||
|
/// ```
|
||||||
|
/// # use badargs::arg;
|
||||||
|
/// # arg!(Force: "force", 'f' -> bool);
|
||||||
|
/// # arg!(OutFile: "outfile", 't' -> bool);
|
||||||
|
/// # arg!(SetUpstream: "set-upstream", 'x' -> bool);
|
||||||
|
/// # fn main() {
|
||||||
|
/// let args = badargs::badargs!(Force, OutFile, SetUpstream);
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
/// will be expanded into
|
||||||
|
/// ```
|
||||||
|
/// # use badargs::arg;
|
||||||
|
/// # arg!(Force: "force", 'f' -> bool);
|
||||||
|
/// # arg!(OutFile: "outfile", 't' -> bool);
|
||||||
|
/// # arg!(SetUpstream: "set-upstream", 'x' -> bool);
|
||||||
|
/// let args = badargs::badargs::<(Force, (OutFile, SetUpstream))>();
|
||||||
|
/// ```
|
||||||
|
/// This only provides a minor benefit for programs with a small amount of args, but is
|
||||||
|
/// very useful for larger arg amounts.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! badargs {
|
||||||
|
(@inner $head:ty) => {
|
||||||
|
$head
|
||||||
|
};
|
||||||
|
(@inner $head:ty, $($tail:ty),+) => {
|
||||||
|
($head, $crate::badargs!(@inner $($tail),+))
|
||||||
|
};
|
||||||
|
($($tail:ty),+) => {
|
||||||
|
{
|
||||||
|
#[allow(unused_parens)] // allow this because there might only be one arg
|
||||||
|
{
|
||||||
|
|
||||||
|
$crate::badargs::<($crate::badargs!(@inner $($tail),+))>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue