Merge pull request #53 from epage/migrate

docs: Clean up 3.0 changelog
This commit is contained in:
Ed Page 2021-12-02 18:10:32 -06:00 committed by GitHub
commit aeb295897d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 516 additions and 1482 deletions

File diff suppressed because it is too large Load diff

View file

@ -210,7 +210,7 @@ pub(crate) fn assert_app(app: &App) {
}
assert!(
!(arg.is_set(ArgSettings::Required) && arg.global),
!(arg.is_set(ArgSettings::Required) && arg.get_global()),
"Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
arg.name
);

View file

@ -290,7 +290,7 @@ impl<'help> App<'help> {
/// this `App`.
pub fn get_arg_conflicts_with(&self, arg: &Arg) -> Vec<&Arg<'help>> // FIXME: This could probably have been an iterator
{
if arg.global {
if arg.get_global() {
self.get_global_arg_conflicts_with(arg)
} else {
arg.blacklist
@ -422,34 +422,26 @@ impl<'help> App<'help> {
)
};
let mut has_metadata = false;
for (k, v) in yaml {
a = match k.as_str().expect("App fields must be strings") {
"_has_metadata" => {
has_metadata = true;
a
}
"bin_name" => yaml_to_str!(a, v, bin_name),
"version" => yaml_to_str!(a, v, version),
"long_version" => yaml_to_str!(a, v, long_version),
"author" => yaml_to_str!(a, v, author),
"bin_name" => yaml_to_str!(a, v, bin_name),
"about" => yaml_to_str!(a, v, about),
"long_about" => yaml_to_str!(a, v, long_about),
"before_help" => yaml_to_str!(a, v, before_help),
"before_long_help" => yaml_to_str!(a, v, before_long_help),
"after_help" => yaml_to_str!(a, v, after_help),
"after_long_help" => yaml_to_str!(a, v, after_long_help),
"help_heading" => yaml_to_str!(a, v, help_heading),
"help_template" => yaml_to_str!(a, v, help_template),
"override_help" => yaml_to_str!(a, v, override_help),
"override_usage" => yaml_to_str!(a, v, override_usage),
"template" => yaml_to_str!(a, v, help_template),
"usage" => yaml_to_str!(a, v, override_usage),
"help" => yaml_to_str!(a, v, override_help),
"help_message" => yaml_to_str!(a, v, help_message),
"version_message" => yaml_to_str!(a, v, version_message),
"alias" => yaml_to_str!(a, v, alias),
"aliases" => yaml_vec_or_str!(a, v, alias),
"visible_alias" => yaml_to_str!(a, v, visible_alias),
"visible_aliases" => yaml_vec_or_str!(a, v, visible_alias),
"display_order" => yaml_to_usize!(a, v, display_order),
"term_width" => yaml_to_usize!(a, v, term_width),
"max_term_width" => yaml_to_usize!(a, v, max_term_width),
"args" => {
if let Some(vec) = v.as_vec() {
for arg_yaml in vec {
@ -486,13 +478,7 @@ impl<'help> App<'help> {
"global_setting" | "global_settings" => {
yaml_to_setting!(a, v, global_setting, AppSettings, "AppSetting", err)
}
"name" => continue,
s => {
if !has_metadata {
panic!("Unknown setting '{}' in YAML file for {}", s, err)
}
continue;
}
_ => a,
}
}
@ -869,6 +855,30 @@ impl<'help> App<'help> {
self.override_help(help)
}
/// Deprecated, replaced with [`App::mut_arg`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::mut_arg`")]
pub fn help_short(self, c: char) -> Self {
self.mut_arg("help", |a| a.short(c))
}
/// Deprecated, replaced with [`App::mut_arg`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::mut_arg`")]
pub fn version_short(self, c: char) -> Self {
self.mut_arg("version", |a| a.short(c))
}
/// Deprecated, replaced with [`App::mut_arg`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::mut_arg`")]
pub fn help_message(self, s: impl Into<&'help str>) -> Self {
self.mut_arg("help", |a| a.help(s.into()))
}
/// Deprecated, replaced with [`App::mut_arg`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::mut_arg`")]
pub fn version_message(self, s: impl Into<&'help str>) -> Self {
self.mut_arg("version", |a| a.help(s.into()))
}
/// Sets the help template to be used, overriding the default format.
///
/// **NOTE:** The template system is by design very simple. Therefore, the
@ -954,6 +964,15 @@ impl<'help> App<'help> {
self
}
/// Deprecated, replaced with [`App::setting(a| b)`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::setting(a | b)`")]
pub fn settings(mut self, settings: &[AppSettings]) -> Self {
for s in settings {
self.settings.insert((*s).into());
}
self
}
/// Remove a setting for the current command or subcommand.
///
/// See [`AppSettings`] for a full list of possibilities and examples.
@ -983,6 +1002,15 @@ impl<'help> App<'help> {
self
}
/// Deprecated, replaced with [`App::unset_setting(a| b)`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::unset_setting(a | b)`")]
pub fn unset_settings(mut self, settings: &[AppSettings]) -> Self {
for s in settings {
self.settings.remove((*s).into());
}
self
}
/// Apply a setting for the current command and all subcommands.
///
/// See [`App::setting`] to apply a setting only to this command.
@ -1004,6 +1032,16 @@ impl<'help> App<'help> {
self
}
/// Deprecated, replaced with [`App::global_setting(a| b)`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::global_setting(a | b)`")]
pub fn global_settings(mut self, settings: &[AppSettings]) -> Self {
for s in settings {
self.settings.insert((*s).into());
self.g_settings.insert((*s).into());
}
self
}
/// Remove a setting and stop propagating down to subcommands.
///
/// See [`AppSettings`] for a full list of possibilities and examples.
@ -1983,6 +2021,12 @@ impl<'help> App<'help> {
self._render_version(false)
}
/// Deprecated, replaced with [`App::render_version`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::render_version`")]
pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
write!(w, "{}", self.render_version()).map_err(From::from)
}
/// Version message rendered as if the user ran `--version`.
///
/// See also [`App::render_version`].
@ -2007,6 +2051,12 @@ impl<'help> App<'help> {
self._render_version(true)
}
/// Deprecated, replaced with [`App::render_long_version`]
#[deprecated(since = "3.0.0", note = "Replaced with `App::render_long_version`")]
pub fn write_long_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
write!(w, "{}", self.render_long_version()).map_err(From::from)
}
/// Usage statement
///
/// ### Examples
@ -2465,7 +2515,7 @@ impl<'help> App<'help> {
let global_args: Vec<_> = self
.args
.args()
.filter(|a| a.global)
.filter(|a| a.get_global())
.map(|ga| ga.id.clone())
.collect();
if let Some(used_subcommand) = matcher.0.subcommand.as_ref() {
@ -2608,7 +2658,7 @@ impl<'help> App<'help> {
debug!("App::_propagate_global_args:{}", self.name);
for sc in &mut self.subcommands {
for a in self.args.args().filter(|a| a.global) {
for a in self.args.args().filter(|a| a.get_global()) {
let mut propagate = false;
let is_generated = matches!(
a.provider,

View file

@ -103,11 +103,11 @@ impl_settings! { AppSettings, AppFlags,
=> Flags::DISABLE_HELP_SC,
DisableHelpFlag("disablehelpflag")
=> Flags::DISABLE_HELP_FLAG,
DisableHelpFlags("disablehelpflag")
DisableHelpFlags("disablehelpflags")
=> Flags::DISABLE_HELP_FLAG,
DisableVersionFlag("disableversionflag")
=> Flags::DISABLE_VERSION_FLAG,
DisableVersion("disableversionflag")
DisableVersion("disableversion")
=> Flags::DISABLE_VERSION_FLAG,
PropagateVersion("propagateversion")
=> Flags::PROPAGATE_VERSION,

View file

@ -23,10 +23,6 @@ use std::{
#[cfg(feature = "env")]
use std::{env, ffi::OsString};
// Third Party
#[cfg(feature = "regex")]
use ::regex::Regex;
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;
@ -119,7 +115,6 @@ pub struct Arg<'help> {
pub(crate) terminator: Option<&'help str>,
pub(crate) index: Option<usize>,
pub(crate) help_heading: Option<Option<&'help str>>,
pub(crate) global: bool,
pub(crate) exclusive: bool,
pub(crate) value_hint: ValueHint,
}
@ -268,7 +263,7 @@ impl<'help> Arg<'help> {
/// Get information on if this argument is global or not
pub fn get_global(&self) -> bool {
self.global
self.is_set(ArgSettings::Global)
}
/// Get the environment variable name specified for this argument, if any
@ -356,6 +351,7 @@ impl<'help> Arg<'help> {
note = "Maybe clap::Parser would fit your use case? (Issue #9)"
)]
pub fn from_yaml(y: &'help Yaml) -> Self {
#![allow(deprecated)]
let yaml_file_hash = y.as_hash().expect("YAML file must be a hash");
// We WANT this to panic on error...so expect() is good.
let (name_yaml, yaml) = yaml_file_hash
@ -365,34 +361,21 @@ impl<'help> Arg<'help> {
let name_str = name_yaml.as_str().expect("Arg name must be a string");
let mut a = Arg::new(name_str);
let mut has_metadata = false;
for (k, v) in yaml.as_hash().expect("Arg must be a hash") {
a = match k.as_str().expect("Arg fields must be strings") {
"_has_metadata" => {
has_metadata = true;
a
}
"short" => yaml_to_char!(a, v, short),
"long" => yaml_to_str!(a, v, long),
"alias" => yaml_to_str!(a, v, alias),
"aliases" => yaml_vec_or_str!(a, v, alias),
"short_alias" => yaml_to_str!(a, v, alias),
"short_aliases" => yaml_to_chars!(a, v, short_aliases),
"help" => yaml_to_str!(a, v, help),
"long_help" => yaml_to_str!(a, v, long_help),
"required" => yaml_to_bool!(a, v, required),
"required_if_eq" => yaml_tuple2!(a, v, required_if_eq),
"required_if_eq_any" => yaml_array_tuple2!(a, v, required_if_eq_any),
"required_if_eq_all" => yaml_array_tuple2!(a, v, required_if_eq_all),
"required_if" => yaml_tuple2!(a, v, required_if_eq),
"required_ifs" => yaml_tuple2!(a, v, required_if_eq),
"takes_value" => yaml_to_bool!(a, v, takes_value),
"index" => yaml_to_usize!(a, v, index),
"global" => yaml_to_bool!(a, v, global),
"multiple_occurrences" => yaml_to_bool!(a, v, multiple_occurrences),
"multiple_values" => yaml_to_bool!(a, v, multiple_values),
"hide" => yaml_to_bool!(a, v, hide),
"hide_long_help" => yaml_to_bool!(a, v, hide_long_help),
"hide_short_help" => yaml_to_bool!(a, v, hide_short_help),
"multiple" => yaml_to_bool!(a, v, multiple),
"hidden" => yaml_to_bool!(a, v, hide),
"next_line_help" => yaml_to_bool!(a, v, next_line_help),
"group" => yaml_to_str!(a, v, group),
"number_of_values" => yaml_to_usize!(a, v, number_of_values),
@ -401,17 +384,14 @@ impl<'help> Arg<'help> {
"value_name" => yaml_to_str!(a, v, value_name),
"use_delimiter" => yaml_to_bool!(a, v, use_delimiter),
"allow_hyphen_values" => yaml_to_bool!(a, v, allow_hyphen_values),
"raw" => yaml_to_bool!(a, v, raw),
"require_equals" => yaml_to_bool!(a, v, require_equals),
"last" => yaml_to_bool!(a, v, last),
"require_delimiter" => yaml_to_bool!(a, v, require_delimiter),
"value_terminator" => yaml_to_str!(a, v, value_terminator),
"value_delimiter" => yaml_to_char!(a, v, value_delimiter),
"required_unless_present" => yaml_to_str!(a, v, required_unless_present),
"required_unless" => yaml_to_str!(a, v, required_unless_present),
"display_order" => yaml_to_usize!(a, v, display_order),
"default_value" => yaml_to_str!(a, v, default_value),
"default_value_if" => yaml_tuple3!(a, v, default_value_if),
"default_value_ifs" => yaml_tuple3!(a, v, default_value_if),
"default_missing_value" => yaml_to_str!(a, v, default_missing_value),
#[cfg(feature = "env")]
"env" => yaml_to_str!(a, v, env),
"value_names" => yaml_vec_or_str!(a, v, value_name),
@ -420,63 +400,17 @@ impl<'help> Arg<'help> {
"requires_if" => yaml_tuple2!(a, v, requires_if),
"requires_ifs" => yaml_tuple2!(a, v, requires_if),
"conflicts_with" => yaml_vec_or_str!(a, v, conflicts_with),
"exclusive" => yaml_to_bool!(a, v, exclusive),
"last" => yaml_to_bool!(a, v, last),
"help_heading" => yaml_to_str!(a, v, help_heading),
"value_hint" => yaml_str_parse!(a, v, value_hint),
"hide_default_value" => yaml_to_bool!(a, v, hide_default_value),
#[cfg(feature = "env")]
"hide_env" => yaml_to_bool!(a, v, hide_env),
#[cfg(feature = "env")]
"hide_env_values" => yaml_to_bool!(a, v, hide_env_values),
"hide_possible_values" => yaml_to_bool!(a, v, hide_possible_values),
"overrides_with" => yaml_to_str!(a, v, overrides_with),
"overrides_with_all" => yaml_vec_or_str!(a, v, overrides_with),
"possible_value" => yaml_to_str!(a, v, possible_value),
"possible_values" => yaml_vec_or_str!(a, v, possible_value),
"ignore_case" => yaml_to_bool!(a, v, ignore_case),
"required_unless_present_any" => yaml_vec!(a, v, required_unless_present_any),
"required_unless_present_all" => yaml_vec!(a, v, required_unless_present_all),
"visible_alias" => yaml_to_str!(a, v, visible_alias),
"visible_aliases" => yaml_vec_or_str!(a, v, visible_alias),
"visible_short_alias" => yaml_to_char!(a, v, visible_short_alias),
"visible_short_aliases" => yaml_to_chars!(a, v, visible_short_aliases),
#[cfg(feature = "regex")]
"validator_regex" => {
if let Some(vec) = v.as_vec() {
debug_assert_eq!(2, vec.len());
let regex = yaml_str!(vec[0]);
match Regex::new(regex) {
Err(e) => panic!(
"Failed to convert \"{}\" into regular expression: {}",
regex, e
),
Ok(regex) => a.validator_regex(regex, yaml_str!(vec[1])),
}
} else {
panic!("Failed to convert YAML value to vector")
}
}
"setting" | "settings" => {
yaml_to_setting!(
a,
v,
setting,
ArgSettings,
"ArgSetting",
format!("arg '{}'", name_str)
)
}
"case_insensitive" => yaml_to_bool!(a, v, ignore_case),
"required_unless_one" => yaml_vec!(a, v, required_unless_present_any),
"required_unless_all" => yaml_vec!(a, v, required_unless_present_all),
s => {
if !has_metadata {
panic!(
"Unknown setting '{}' in YAML file for arg '{}'",
s, name_str
)
}
continue;
}
}
}
@ -1113,7 +1047,7 @@ impl<'help> Arg<'help> {
since = "3.0.0",
note = "Replaced with `Arg::required_unless_present_any`"
)]
pub fn required_unless_any<T, I>(self, names: I) -> Self
pub fn required_unless_one<T, I>(self, names: I) -> Self
where
I: IntoIterator<Item = T>,
T: Key,
@ -3020,6 +2954,8 @@ impl<'help> Arg<'help> {
/// If `val` is set to `None`, `arg` only needs to be present. If `val` is set to `"some-val"`
/// then `arg` must be present at runtime **and** have the value `val`.
///
/// If `default` is set to `None`, `default_value` will be removed.
///
/// **NOTE:** This setting is perfectly compatible with [`Arg::default_value`] but slightly
/// different. `Arg::default_value` *only* takes effect when the user has not provided this arg
/// at runtime. This setting however only takes effect when the user has not provided a value at
@ -3791,9 +3727,12 @@ impl<'help> Arg<'help> {
/// [`Subcommand`]: crate::Subcommand
/// [`ArgMatches::is_present("flag")`]: ArgMatches::is_present()
#[inline]
pub fn global(mut self, yes: bool) -> Self {
self.global = yes;
self
pub fn global(self, yes: bool) -> Self {
if yes {
self.setting(ArgSettings::Global)
} else {
self.unset_setting(ArgSettings::Global)
}
}
/// Specifies that *multiple values* may only be set using the delimiter.
@ -5082,7 +5021,6 @@ impl<'help> fmt::Debug for Arg<'help> {
.field("terminator", &self.terminator)
.field("index", &self.index)
.field("help_heading", &self.help_heading)
.field("global", &self.global)
.field("exclusive", &self.exclusive)
.field("value_hint", &self.value_hint)
.field("default_missing_vals", &self.default_missing_vals);

View file

@ -52,7 +52,7 @@ impl_settings! { ArgSettings, ArgFlags,
MultipleValues("multiplevalues") => Flags::MULTIPLE_VALS,
Multiple("multiple") => Flags::MULTIPLE,
ForbidEmptyValues("forbidemptyvalues") => Flags::NO_EMPTY_VALS,
EmptyValues("emptyvalues") => Flags::NO_OP,
Global("global") => Flags::GLOBAL,
Hidden("hidden") => Flags::HIDDEN,
TakesValue("takesvalue") => Flags::TAKES_VAL,
UseValueDelimiter("usevaluedelimiter") => Flags::USE_DELIM,
@ -64,7 +64,7 @@ impl_settings! { ArgSettings, ArgFlags,
RequireEquals("requireequals") => Flags::REQUIRE_EQUALS,
Last("last") => Flags::LAST,
IgnoreCase("ignorecase") => Flags::CASE_INSENSITIVE,
CaseInsensitive("ignorecase") => Flags::CASE_INSENSITIVE,
CaseInsensitive("caseinsensitive") => Flags::CASE_INSENSITIVE,
#[cfg(feature = "env")]
HideEnv("hideenv") => Flags::HIDE_ENV,
#[cfg(feature = "env")]
@ -100,13 +100,8 @@ pub enum ArgSettings {
Multiple,
/// Forbids an arg from accepting empty values such as `""`
ForbidEmptyValues,
/// Deprecated, this is now the default, see [`ArgSettings::ForbidEmptyValues`] for the
/// opposite.
#[deprecated(
since = "3.0.0",
note = "This is now the default see [`ArgSettings::ForbidEmptyValues`] for the opposite."
)]
EmptyValues,
/// Sets an arg to be global (i.e. exist in all subcommands)
Global,
/// Hides an arg from the help message
Hidden,
/// Allows an argument to take a value (such as `--option value`)

View file

@ -17,25 +17,6 @@ macro_rules! yaml_tuple2 {
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_array_tuple2 {
($a:ident, $v:ident, $c:ident) => {{
if let Some(vec) = $v.as_vec() {
for ys in vec {
if let Some(tup) = ys.as_vec() {
debug_assert_eq!(2, tup.len());
$a = $a.$c(&[(yaml_str!(tup[0]), yaml_str!(tup[1]))]);
} else {
panic!("Failed to convert YAML value to vec");
}
}
} else {
panic!("Failed to convert YAML value to vec");
}
$a
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_tuple3 {
($a:ident, $v:ident, $c:ident) => {{
@ -130,28 +111,6 @@ macro_rules! yaml_char {
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_chars {
($v:expr) => {{
&$v.as_vec()
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a list", $v))
.into_iter()
.map(|s| {
s.as_str()
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", s))
})
.map(|s| {
let mut chars = s.chars();
let c = chars.next().expect("short aliases must be a single char");
if chars.next().is_some() {
panic!("short aliases must be a single char");
}
c
})
.collect::<Vec<char>>()
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_str {
($v:expr) => {{
@ -160,17 +119,6 @@ macro_rules! yaml_str {
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_str_parse {
($a:ident, $v:ident, $c:ident) => {{
$a.$c($v
.as_str()
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))
.parse()
.unwrap_or_else(|err| panic!("{}", err)))
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_to_char {
($a:ident, $v:ident, $c:ident) => {{
@ -178,13 +126,6 @@ macro_rules! yaml_to_char {
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_to_chars {
($a:ident, $v:ident, $c:ident) => {{
$a.$c(yaml_chars!($v))
}};
}
#[cfg(feature = "yaml")]
macro_rules! yaml_to_str {
($a:ident, $v:ident, $c:ident) => {{

View file

@ -12,6 +12,166 @@ macro_rules! load_yaml {
};
}
/// Deprecated, replaced with [`ArgMatches::value_of_t`][crate::ArgMatches::value_of_t]
#[macro_export]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::value_of_t`")]
macro_rules! value_t {
($m:ident, $v:expr, $t:ty) => {
$crate::value_t!($m.value_of($v), $t)
};
($m:ident.value_of($v:expr), $t:ty) => {
$m.value_of_t::<$t>($v)
};
}
/// Deprecated, replaced with [`ArgMatches::value_of_t_or_exit`][crate::ArgMatches::value_of_t_or_exit]
#[macro_export]
#[deprecated(
since = "3.0.0",
note = "Replaced with `ArgMatches::value_of_t_or_exit`"
)]
macro_rules! value_t_or_exit {
($m:ident, $v:expr, $t:ty) => {
value_t_or_exit!($m.value_of($v), $t)
};
($m:ident.value_of($v:expr), $t:ty) => {
$m.value_of_t_or_exit::<$t>($v)
};
}
/// Deprecated, replaced with [`ArgMatches::values_of_t`][crate::ArgMatches::value_of_t]
#[macro_export]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::values_of_t`")]
macro_rules! values_t {
($m:ident, $v:expr, $t:ty) => {
values_t!($m.values_of($v), $t)
};
($m:ident.values_of($v:expr), $t:ty) => {
$m.values_of_t::<$t>($v)
};
}
/// Deprecated, replaced with [`ArgMatches::values_of_t_or_exit`][crate::ArgMatches::value_of_t_or_exit]
#[macro_export]
#[deprecated(
since = "3.0.0",
note = "Replaced with `ArgMatches::values_of_t_or_exit`"
)]
macro_rules! values_t_or_exit {
($m:ident, $v:expr, $t:ty) => {
values_t_or_exit!($m.values_of($v), $t)
};
($m:ident.values_of($v:expr), $t:ty) => {
$m.values_of_t_or_exit::<$t>($v)
};
}
/// Deprecated, replaced with [`ArgEnum`][crate::ArgEnum]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgEnum`")]
#[macro_export]
macro_rules! arg_enum {
(@as_item $($i:item)*) => ($($i)*);
(@impls ( $($tts:tt)* ) -> ($e:ident, $($v:ident),+)) => {
$crate::arg_enum!(@as_item
$($tts)*
impl ::std::str::FromStr for $e {
type Err = String;
fn from_str(s: &str) -> ::std::result::Result<Self,Self::Err> {
#[allow(deprecated, unused_imports)]
use ::std::ascii::AsciiExt;
match s {
$(stringify!($v) |
_ if s.eq_ignore_ascii_case(stringify!($v)) => Ok($e::$v)),+,
_ => Err({
let v = vec![
$(stringify!($v),)+
];
format!("valid values: {}",
v.join(", "))
}),
}
}
}
impl ::std::fmt::Display for $e {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
$($e::$v => write!(f, stringify!($v)),)+
}
}
}
impl $e {
#[allow(dead_code)]
pub fn variants() -> [&'static str; $crate::_clap_count_exprs!($(stringify!($v)),+)] {
[
$(stringify!($v),)+
]
}
});
};
($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
$crate::arg_enum!(@impls
($(#[$($m),+])+
pub enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
$crate::arg_enum!(@impls
($(#[$($m),+])+
pub enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
$crate::arg_enum!(@impls
($(#[$($m),+])+
enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
$crate::arg_enum!(@impls
($(#[$($m),+])+
enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
(pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
$crate::arg_enum!(@impls
(pub enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
(pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
$crate::arg_enum!(@impls
(pub enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
(enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
$crate::arg_enum!(@impls
(enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
(enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
$crate::arg_enum!(@impls
(enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
}
/// Allows you to pull the version from your Cargo.toml at compile time as
/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE`
///
@ -464,13 +624,6 @@ macro_rules! clap_app {
$($tt)*
}
};
(@app ($builder:expr) (@arg $name:literal: $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.arg(
$crate::clap_app!{ @arg ($crate::Arg::new(stringify!($name).trim_matches('"'))) (-) $($tail)* }))
$($tt)*
}
};
(@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.arg(
@ -478,14 +631,6 @@ macro_rules! clap_app {
$($tt)*
}
};
// Global Settings
(@app ($builder:expr) (@global_setting $setting:ident) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.global_setting($crate::AppSettings::$setting))
$($tt)*
}
};
// Settings
(@app ($builder:expr) (@setting $setting:ident) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.setting($crate::AppSettings::$setting))
@ -496,30 +641,25 @@ macro_rules! clap_app {
(@app ($builder:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app ($crate::clap_app!{ @arg ($builder) $($attr)* }) $($tt)* }
};
// ArgGroup
(@app ($builder:expr) (@group $name:ident: $($attrs:tt)*) $($tt:tt)*) => {
(@app ($builder:expr) (@group $name:ident => $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($crate::clap_app!{ @group ($builder, $crate::ArgGroup::new(stringify!($name))) $($attrs)* })
($crate::clap_app!{ @group ($builder, $crate::ArgGroup::new(stringify!($name))) $($tail)* })
$($tt)*
}
};
(@app ($builder:expr) (@group $name:ident !$ident:ident => $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($crate::clap_app!{ @group ($builder, $crate::ArgGroup::new(stringify!($name)).$ident(false)) $($tail)* })
$($tt)*
}
};
(@app ($builder:expr) (@group $name:ident +$ident:ident => $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($crate::clap_app!{ @group ($builder, $crate::ArgGroup::new(stringify!($name)).$ident(true)) $($tail)* })
$($tt)*
}
};
// Handle subcommand creation
(@app ($builder:expr) (@subcommand ($name:expr) => $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.subcommand(
$crate::clap_app!{ @app ($crate::App::new($name)) $($tail)* }
))
$($tt)*
}
};
(@app ($builder:expr) (@subcommand $name:literal => $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.subcommand(
$crate::clap_app!{ @app ($crate::App::new(stringify!($name).trim_matches('"'))) $($tail)* }
))
$($tt)*
}
};
(@app ($builder:expr) (@subcommand $name:ident => $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.subcommand(
@ -530,30 +670,18 @@ macro_rules! clap_app {
};
// Yaml like function calls - used for setting various meta directly against the app
(@app ($builder:expr) ($ident:ident: $($v:expr),*) $($tt:tt)*) => {
// $crate::clap_app!{ @app ($builder.$ident($($v),*)) $($tt)* }
$crate::clap_app!{ @app
($builder.$ident($($v),*))
$($tt)*
}
};
// Add members to group and continue argument handling with the parent builder
(@group ($builder:expr, $group:expr)) => { $builder.group($group) };
// Treat the group builder as an argument to set its attributes
(@group ($builder:expr, $group:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @group ($builder, $group) $($attr)* $($tt)* }
};
(@group ($builder:expr, $group:expr) (@arg ($name:expr): $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @group
($crate::clap_app!{ @app ($builder) (@arg ($name): $($tail)*) },
$group.arg($name))
$($tt)*
}
};
(@group ($builder:expr, $group:expr) (@arg $name:literal: $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @group
($crate::clap_app!{ @app ($builder) (@arg $name: $($tail)*) },
$group.arg(stringify!($name).trim_matches('"')))
$($tt)*
}
$crate::clap_app!{ @group ($builder, $crate::clap_app!{ @arg ($group) (-) $($attr)* }) $($tt)* }
};
(@group ($builder:expr, $group:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @group
@ -562,31 +690,6 @@ macro_rules! clap_app {
$($tt)*
}
};
// Handle group attributes
(@group ($builder:expr, $group:expr) !$ident:ident $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group.$ident(false)) $($tail)* }
};
(@group ($builder:expr, $group:expr) +$ident:ident $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group.$ident(true)) $($tail)* }
};
(@group ($builder:expr, $group:expr) * $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group) +required $($tail)* }
};
(@group ($builder:expr, $group:expr) ... $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group) +multiple $($tail)* }
};
(@group ($builder:expr, $group:expr) $ident:ident[$($target:literal)*] $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group $( .$ident(stringify!($target).trim_matches('"')) )*) $($tail)* }
};
(@group ($builder:expr, $group:expr) $ident:ident[$($target:ident)*] $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group $( .$ident(stringify!($target)) )*) $($tail)* }
};
(@group ($builder:expr, $group:expr) $ident:ident($($expr:expr),*) $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group.$ident($($expr),*)) $($tail)* }
};
(@group ($builder:expr, $group:expr) $ident:ident($($expr:expr,)*) $($tail:tt)*) => {
$crate::clap_app!{ @group ($builder, $group.$ident($($expr),*)) $($tail)* }
};
// No more tokens to munch
(@arg ($arg:expr) $modes:tt) => { $arg };
@ -594,18 +697,9 @@ macro_rules! clap_app {
(@arg ($arg:expr) $modes:tt --($long:expr) $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg.long($long)) $modes $($tail)* }
};
(@arg ($arg:expr) $modes:tt --$long:literal $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg.long(stringify!($long).trim_matches('"'))) $modes $($tail)* }
};
(@arg ($arg:expr) $modes:tt --$long:ident $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg.long(stringify!($long))) $modes $($tail)* }
};
(@arg ($arg:expr) $modes:tt -($short:expr) $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg.short($short)) $modes $($tail)* }
};
(@arg ($arg:expr) $modes:tt -$short:literal $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg.short($short.to_string().chars().next().expect(r#""" is not allowed here"#))) $modes $($tail)* }
};
(@arg ($arg:expr) $modes:tt -$short:ident $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg.short(stringify!($short).chars().next().unwrap())) $modes $($tail)* }
};
@ -622,7 +716,7 @@ macro_rules! clap_app {
$crate::clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* }
};
(@arg ($arg:expr) $modes:tt ... $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg) $modes +multiple_values +takes_value $($tail)* }
$crate::clap_app!{ @arg ($arg) $modes +multiple +takes_value $($tail)* }
};
// Shorthand magic
(@arg ($arg:expr) $modes:tt #{$n:expr, $m:expr} $($tail:tt)*) => {
@ -647,9 +741,6 @@ macro_rules! clap_app {
// Help
(@arg ($arg:expr) $modes:tt $desc:tt) => { $arg.help($crate::clap_app!{ @as_expr $desc }) };
// Handle functions that need to be called multiple times for each argument
(@arg ($arg:expr) $modes:tt $ident:ident[$($target:literal)*] $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg $( .$ident(stringify!($target).trim_matches('"')) )*) $modes $($tail)* }
};
(@arg ($arg:expr) $modes:tt $ident:ident[$($target:ident)*] $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg $( .$ident(stringify!($target)) )*) $modes $($tail)* }
};
@ -661,13 +752,8 @@ macro_rules! clap_app {
(@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr,)*) $($tail:tt)*) => {
$crate::clap_app!{ @arg ($arg.$ident($($expr),*)) $modes $($tail)* }
};
// Build a subcommand outside of an app.
(@subcommand ($name:expr) => $($tail:tt)*) => {
$crate::clap_app!{ @app ($crate::App::new($name)) $($tail)* }
};
(@subcommand $name:literal => $($tail:tt)*) => {
$crate::clap_app!{ @app ($crate::App::new(stringify!($name).trim_matches('"'))) $($tail)* }
};
(@subcommand $name:ident => $($tail:tt)*) => {
$crate::clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)* }
};
@ -675,9 +761,7 @@ macro_rules! clap_app {
(($name:expr) => $($tail:tt)*) => {{
$crate::clap_app!{ @app ($crate::App::new($name)) $($tail)*}
}};
($name:literal => $($tail:tt)*) => {{
$crate::clap_app!{ @app ($crate::App::new(stringify!($name).trim_matches('"'))) $($tail)*}
}};
($name:ident => $($tail:tt)*) => {{
$crate::clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)*}
}};
@ -819,57 +903,3 @@ macro_rules! debug {
macro_rules! debug {
($($arg:tt)*) => {};
}
/// Deprecated, replaced with [`ArgMatches::value_of_t`][crate::ArgMatches::value_of_t]
#[macro_export]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::value_of_t`")]
macro_rules! value_t {
($m:ident, $v:expr, $t:ty) => {
clap::value_t!($m.value_of($v), $t)
};
($m:ident.value_of($v:expr), $t:ty) => {
$m.value_of_t::<$t>($v)
};
}
/// Deprecated, replaced with [`ArgMatches::value_of_t_or_exit`][crate::ArgMatches::value_of_t_or_exit]
#[macro_export]
#[deprecated(
since = "3.0.0",
note = "Replaced with `ArgMatches::value_of_t_or_exit`"
)]
macro_rules! value_t_or_exit {
($m:ident, $v:expr, $t:ty) => {
value_t_or_exit!($m.value_of($v), $t)
};
($m:ident.value_of($v:expr), $t:ty) => {
$m.value_of_t_or_exit::<$t>($v)
};
}
/// Deprecated, replaced with [`ArgMatches::values_of_t`][crate::ArgMatches::value_of_t]
#[macro_export]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::values_of_t`")]
macro_rules! values_t {
($m:ident, $v:expr, $t:ty) => {
values_t!($m.values_of($v), $t)
};
($m:ident.values_of($v:expr), $t:ty) => {
$m.values_of_t::<$t>($v)
};
}
/// Deprecated, replaced with [`ArgMatches::values_of_t_or_exit`][crate::ArgMatches::value_of_t_or_exit]
#[macro_export]
#[deprecated(
since = "3.0.0",
note = "Replaced with `ArgMatches::values_of_t_or_exit`"
)]
macro_rules! values_t_or_exit {
($m:ident, $v:expr, $t:ty) => {
values_t_or_exit!($m.values_of($v), $t)
};
($m:ident.values_of($v:expr), $t:ty) => {
$m.values_of_t_or_exit::<$t>($v)
};
}

View file

@ -4,31 +4,26 @@ about: tests clap library
author: Kevin K. <kbknapp@gmail.com>
settings:
- ArgRequiredElseHelp
help_message: prints help with a nonstandard description
args:
- help:
short: h
long: help
help: prints help with a nonstandard description
- option:
- opt:
short: o
long: option
multiple: true
takes_value: true
multiple_values: true
help: tests options
- positional:
help: tests positionals
index: 1
- positional2:
help: tests positionals with exclusions
index: 2
default_value_if:
- [flag, null, some]
- [positional, other, something]
- [flag, Null, some]
- [postional, other, something]
- flag:
short: f
long: flag
multiple: true
takes_value: true
multiple_values: true
help: tests flags
global: true
- flag2:
@ -41,13 +36,11 @@ args:
- option2:
long: long-option-2
help: tests long options with exclusions
conflicts_with:
- option
requires:
- positional2
- option3:
short: O
long: option3
long: Option
help: tests options with specific value sets
takes_value: true
possible_values:
@ -56,7 +49,6 @@ args:
requires_if:
- [fast, flag]
- positional3:
index: 3
help: tests positionals with specific values
possible_values: [ vi, emacs ]
- multvals:
@ -67,83 +59,49 @@ args:
- two
- multvalsmo:
long: multvalsmo
multiple_values: true
multiple: true
takes_value: true
help: Tests multiple values, not mult occs
value_names: [one, two]
- multvalsdelim:
long: multvalsdelim
help: Tests multiple values with required delimiter
multiple: true
takes_value: true
multiple_occurrences: true
use_delimiter: true
require_delimiter: true
- settings:
short: s
takes_value: true
multiple_values: true
value_delimiter: ","
- singlealias:
long: singlealias
help: Tests single alias
aliases: [alias]
required_if_eq:
required_if:
- [multvalsmo, two]
- multaliases:
long: multaliases
help: Tests multiple aliases
aliases: [als1, als2, als3]
- singleshortalias:
long: singleshortalias
help: Tests single short alias
short_aliases: [a]
required_if_eq:
- [multvalsmo, two]
- multshortaliases:
long: multshortaliases
help: Tests multiple short aliases
short_aliases: [b, c]
- minvals2:
long: minvals2
multiple_values: true
multiple: true
takes_value: true
help: Tests 2 min vals
min_values: 2
- maxvals3:
long: maxvals3
multiple_values: true
multiple: true
takes_value: true
help: Tests 3 max vals
max_values: 3
- exclusive:
long: exclusive
help: Tests 3 exclusive
exclusive: true
- ignore_case:
index: 4
help: Test ignore case
- case_insensitive:
help: Test case_insensitive
possible_values: [test123, test321]
ignore_case: true
- value_hint:
long: value-hint
help: Test value_hint
value_hint: FilePath
- verbose:
short: v
multiple_occurrences: true
takes_value: false
help: Sets the level of verbosity
- visiblealiases:
long: visiblealiases
help: Tests visible aliases
visible_alias: visals1
visible_aliases: [visals2, visals2, visals3]
- visibleshortaliases:
long: visibleshortaliases
help: Tests visible short aliases
visible_short_alias: e
visible_short_aliases: [l, m]
groups:
case_insensitive: true
arg_groups:
- test:
args:
- maxvals3
- minvals2
- minmals2
conflicts_with:
- option3
requires:
@ -157,9 +115,8 @@ subcommands:
- scoption:
short: o
long: option
multiple_values: true
multiple: true
help: tests options
takes_value: true
- scpositional:
help: tests positionals
index: 1

View file

@ -1,11 +0,0 @@
name: claptests
version: "1.0"
about: tests clap library
author: Kevin K. <kbknapp@gmail.com>
args:
- opt:
short: o
long: option
takes_value: true
multiple_values: true
help: tests options

View file

@ -1,2 +0,0 @@
name: claptests
1: "invalid"

View file

@ -1,9 +0,0 @@
name: clapregextest
version: "1.0"
about: tests clap regex functionality
author: Benjamin Kästner <benjamin.kaestner@gmail.com>
args:
- filter:
index: 1
validator_regex: ["^*\\.[a-z]+$", expected extension pattern]
help: file extension pattern

View file

@ -1,8 +0,0 @@
name: clapregextest
version: "1.0"
about: tests clap regex functionality
author: Benjamin Kästner <benjamin.kaestner@gmail.com>
args:
- filter:
index: 1
validator_regex: [")", invalid regular expression]

View file

@ -1,5 +0,0 @@
name: claptests
version: "1.0"
about: tests clap extra fields
settings:
- random

View file

@ -1,2 +0,0 @@
claptest-arg:
6: false

View file

@ -1,4 +0,0 @@
name: claptests
args:
- arg:
short: a

View file

@ -1,8 +0,0 @@
name: claptests
version: "1.0"
about: tests clap extra fields
args:
- option:
long: option
settings:
- random

View file

@ -1,10 +0,0 @@
_has_metadata: true
name: claptests
version: "1.0"
about: tests clap extra fields
random: This field is extra
args:
- option:
_has_metadata: true
long: option
random: This field is extra

View file

@ -1,6 +0,0 @@
name: claptests
version: "1.0"
about: tests clap extra fields
subcommands:
- info:
random: This field is extra

View file

@ -1,7 +0,0 @@
name: claptests
version: "1.0"
about: tests clap extra fields
args:
- option:
long: option
random: This field is extra

View file

@ -1,3 +0,0 @@
claptests:
- 5
- 6

View file

@ -1,21 +0,0 @@
name: app
args:
- arg_1:
short: a
- arg_2:
short: b
- arg_3:
short: c
- arg_4:
short: d
groups:
- group_1:
args:
- arg_1
- arg_2
- group_2:
args:
- arg_3
- arg_4

View file

@ -1 +0,0 @@
100: "claptests"

View file

@ -1 +0,0 @@
["clap", "tests"]

View file

@ -9,7 +9,6 @@ fn basic() {
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@global_setting AllowNegativeNumbers)
(@arg opt: -o --option +takes_value ... "tests options")
(@arg positional: index(1) "tests positionals")
(@arg flag: -f --flag ... +global "tests flags")
@ -157,42 +156,6 @@ fn quoted_arg_name() {
assert!(matches.is_present("option2"));
}
#[test]
fn quoted_subcommand_name() {
#![allow(deprecated)]
clap::clap_app!(claptests =>
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@arg opt: -o --option +takes_value ... "tests options")
(@arg positional: index(1) "tests positionals")
(@arg flag: -f --flag ... +global "tests flags")
(@arg flag2: -F conflicts_with[flag] requires[option2]
"tests flags with exclusions")
(@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
"tests long options with exclusions")
(@arg positional2: index(2) "tests positionals with exclusions")
(@arg option3: -O --Option +takes_value possible_value[fast slow]
"tests options with specific value sets")
(@arg positional3: index(3) ... possible_value[vi emacs]
"tests positionals with specific values")
(@arg multvals: --multvals +takes_value value_name[one two]
"Tests multiple values, not mult occs")
(@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
"Tests multiple values, not mult occs")
(@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
(@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
(@subcommand subcmd =>
(about: "tests subcommands")
(version: "0.1")
(author: "Kevin K. <kbknapp@gmail.com>")
(@arg scoption: -o --option ... +takes_value "tests options")
(@arg scpositional: index(1) "tests positionals"))
(@subcommand ("other-subcmd") =>
(about: "some other subcommand"))
);
}
#[test]
fn group_macro() {
#![allow(deprecated)]
@ -200,7 +163,7 @@ fn group_macro() {
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty:
(@group difficulty =>
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
@ -221,7 +184,7 @@ fn group_macro_set_multiple() {
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty: +multiple
(@group difficulty +multiple =>
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
@ -244,7 +207,7 @@ fn group_macro_set_not_multiple() {
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty: !multiple
(@group difficulty !multiple =>
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
@ -264,7 +227,7 @@ fn group_macro_set_required() {
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty: +required
(@group difficulty +required =>
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
@ -284,7 +247,7 @@ fn group_macro_set_not_required() {
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty: !required
(@group difficulty !required =>
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
@ -297,145 +260,6 @@ fn group_macro_set_not_required() {
assert!(!matches.is_present("difficulty"));
}
#[test]
fn group_macro_attributes_alternative() {
#![allow(deprecated)]
let app = clap::clap_app!(claptests =>
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty:
(@attributes +multiple +required)
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
)
);
let result = app
.clone()
.try_get_matches_from(vec!["bin_name", "--hard", "--easy"]);
assert!(result.is_ok());
let matches = result.expect("Expected to successfully match the given args.");
assert!(matches.is_present("difficulty"));
assert!(matches.is_present("hard"));
assert!(matches.is_present("easy"));
assert!(!matches.is_present("normal"));
let result = app.try_get_matches_from(vec!["bin_name"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}
#[test]
fn group_macro_multiple_methods() {
#![allow(deprecated)]
let app = clap::clap_app!(claptests =>
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty: +multiple +required
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
)
);
let result = app
.clone()
.try_get_matches_from(vec!["bin_name", "--hard", "--easy"]);
assert!(result.is_ok());
let matches = result.expect("Expected to successfully match the given args.");
assert!(matches.is_present("difficulty"));
assert!(matches.is_present("hard"));
assert!(matches.is_present("easy"));
assert!(!matches.is_present("normal"));
let result = app.try_get_matches_from(vec!["bin_name"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}
#[test]
fn group_macro_multiple_methods_alternative() {
#![allow(deprecated)]
let app = clap::clap_app!(claptests =>
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@group difficulty: * ...
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
)
);
let result = app
.clone()
.try_get_matches_from(vec!["bin_name", "--hard", "--easy"]);
assert!(result.is_ok());
let matches = result.expect("Expected to successfully match the given args.");
assert!(matches.is_present("difficulty"));
assert!(matches.is_present("hard"));
assert!(matches.is_present("easy"));
assert!(!matches.is_present("normal"));
let result = app.try_get_matches_from(vec!["bin_name"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}
#[test]
fn group_macro_multiple_invocations() {
#![allow(deprecated)]
let app = clap::clap_app!(claptests =>
(version: "0.1")
(about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>")
(@arg foo: --foo)
(@arg bar: --bar)
(@group difficulty: conflicts_with[foo bar]
(@arg hard: -h --hard "Sets hard mode")
(@arg normal: -n --normal "Sets normal mode")
(@arg easy: -e --easy "Sets easy mode")
)
);
let result = app
.clone()
.try_get_matches_from(vec!["bin_name", "--hard", "--foo"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind, ErrorKind::ArgumentConflict);
let result = app.try_get_matches_from(vec!["bin_name", "--hard", "--bar"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}
#[test]
fn literals() {
#![allow(deprecated)]
clap::clap_app!("clap-tests" =>
(version: "0.1")
(@arg "task-num": -"t-n" --"task-num" +takes_value possible_value["all" 0 1 2]
"Task number")
(@group priority:
(@arg "4": -4 --4 "Sets priority to 4")
(@arg ("5"): -('5') --5 "Sets priority to 5")
(@arg 6: -6 --6 "Sets priority to 6")
)
(@subcommand "view-tasks" =>
(about: "View all tasks"))
(@subcommand 0 =>
(about: "Set everything to zero priority"))
);
}
#[test]
fn multiarg() {
#![allow(deprecated)]
@ -465,31 +289,6 @@ fn multiarg() {
assert_eq!(matches.value_of("multiarg2"), Some("flag-set"));
}
#[test]
fn validator() {
#![allow(deprecated)]
use std::str::FromStr;
fn validate(val: &str) -> Result<u32, String> {
val.parse::<u32>().map_err(|e| e.to_string())
}
let app = clap::clap_app!(claptests =>
(@arg inline: { |val| val.parse::<u16>() })
(@arg func1: { validate })
(@arg func2: { u64::from_str })
);
let matches = app
.try_get_matches_from(&["bin", "12", "34", "56"])
.expect("match failed");
assert_eq!(matches.value_of_t::<u16>("inline").ok(), Some(12));
assert_eq!(matches.value_of_t::<u16>("func1").ok(), Some(34));
assert_eq!(matches.value_of_t::<u16>("func2").ok(), Some(56));
}
mod arg {
#[test]
fn name_explicit() {

View file

@ -1,268 +1,38 @@
#![cfg(feature = "yaml")]
#![allow(deprecated)]
use clap::{load_yaml, App, Arg, ErrorKind, ValueHint};
use clap::{load_yaml, App};
#[test]
fn create_app_from_yaml() {
let yaml = load_yaml!("fixtures/app.yaml");
let _ = App::from_yaml(yaml);
let yml = load_yaml!("app.yml");
App::from_yaml(yml);
}
// TODO: Uncomment to test yaml with 2 spaces https://github.com/chyh1990/yaml-rust/issues/101
// #[test]
// fn create_app_from_yaml_2spaces() {
// let yaml = load_yaml!("fixtures/app_2space.yaml");
// App::from_yaml(yaml);
// }
#[test]
fn help_message() {
let yaml = load_yaml!("fixtures/app.yaml");
let mut app = App::from_yaml(yaml);
let yml = load_yaml!("app.yml");
let mut app = App::from_yaml(yml);
// Generate the full help message!
let _ = app.try_get_matches_from_mut(Vec::<String>::new());
let _ = app.get_matches_from_safe_borrow(Vec::<String>::new());
let mut help_buffer = Vec::new();
app.write_help(&mut help_buffer).unwrap();
let help_string = String::from_utf8(help_buffer).unwrap();
println!("{}", help_string);
assert!(help_string
.contains("-h, --help\n prints help with a nonstandard description\n"));
println!("{}", &help_string);
assert!(help_string.contains("tests positionals with exclusions\n"));
}
#[test]
fn author() {
let yaml = load_yaml!("fixtures/app.yaml");
let mut app = App::from_yaml(yaml);
let yml = load_yaml!("app.yml");
let mut app = App::from_yaml(yml);
// Generate the full help message!
let _ = app.try_get_matches_from_mut(Vec::<String>::new());
let _ = app.get_matches_from_safe_borrow(Vec::<String>::new());
let mut help_buffer = Vec::new();
app.write_help(&mut help_buffer).unwrap();
let help_string = String::from_utf8(help_buffer).unwrap();
println!("{}", &help_string);
assert!(help_string.contains("Kevin K. <kbknapp@gmail.com>"));
}
#[test]
fn app_settings() {
let yaml = load_yaml!("fixtures/app.yaml");
let app = App::from_yaml(yaml);
let m = app.try_get_matches_from(vec!["prog"]);
assert!(m.is_err());
assert_eq!(
m.unwrap_err().kind,
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
);
}
#[test]
#[should_panic = "Unknown AppSetting 'random' found in YAML file for app"]
fn app_setting_invalid() {
let yaml = load_yaml!("fixtures/app_setting_invalid.yaml");
let _ = App::from_yaml(yaml);
}
#[test]
#[should_panic = "Unknown ArgSetting 'random' found in YAML file for arg 'option'"]
fn arg_setting_invalid() {
let yaml = load_yaml!("fixtures/arg_setting_invalid.yaml");
let _ = App::from_yaml(yaml);
}
// ValueHint must be parsed correctly from Yaml
#[test]
fn value_hint() {
let yml = load_yaml!("fixtures/app.yaml");
let app = App::from_yaml(yml);
let arg = app
.get_arguments()
.find(|a| a.get_name() == "value_hint")
.unwrap();
assert_eq!(arg.get_value_hint(), ValueHint::FilePath);
}
#[test]
fn default_value_if_not_triggered_by_argument() {
let yml = load_yaml!("fixtures/app.yaml");
let app = App::from_yaml(yml);
// Fixtures use "other" as value
let matches = app.try_get_matches_from(vec!["prog", "wrong"]).unwrap();
assert!(matches.value_of("positional2").is_none());
}
#[test]
fn default_value_if_triggered_by_matching_argument() {
let yml = load_yaml!("fixtures/app.yaml");
let app = App::from_yaml(yml);
let matches = app.try_get_matches_from(vec!["prog", "other"]).unwrap();
assert_eq!(matches.value_of("positional2").unwrap(), "something");
}
#[test]
fn default_value_if_triggered_by_flag() {
let yml = load_yaml!("fixtures/app.yaml");
let app = App::from_yaml(yml);
let matches = app
.try_get_matches_from(vec!["prog", "--flag", "flagvalue"])
.unwrap();
assert_eq!(matches.value_of("positional2").unwrap(), "some");
}
#[test]
fn default_value_if_triggered_by_flag_and_argument() {
let yml = load_yaml!("fixtures/app.yaml");
let app = App::from_yaml(yml);
let matches = app
.try_get_matches_from(vec!["prog", "--flag", "flagvalue", "other"])
.unwrap();
// First condition triggers, therefore "some"
assert_eq!(matches.value_of("positional2").unwrap(), "some");
}
#[test]
fn yaml_multiple_occurrences() {
let yaml = load_yaml!("fixtures/app.yaml");
let matches = App::from_yaml(yaml)
.try_get_matches_from(vec!["prog", "-vvv"])
.unwrap();
assert_eq!(matches.occurrences_of("verbose"), 3);
}
#[test]
fn yaml_multiple_values() {
let yaml = load_yaml!("fixtures/app.yaml");
let matches = App::from_yaml(yaml)
.try_get_matches_from(vec!["prog", "-s", "aaa", "bbb"])
.unwrap();
assert_eq!(
matches
.values_of("settings")
.unwrap()
.collect::<Vec<&str>>(),
vec!["aaa", "bbb"]
);
}
#[cfg(feature = "regex")]
#[test]
fn regex_with_invalid_string() {
let yml = load_yaml!("fixtures/app_regex.yaml");
let app = App::from_yaml(yml);
let res = app.try_get_matches_from(vec!["prog", "not a proper filter"]);
assert!(res.is_err());
}
#[cfg(feature = "regex")]
#[test]
fn regex_with_valid_string() {
let yml = load_yaml!("fixtures/app_regex.yaml");
let app = App::from_yaml(yml);
let matches = app.try_get_matches_from(vec!["prog", "*.txt"]).unwrap();
assert_eq!(matches.value_of("filter").unwrap(), "*.txt");
}
#[cfg(feature = "regex")]
#[test]
#[should_panic]
fn regex_with_invalid_yaml() {
let yml = load_yaml!("fixtures/app_regex_invalid.yaml");
let _ = App::from_yaml(yml);
}
#[test]
fn extra_fields() {
let yml = load_yaml!("fixtures/extra_fields.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "Unknown setting 'random' in YAML file for arg 'option'"]
fn extra_fields_invalid_arg() {
let yml = load_yaml!("fixtures/extra_fields_invalid_arg.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "Unknown setting 'random' in YAML file for subcommand 'info'"]
fn extra_fields_invalid_app() {
let yml = load_yaml!("fixtures/extra_fields_invalid_app.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "YAML file must be a hash"]
fn app_not_hash() {
let yml = load_yaml!("fixtures/not_hash.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "YAML file must be a hash"]
fn arg_file_not_hash() {
let yml = load_yaml!("fixtures/not_hash.yaml");
let _ = Arg::from_yaml(yml);
}
#[test]
#[should_panic = "Subcommand must be a hash"]
fn subcommand_not_hash() {
let yml = load_yaml!("fixtures/field_not_hash.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "Arg must be a hash"]
fn arg_not_hash() {
let yml = load_yaml!("fixtures/arg_not_hash.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "Subcommand name must be a string"]
fn subcommand_name_not_string() {
let yml = load_yaml!("fixtures/name_not_string.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "Arg name must be a string"]
fn arg_name_not_string() {
let yml = load_yaml!("fixtures/name_not_string.yaml");
let _ = Arg::from_yaml(yml);
}
#[test]
#[should_panic = "App fields must be strings"]
fn app_field_not_string() {
let yml = load_yaml!("fixtures/app_field_not_string.yaml");
let _ = App::from_yaml(yml);
}
#[test]
#[should_panic = "Arg fields must be strings"]
fn arg_field_not_string() {
let yml = load_yaml!("fixtures/arg_field_not_string.yaml");
let _ = Arg::from_yaml(yml);
}
#[test]
fn multiple_groups() {
let yml = load_yaml!("fixtures/multiple_groups.yaml");
let matches = App::from_yaml(yml).try_get_matches_from(&["app", "-a", "-c"]);
eprintln!("{:?}", matches);
assert!(matches.is_ok());
}