From 88019ffe4b4257b0f3043aabb2516265384cedda Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 19 Dec 2023 13:22:39 +0100 Subject: [PATCH] add docs for `Value` trait and derive --- derive/src/lib.rs | 20 ++++------------ docs/guide/value.md | 56 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 35 +++++++++++++++++++++++++++- 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 5a74dfe..486530c 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -1,6 +1,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +//! Derive macros for `uutils_args`. All items here are documented in that +//! crate. + mod argument; mod attributes; mod complete; @@ -18,21 +21,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, Data::Enum, DeriveInput}; -/// Derive `Arguments` -/// -/// ## Argument specifications -/// -/// | specification | kind | value | -/// | -------------- | ---------- | -------- | -/// | `VAL` | positional | n.a. | -/// | `-s` | short | none | -/// | `-s VAL` | short | required | -/// | `-s[VAL]` | short | optional | -/// | `--long` | long | none | -/// | `--long=VAL` | long | required | -/// | `--long[=VAL]` | long | optional | -/// | `long=VAL` | dd | required | -/// +/// Documentation for this can be found in `uutils_args`. #[proc_macro_derive(Arguments, attributes(arg, arguments))] pub fn arguments(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -125,6 +114,7 @@ pub fn arguments(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } +/// Documentation for this can be found in `uutils_args`. #[proc_macro_derive(Value, attributes(value))] pub fn value(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); diff --git a/docs/guide/value.md b/docs/guide/value.md index 4c689c8..7cbff6e 100644 --- a/docs/guide/value.md +++ b/docs/guide/value.md @@ -1 +1,57 @@ # Value trait + +Any field on the enum implementing [`Arguments`](trait@crate::Arguments) has to implement the [`Value`](trait@crate::Value) trait, which determines how it is derive from the text value. Normally, [`Value`](trait@crate::Value) only requires one method: [`from_value`](crate::Value::from_value), which takes an `&OsStr` and returns a `Result` with either `Self` or some boxed error. + +This trait is implemented for common types, such as integers, [`OsString`](std::ffi::OsString), [`PathBuf`](std::path::PathBuf), [`String`] and [`Option`] where `T` implements `Value`. + +There is also a [`Value` derive macro](derive@crate::Value), which provides parsing string values into an `enum`. The name of each variant (lowercased) with a `#[value]` attribute is parsed automatically. Additionally, if the string is an unambiguous prefix, it is also parsed. For example, if we have the values `"yes"` and `"no"` then `"y"`, `"ye"`, `"yes"` are all valid for `"yes"`, because no other values start with those substrings. + +```rust +use uutils_args::Value; +use std::ffi::OsStr; + +#[derive(Value, Debug, PartialEq, Eq)] +enum YesOrNo { + #[value] + Yes, + #[value] + No, +} + +assert_eq!(YesOrNo::from_value(OsStr::new("yes")).unwrap(), YesOrNo::Yes); +assert_eq!(YesOrNo::from_value(OsStr::new("no")).unwrap(), YesOrNo::No); +assert_eq!(YesOrNo::from_value(OsStr::new("y")).unwrap(), YesOrNo::Yes); +assert_eq!(YesOrNo::from_value(OsStr::new("n")).unwrap(), YesOrNo::No); +assert!(YesOrNo::from_value(OsStr::new("YES")).is_err()); +assert!(YesOrNo::from_value(OsStr::new("NO")).is_err()); +assert!(YesOrNo::from_value(OsStr::new("maybe")).is_err()); +``` + +We can also provide custom names for the variants. This is useful if there are multiple strings that should parse to one variant. + +```rust +use uutils_args::Value; +use std::ffi::OsStr; + +#[derive(Value, Debug, PartialEq, Eq)] +enum Color { + #[value("yes", "always")] + Always, + #[value("auto")] + Auto, + #[value("no", "never")] + Never, +} + +assert_eq!(Color::from_value(&OsStr::new("yes")).unwrap(), Color::Always); +assert_eq!(Color::from_value(&OsStr::new("always")).unwrap(), Color::Always); +assert_eq!(Color::from_value(&OsStr::new("auto")).unwrap(), Color::Auto); +assert_eq!(Color::from_value(&OsStr::new("no")).unwrap(), Color::Never); +assert_eq!(Color::from_value(&OsStr::new("never")).unwrap(), Color::Never); + +// The prefixes here are interesting: +// - "a" is ambiguous because it is a prefix of "auto" and "always" +// - "n" is not ambiguous because "no" and "never" map to the same variant +assert!(Color::from_value(&OsStr::new("a")).is_err()); +assert_eq!(Color::from_value(&OsStr::new("n")).unwrap(), Color::Never); +``` diff --git a/src/lib.rs b/src/lib.rs index 87716a1..a7afc2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,40 @@ mod value; pub mod docs; pub use lexopt; -pub use uutils_args_derive::*; + +// The documentation for the derive macros is written here instead of in +// `uutils_args_derive`, because we need to be able to link to items and the +// documentation in this crate. + +/// Derive macro for [`Value`](trait@crate::Value) +/// +/// [See also the chapter on this trait in the guide](crate::docs::guide::value) +/// +/// This macro only works on `enums` and will error at compile time when it is +/// used on a `struct`. +pub use uutils_args_derive::Value; + +/// Derive macro for [`Arguments`](trait@crate::Arguments) +/// +/// [See also the chapter on this trait in the guide](crate::docs::guide::quick) +/// +/// This macro only works on `enums` and will error at compile time when it is +/// used on a `struct`. +/// +/// /// ## Argument specifications +/// +/// | specification | kind | value | +/// | -------------- | ---------- | -------- | +/// | `VAL` | positional | n.a. | +/// | `-s` | short | none | +/// | `-s VAL` | short | required | +/// | `-s[VAL]` | short | optional | +/// | `--long` | long | none | +/// | `--long=VAL` | long | required | +/// | `--long[=VAL]` | long | optional | +/// | `long=VAL` | dd | required | +/// +pub use uutils_args_derive::Arguments; pub use error::{Error, ErrorKind}; pub use value::{Value, ValueError, ValueResult};