Skip to content

Commit

Permalink
comment,doc: added the document comments (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
sttk authored Jun 5, 2024
1 parent d008168 commit cc4a7cc
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 14 deletions.
14 changes: 13 additions & 1 deletion src/errors/arg_err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
49 changes: 41 additions & 8 deletions src/errors/cfg_err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
}
}
Expand Down
54 changes: 49 additions & 5 deletions src/errors/opt_err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
148 changes: 148 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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>,
Expand Down Expand Up @@ -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<Cmd<'a>, 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<Item = OsString>,
) -> Result<Cmd<'a>, errors::InvalidOsArg> {
Expand Down Expand Up @@ -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<Item = String>) -> Cmd<'a> {
let arg_iter = args.into_iter();
let (size, _) = arg_iter.size_hint();
Expand Down Expand Up @@ -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 {
Expand All @@ -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),
Expand Down
20 changes: 20 additions & 0 deletions src/parse/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit cc4a7cc

Please sign in to comment.