Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

comment,doc: added the document comments #6

Merged
merged 2 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
14 changes: 14 additions & 0 deletions src/parse/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ 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 a simple rule: arguments staring with `-` or `--`
sttk marked this conversation as resolved.
Show resolved Hide resolved
/// are treated as options, and otherwise 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.
sttk marked this conversation as resolved.
Show resolved Hide resolved
/// 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