From cc4a7cc8a4eac59422a991c23ba56712143f9e95 Mon Sep 17 00:00:00 2001 From: Takayuki Sato Date: Thu, 6 Jun 2024 07:36:41 +0900 Subject: [PATCH] comment,doc: added the document comments (#6) --- src/errors/arg_err.rs | 14 +++- src/errors/cfg_err.rs | 49 +++++++++++--- src/errors/opt_err.rs | 54 +++++++++++++-- src/lib.rs | 148 ++++++++++++++++++++++++++++++++++++++++++ src/parse/parse.rs | 20 ++++++ 5 files changed, 271 insertions(+), 14 deletions(-) diff --git a/src/errors/arg_err.rs b/src/errors/arg_err.rs index c5c2117..ea70be0 100644 --- a/src/errors/arg_err.rs +++ b/src/errors/arg_err.rs @@ -6,9 +6,21 @@ use std::error; use std::ffi; use std::fmt; +/// The enum type for errors of `OsString` arguments. +/// +/// The variants of this enum indicates errors that can occur when operating +/// command line arguments represented by `OsString`. #[derive(Debug, PartialEq)] pub enum InvalidOsArg { - OsArgsContainInvalidUnicode { index: usize, os_arg: ffi::OsString }, + /// The enum variant which indicates that at least one `OsString` value in + /// the command line arguments is invalid Unicode. + OsArgsContainInvalidUnicode { + /// The index of the invalid argument. + /// The argument of which index is zero is the command path. + index: usize, + /// The `OsString` value of the invalid argument. + os_arg: ffi::OsString, + }, } impl fmt::Display for InvalidOsArg { diff --git a/src/errors/cfg_err.rs b/src/errors/cfg_err.rs index 64ab50c..b56b98d 100644 --- a/src/errors/cfg_err.rs +++ b/src/errors/cfg_err.rs @@ -5,21 +5,54 @@ use std::error; use std::fmt; +/// The enum type for errors of option configurations. +/// +/// This enum type has `store_key()` method, which makes it possible to handle +/// configuration-related errors in a unified manner. #[derive(Debug, PartialEq)] pub enum InvalidConfig { - StoreKeyIsDuplicated { store_key: String }, - ConfigIsMultiArgsButHasNoArg { store_key: String }, - ConfigHasDefaultsButHasNoArg { store_key: String }, - OptionNameIsDuplicated { store_key: String, name: String }, + /// Indicates that there are duplicate store keys among multiple + /// configurations. + StoreKeyIsDuplicated { + /// The store key of the specified option in the configuration. + store_key: String, + }, + + /// Indicates that an option configuration contradicts that the option can + /// take multiple arguments (`.is_multi_args == true`) though it does not + /// take option arguments (`.has_arg == false`). + ConfigIsMultiArgsButHasNoArg { + /// The store key of the specified option in the configuration. + store_key: String, + }, + + /// Indicates that an option configuration contradicts that the default + /// arguments (`.defaults`) is not empty though it does not take option + /// arguments (`has_arg == false`). + ConfigHasDefaultsButHasNoArg { + /// The store key of the specified option in the configuration. + store_key: String, + }, + + /// Indicates that there are duplicated option names among the option + /// configurations. + OptionNameIsDuplicated { + /// The store key of the specified option in the configuration. + store_key: String, + + /// The option name that caused this error. + name: String, + }, } impl InvalidConfig { + /// Returns the key used to store the option in the `Cmd` instance. pub fn store_key(&self) -> &str { return match self { - InvalidConfig::StoreKeyIsDuplicated { store_key } => store_key, - InvalidConfig::ConfigIsMultiArgsButHasNoArg { store_key } => store_key, - InvalidConfig::ConfigHasDefaultsButHasNoArg { store_key } => store_key, - InvalidConfig::OptionNameIsDuplicated { store_key, .. } => store_key, + InvalidConfig::StoreKeyIsDuplicated { store_key } => &store_key, + InvalidConfig::ConfigIsMultiArgsButHasNoArg { store_key } => &store_key, + InvalidConfig::ConfigHasDefaultsButHasNoArg { store_key } => &store_key, + InvalidConfig::OptionNameIsDuplicated { store_key, .. } => &store_key, }; } } diff --git a/src/errors/opt_err.rs b/src/errors/opt_err.rs index 70dd779..b91adfd 100644 --- a/src/errors/opt_err.rs +++ b/src/errors/opt_err.rs @@ -5,16 +5,60 @@ use std::error; use std::fmt; +/// The enum type for errors of options or option arguments. +/// +/// This enum type has `option()` method, which makes it possible to handle +/// option-related errors in a unified manner. #[derive(Debug, PartialEq)] pub enum InvalidOption { - OptionContainsInvalidChar { option: String }, - UnconfiguredOption { option: String }, - OptionNeedsArg { option: String, store_key: String }, - OptionTakesNoArg { option: String, store_key: String }, - OptionIsNotMultiArgs { option: String, store_key: String }, + /// Indicates that the name of an option is using invalid characters. + /// This error occurs if the name contains symbols or starts with a symbol + /// or number. + OptionContainsInvalidChar { + /// The option name that caused this error. + option: String, + }, + + /// Indicates that the option with the specified name does not exist in the + /// option configurations. + UnconfiguredOption { + /// The option name that caused this error. + option: String, + }, + + /// Indicates that the option requires arguments in the configuration, but + /// no argument is specified. + OptionNeedsArg { + /// The option name that caused this error. + option: String, + + /// The store key of the specified option in the configuration. + store_key: String, + }, + + /// Indicates that the option is not suppoesed to take an argument in the + /// configuration, but an argument is specified. + OptionTakesNoArg { + /// The option name that caused this error. + option: String, + + /// The store key of the specified option in the configuration. + store_key: String, + }, + + /// Indicates that the option is supposed to take one argument in the + /// configuration, but multiple arguments are specified. + OptionIsNotMultiArgs { + /// The option name that caused this error. + option: String, + + /// The store key of the specified option in the configuration. + store_key: String, + }, } impl InvalidOption { + /// Returns the name of the option that caused the error. pub fn option(&self) -> &str { return match self { InvalidOption::OptionContainsInvalidChar { option } => &option, diff --git a/src/lib.rs b/src/lib.rs index 4e70b8d..8fb5c7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,110 @@ // This program is free software under MIT License. // See the file LICENSE in this distribution for more details. +//! This crate is a library to parse command line arguments. +//! +//! This crate provides the following functionalities: +//! +//! - Supports [POSIX][posix] & [GNU][gnu] like short and long options. +//! - This crate supports `--` option. +//! - This library doesn't support numeric short option. +//! - This library supports not `-ofoo` but `-o=foo` as an alternative to +//! `-o foo` for short option. +//! +//! [posix]: https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html#Argument-Syntax +//! [gnu]: https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html +//! +//! ## Install +//! +//! In `Cargo.toml`, write this crate as a dependency. +//! +//! ```toml +//! [dependencies] +//! cliargs = "0.1.0" +//! ``` +//! +//! ## Usage +//! +//! This crate provides the `Cmd` strcut to parse command line arguments. +//! The usage of this `Cmd` struct is as follows: +//! +//! ### Creates a `Cmd` instance +//! +//! The `Cmd::new` function creates a `Cmd` instance with original command line +//! arguments. +//! This function uses `std::env::arg_os` and `OsString#into_string` to read +//! command line arguments in order to avoid `panic!` call that the user cannot +//! control. +//! +//! ```rust +//! use cliargs::Cmd; +//! use cliargs::errors::InvalidOsArg; +//! +//! let cmd = match Cmd::new() { +//! Ok(cmd) => cmd, +//! Err(InvalidOsArg::OsArgsContainInvalidUnicode { index, os_arg }) => { +//! panic!("Invalid Unicode data: {:?} (index: {})", os_arg, index); +//! } +//! }; +//! ``` +//! +//! ### Creates a `Cmd` instance with the specified `String` array +//! +//! The `Cmd::with_strings` function creates a `Cmd` instance with the +//! specified `String` array. +//! +//! ```rust +//! use cliargs::Cmd; +//! use std::env; +//! +//! let cmd = Cmd::with_strings(env::args()); +//! ``` +//! +//! ### Creates a `Cmd` instance with the specified `OsString` array. +//! +//! ```rust +//! use cliargs::Cmd; +//! use cliargs::errors::InvalidOsArg; +//! use std::env; +//! +//! let cmd = match Cmd::with_os_strings(env::args_os()) { +//! Ok(cmd) => cmd, +//! Err(InvalidOsArg::OsArgsContainInvalidUnicode { index, os_arg }) => { +//! panic!("Invalid Unicode data: {:?} (index: {})", os_arg, index); +//! } +//! }; +//! ``` +//! +//! ## Parses without configurations +//! +//! The `Cmd` struct has the method which parses command line arguments without +//! configurations. +//! This method automatically divides command line arguments to options and +//! command arguments. +//! +//! Command line arguments starts with `-` or `--` are options, and others are +//! command arguments. +//! If you want to specify a value to an option, follows `"="` and the value +//! after the option, like `foo=123`. +//! +//! All command line arguments after `--` are command arguments, even they +//! starts with `-` or `--`. +//! +//! ```rust +//! use cliargs::Cmd; +//! use cliargs::errors::InvalidOption; +//! +//! let mut cmd = Cmd::with_strings(vec![ /* ... */ ]); +//! match cmd.parse() { +//! Ok(_) => { /* ... */ }, +//! Err(InvalidOption::OptionContainsInvalidChar { option }) => { +//! panic!("Option contains invalid character: {option}"); +//! }, +//! Err(err) => panic!("Invalid option: {}", err.option()), +//! } +//! ``` + +/// Enums for errors that can occur when parsing command line arguments. pub mod errors; mod parse; @@ -13,6 +117,15 @@ use std::fmt; use std::mem; use std::path; +/// `Cmd` is the struct that parses command line arguments and stores them. +/// +/// The results of parsing are stored by separating into command name, +/// command arguments, options, and option arguments. +/// +/// These values are retrieved as string slices with the same lifetime as this +/// `Cmd` instance. +/// Therefore, if you want to use those values for a longer period, it is +/// needed to convert them to [String]s. pub struct Cmd<'a> { name: &'a str, args: Vec<&'a str>, @@ -41,10 +154,20 @@ impl fmt::Debug for Cmd<'_> { } impl<'a> Cmd<'a> { + /// Creates a `Cmd` instance with command line arguments obtained from + /// [std::env::args_os]. + /// + /// Since [std::env::args_os] returns a vector of [OsString] and they can + /// contain invalid unicode data, the return value of this funciton is + /// [Result] of `Cmd` or `errors::InvalidOsArg`. pub fn new() -> Result, errors::InvalidOsArg> { Self::with_os_strings(env::args_os()) } + /// Creates a `Cmd` instance with the specified iterator of [OsString]s. + /// + /// [OsString]s can contain invalid unicode data, the return value of + /// this function is [Result] of `Cmd` or `errors::InvalidOsArg`. pub fn with_os_strings( osargs: impl IntoIterator, ) -> Result, errors::InvalidOsArg> { @@ -113,6 +236,7 @@ impl<'a> Cmd<'a> { }) } + /// Creates a `Cmd` instance with the specified iterator of [String]s. pub fn with_strings(args: impl IntoIterator) -> Cmd<'a> { let arg_iter = args.into_iter(); let (size, _) = arg_iter.size_hint(); @@ -147,18 +271,34 @@ impl<'a> Cmd<'a> { } } + /// Returns the command name. + /// + /// This name is base name extracted from the command path string slice, + /// which is the first element of the command line arguments. pub fn name(&'a self) -> &'a str { self.name } + /// Returns the command arguments. + /// + /// These arguments are retrieved as string slices in an array. pub fn args(&'a self) -> &'a [&'a str] { &self.args } + /// Checks whether an option with the specified name exists. pub fn has_opt(&self, name: &str) -> bool { self.opts.contains_key(name) } + /// Returns the option argument with the specified name. + /// + /// If the option has multiple arguments, this method returns the first + /// argument. + /// + /// Since the option may not be specified in the command line arguments, + /// the return value of this method is an [Option] of an option argument + /// or [None]. pub fn opt_arg(&'a self, name: &str) -> Option<&'a str> { if let Some(opt_vec) = self.opts.get(name) { if opt_vec.len() > 0 { @@ -168,6 +308,14 @@ impl<'a> Cmd<'a> { None } + /// Returns the option arguments with the specified name. + /// + /// If the option has one or multiple arguments, this method returns an + /// array of the arguments. + /// + /// Since the option may not be specified in the command line arguments, + /// the return value of this method is an [Option] of option arguments or + /// [None]. pub fn opt_args(&'a self, name: &str) -> Option<&'a [&'a str]> { match self.opts.get(name) { Some(vec) => Some(&vec), diff --git a/src/parse/parse.rs b/src/parse/parse.rs index 7a42c34..8d3b9a1 100644 --- a/src/parse/parse.rs +++ b/src/parse/parse.rs @@ -7,6 +7,26 @@ use crate::errors::InvalidOption; use crate::Cmd; impl<'a> Cmd<'a> { + /// Parses command line arguments without configurations. + /// + /// This method divides command line arguments into options and command + /// arguments based on imple rules that are almost the same as POSIX & + /// GNU: + /// arguments staring with `-` or `--` are treated as options, and + /// others are treated as command arguments. + /// If an `=` is found within an option, the part before the `=` is treated + /// as the option name, and the part after the `=` is treated as the option + /// argument. + /// Options starting with `--` are long options and option starting with + /// `-` are short options. + /// Multiple short options can be concatenated into a single command line + /// argument. + /// If an argument is exactly `--`, all subsequent arguments are treated as + /// command arguments. + /// + /// Since the results of parsing are stored into this `Cmd` instance, this + /// method returns a [Result] which contains an unit value (`()`) if + /// succeeding, or a `errors::InvalidOption` if failing. pub fn parse(&mut self) -> Result<(), InvalidOption> { let collect_args = |arg| { self.args.push(arg);