WIP: add from_env option

This commit is contained in:
Benjamin Fry 2017-09-29 11:56:53 -07:00
parent 3224e2e1cd
commit f254807c73
11 changed files with 300 additions and 157 deletions

View file

@ -474,6 +474,7 @@ impl<'a> Help<'a> {
Format::None(pv.to_string_lossy()) Format::None(pv.to_string_lossy())
})); }));
} }
// FIXME: add [env::{}: {}] here
} }
if let Some(ref aliases) = a.aliases() { if let Some(ref aliases) = a.aliases() {
debugln!("Help::spec_vals: Found aliases...{:?}", aliases); debugln!("Help::spec_vals: Found aliases...{:?}", aliases);

View file

@ -1796,6 +1796,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
None None
} }
fn from_env(&self) -> Option<&OsString> { None }
fn longest_filter(&self) -> bool { true } fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> { fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.p.meta.aliases { if let Some(ref aliases) = self.p.meta.aliases {

View file

@ -1788,6 +1788,38 @@ impl<'a, 'b> Parser<'a, 'b>
} }
Ok(()) Ok(())
} }
pub fn add_from_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
macro_rules! add_val {
($_self:ident, $a:ident, $m:ident) => {
if let Some(ref val) = $a.v.from_env {
if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) {
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
} else {
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
}
}
};
}
for o in &self.opts {
add_val!(self, o, matcher);
}
for p in self.positionals.values() {
add_val!(self, p, matcher);
}
Ok(())
}
pub fn flags(&self) -> Iter<FlagBuilder<'a, 'b>> { self.flags.iter() } pub fn flags(&self) -> Iter<FlagBuilder<'a, 'b>> { self.flags.iter() }

View file

@ -28,6 +28,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
-> ClapResult<()> { -> ClapResult<()> {
debugln!("Validator::validate;"); debugln!("Validator::validate;");
let mut reqs_validated = false; let mut reqs_validated = false;
self.0.add_from_env(matcher)?;
self.0.add_defaults(matcher)?; self.0.add_defaults(matcher)?;
if let ParseResult::Opt(a) = needs_val_of { if let ParseResult::Opt(a) = needs_val_of {
debugln!("Validator::validate: needs_val_of={:?}", a); debugln!("Validator::validate: needs_val_of={:?}", a);

View file

@ -33,6 +33,7 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display {
fn long_help(&self) -> Option<&'e str>; fn long_help(&self) -> Option<&'e str>;
fn default_val(&self) -> Option<&'e OsStr>; fn default_val(&self) -> Option<&'e OsStr>;
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>>; fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>>;
fn from_env(&self) -> Option<&OsString>;
fn longest_filter(&self) -> bool; fn longest_filter(&self) -> bool;
fn val_terminator(&self) -> Option<&'e str>; fn val_terminator(&self) -> Option<&'e str>;
} }

View file

@ -6,7 +6,7 @@ use std::ffi::{OsString, OsStr};
use osstringext::OsStrExt3; use osstringext::OsStrExt3;
#[cfg(not(target_os="windows"))] #[cfg(not(target_os="windows"))]
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
use std::env;
#[cfg(feature = "yaml")] #[cfg(feature = "yaml")]
use yaml_rust::Yaml; use yaml_rust::Yaml;
@ -128,6 +128,7 @@ impl<'a, 'b> Arg<'a, 'b> {
"default_value" => yaml_to_str!(a, v, default_value), "default_value" => yaml_to_str!(a, v, default_value),
"default_value_if" => yaml_tuple3!(a, v, default_value_if), "default_value_if" => yaml_tuple3!(a, v, default_value_if),
"default_value_ifs" => yaml_tuple3!(a, v, default_value_if), "default_value_ifs" => yaml_tuple3!(a, v, default_value_if),
"from_env" => yaml_to_str!(a, v, from_env),
"value_names" => yaml_vec_or_str!(v, a, value_name), "value_names" => yaml_vec_or_str!(v, a, value_name),
"groups" => yaml_vec_or_str!(v, a, group), "groups" => yaml_vec_or_str!(v, a, group),
"requires" => yaml_vec_or_str!(v, a, requires), "requires" => yaml_vec_or_str!(v, a, requires),
@ -3311,6 +3312,16 @@ impl<'a, 'b> Arg<'a, 'b> {
self self
} }
/// Specifies that if the value is not passed in as an argument, that it should be retrieved
/// from the environment if available. If it is not present in the environment, then default
/// rules will apply.
pub fn from_env<K: AsRef<OsStr>>(mut self, name: K) -> Self {
self.setb(ArgSettings::TakesValue);
self.v.from_env = env::var_os(name);
self
}
/// When set to `true` the help string will be displayed on the line after the argument and /// When set to `true` the help string will be displayed on the line after the argument and
/// indented once. This can be helpful for arguments with very long or complex help messages. /// indented once. This can be helpful for arguments with very long or complex help messages.
/// This can also be helpful for arguments with very long flag names, or many/long value names. /// This can also be helpful for arguments with very long flag names, or many/long value names.

View file

@ -8,20 +8,26 @@ use std::mem;
// Internal // Internal
use Arg; use Arg;
use args::{ArgSettings, Base, Switched, AnyArg, DispOrder}; use args::{AnyArg, ArgSettings, Base, DispOrder, Switched};
use map::{self, VecMap}; use map::{self, VecMap};
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
#[doc(hidden)] #[doc(hidden)]
pub struct FlagBuilder<'n, 'e> pub struct FlagBuilder<'n, 'e>
where 'n: 'e where
'n: 'e,
{ {
pub b: Base<'n, 'e>, pub b: Base<'n, 'e>,
pub s: Switched<'e>, pub s: Switched<'e>,
} }
impl<'n, 'e> FlagBuilder<'n, 'e> { impl<'n, 'e> FlagBuilder<'n, 'e> {
pub fn new(name: &'n str) -> Self { FlagBuilder { b: Base::new(name), ..Default::default() } } pub fn new(name: &'n str) -> Self {
FlagBuilder {
b: Base::new(name),
..Default::default()
}
}
} }
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> { impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
@ -83,10 +89,12 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
None None
} }
fn from_env(&self) -> Option<&OsString> { None }
fn longest_filter(&self) -> bool { self.s.long.is_some() } fn longest_filter(&self) -> bool { self.s.long.is_some() }
fn aliases(&self) -> Option<Vec<&'e str>> { fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.s.aliases { if let Some(ref aliases) = self.s.aliases {
let vis_aliases: Vec<_> = aliases.iter() let vis_aliases: Vec<_> = aliases
.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None }) .filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect(); .collect();
if vis_aliases.is_empty() { if vis_aliases.is_empty() {
@ -105,9 +113,7 @@ impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> {
} }
impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> { impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> {
fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { self.b == other.b }
self.b == other.b
}
} }
#[cfg(test)] #[cfg(test)]
@ -142,8 +148,12 @@ mod test {
fn flagbuilder_display_multiple_aliases() { fn flagbuilder_display_multiple_aliases() {
let mut f = FlagBuilder::new("flg"); let mut f = FlagBuilder::new("flg");
f.s.short = Some('f'); f.s.short = Some('f');
f.s.aliases = f.s.aliases = Some(vec![
Some(vec![("alias_not_visible", false), ("f2", true), ("f3", true), ("f4", true)]); ("alias_not_visible", false),
("f2", true),
("f3", true),
("f4", true),
]);
assert_eq!(&*format!("{}", f), "-f"); assert_eq!(&*format!("{}", f), "-f");
} }
} }

View file

@ -6,14 +6,15 @@ use std::ffi::{OsStr, OsString};
use std::mem; use std::mem;
// Internal // Internal
use args::{ArgSettings, AnyArg, Base, Switched, Valued, Arg, DispOrder}; use args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued};
use map::{self, VecMap}; use map::{self, VecMap};
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
#[doc(hidden)] #[doc(hidden)]
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct OptBuilder<'n, 'e> pub struct OptBuilder<'n, 'e>
where 'n: 'e where
'n: 'e,
{ {
pub b: Base<'n, 'e>, pub b: Base<'n, 'e>,
pub s: Switched<'e>, pub s: Switched<'e>,
@ -21,7 +22,12 @@ pub struct OptBuilder<'n, 'e>
} }
impl<'n, 'e> OptBuilder<'n, 'e> { impl<'n, 'e> OptBuilder<'n, 'e> {
pub fn new(name: &'n str) -> Self { OptBuilder { b: Base::new(name), ..Default::default() } } pub fn new(name: &'n str) -> Self {
OptBuilder {
b: Base::new(name),
..Default::default()
}
}
} }
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> { impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> {
@ -85,14 +91,16 @@ impl<'n, 'e> Display for OptBuilder<'n, 'e> {
write!(f, "...")?; write!(f, "...")?;
} }
} else { } else {
write!(f, write!(
f,
"<{}>{}", "<{}>{}",
self.b.name, self.b.name,
if self.is_set(ArgSettings::Multiple) { if self.is_set(ArgSettings::Multiple) {
"..." "..."
} else { } else {
"" ""
})?; }
)?;
} }
Ok(()) Ok(())
@ -132,10 +140,12 @@ impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
} }
fn from_env(&self) -> Option<&OsString> { self.v.from_env.as_ref() }
fn longest_filter(&self) -> bool { true } fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> { fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.s.aliases { if let Some(ref aliases) = self.s.aliases {
let vis_aliases: Vec<_> = aliases.iter() let vis_aliases: Vec<_> = aliases
.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None }) .filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect(); .collect();
if vis_aliases.is_empty() { if vis_aliases.is_empty() {
@ -154,9 +164,7 @@ impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> {
} }
impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> { impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> {
fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool { fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool { self.b == other.b }
self.b == other.b
}
} }
#[cfg(test)] #[cfg(test)]
@ -214,8 +222,12 @@ mod test {
fn optbuilder_display_multiple_aliases() { fn optbuilder_display_multiple_aliases() {
let mut o = OptBuilder::new("opt"); let mut o = OptBuilder::new("opt");
o.s.long = Some("option"); o.s.long = Some("option");
o.s.aliases = o.s.aliases = Some(vec![
Some(vec![("als_not_visible", false), ("als2", true), ("als3", true), ("als4", true)]); ("als_not_visible", false),
("als2", true),
("als3", true),
("als4", true),
]);
assert_eq!(&*format!("{}", o), "--option <opt>"); assert_eq!(&*format!("{}", o), "--option <opt>");
} }
} }

View file

@ -8,7 +8,7 @@ use std::mem;
// Internal // Internal
use Arg; use Arg;
use args::{ArgSettings, Base, Valued, AnyArg, DispOrder}; use args::{AnyArg, ArgSettings, Base, DispOrder, Valued};
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
use map::{self, VecMap}; use map::{self, VecMap};
@ -16,7 +16,8 @@ use map::{self, VecMap};
#[doc(hidden)] #[doc(hidden)]
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct PosBuilder<'n, 'e> pub struct PosBuilder<'n, 'e>
where 'n: 'e where
'n: 'e,
{ {
pub b: Base<'n, 'e>, pub b: Base<'n, 'e>,
pub v: Valued<'n, 'e>, pub v: Valued<'n, 'e>,
@ -39,7 +40,8 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
index: idx, index: idx,
}; };
if a.v.max_vals.is_some() || a.v.min_vals.is_some() || if a.v.max_vals.is_some() || a.v.min_vals.is_some() ||
(a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1) { (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
{
pb.b.settings.set(ArgSettings::Multiple); pb.b.settings.set(ArgSettings::Multiple);
} }
pb pb
@ -47,7 +49,8 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
pub fn from_arg(mut a: Arg<'n, 'e>, idx: u64) -> Self { pub fn from_arg(mut a: Arg<'n, 'e>, idx: u64) -> Self {
if a.v.max_vals.is_some() || a.v.min_vals.is_some() || if a.v.max_vals.is_some() || a.v.min_vals.is_some() ||
(a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1) { (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
{
a.b.settings.set(ArgSettings::Multiple); a.b.settings.set(ArgSettings::Multiple);
} }
PosBuilder { PosBuilder {
@ -74,11 +77,13 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
if let Some(ref names) = self.v.val_names { if let Some(ref names) = self.v.val_names {
debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names); debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names);
if names.len() > 1 { if names.len() > 1 {
Cow::Owned(names Cow::Owned(
.values() names
.map(|n| format!("<{}>", n)) .values()
.collect::<Vec<_>>() .map(|n| format!("<{}>", n))
.join(" ")) .collect::<Vec<_>>()
.join(" "),
)
} else { } else {
Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG)) Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG))
} }
@ -92,17 +97,21 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
impl<'n, 'e> Display for PosBuilder<'n, 'e> { impl<'n, 'e> Display for PosBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result { fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(ref names) = self.v.val_names { if let Some(ref names) = self.v.val_names {
write!(f, write!(
f,
"{}", "{}",
names names
.values() .values()
.map(|n| format!("<{}>", n)) .map(|n| format!("<{}>", n))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(" "))?; .join(" ")
)?;
} else { } else {
write!(f, "<{}>", self.b.name)?; write!(f, "<{}>", self.b.name)?;
} }
if self.b.settings.is_set(ArgSettings::Multiple) && (self.v.val_names.is_none() || self.v.val_names.as_ref().unwrap().len() == 1) { if self.b.settings.is_set(ArgSettings::Multiple) &&
(self.v.val_names.is_none() || self.v.val_names.as_ref().unwrap().len() == 1)
{
write!(f, "...")?; write!(f, "...")?;
} }
@ -143,6 +152,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
} }
fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val } fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
fn from_env(&self) -> Option<&OsString> { self.v.from_env.as_ref() }
fn longest_filter(&self) -> bool { true } fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> { None } fn aliases(&self) -> Option<Vec<&'e str>> { None }
} }

View file

@ -8,7 +8,8 @@ use Arg;
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
#[derive(Clone)] #[derive(Clone)]
pub struct Valued<'a, 'b> pub struct Valued<'a, 'b>
where 'a: 'b where
'a: 'b,
{ {
pub possible_vals: Option<Vec<&'b str>>, pub possible_vals: Option<Vec<&'b str>>,
pub val_names: Option<VecMap<&'b str>>, pub val_names: Option<VecMap<&'b str>>,
@ -20,6 +21,7 @@ pub struct Valued<'a, 'b>
pub val_delim: Option<char>, pub val_delim: Option<char>,
pub default_val: Option<&'b OsStr>, pub default_val: Option<&'b OsStr>,
pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>, pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>,
pub from_env: Option<OsString>,
pub terminator: Option<&'b str>, pub terminator: Option<&'b str>,
} }
@ -36,6 +38,7 @@ impl<'n, 'e> Default for Valued<'n, 'e> {
val_delim: None, val_delim: None,
default_val: None, default_val: None,
default_vals_ifs: None, default_vals_ifs: None,
from_env: None,
terminator: None, terminator: None,
} }
} }

View file

@ -8,8 +8,9 @@ use clap::{App, Arg, ErrorKind};
#[test] #[test]
fn opts() { fn opts() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("-o [opt] 'some opt'") .arg(
.default_value("default")) Arg::from_usage("-o [opt] 'some opt'").default_value("default"),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -20,8 +21,9 @@ fn opts() {
#[test] #[test]
fn opt_user_override() { fn opt_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'") .arg(
.default_value("default")) Arg::from_usage("--opt [FILE] 'some arg'").default_value("default"),
)
.get_matches_from_safe(vec!["", "--opt", "value"]); .get_matches_from_safe(vec!["", "--opt", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -32,8 +34,7 @@ fn opt_user_override() {
#[test] #[test]
fn positionals() { fn positionals() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("[arg] 'some opt'") .arg(Arg::from_usage("[arg] 'some opt'").default_value("default"))
.default_value("default"))
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -44,8 +45,7 @@ fn positionals() {
#[test] #[test]
fn positional_user_override() { fn positional_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("[arg] 'some arg'") .arg(Arg::from_usage("[arg] 'some arg'").default_value("default"))
.default_value("default"))
.get_matches_from_safe(vec!["", "value"]); .get_matches_from_safe(vec!["", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -59,10 +59,11 @@ fn positional_user_override() {
fn osstr_opts() { fn osstr_opts() {
use std::ffi::OsStr; use std::ffi::OsStr;
let expected = OsStr::new("default"); let expected = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("-o [opt] 'some opt'") .arg(
.default_value_os(expected)) Arg::from_usage("-o [opt] 'some opt'").default_value_os(expected),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -76,8 +77,9 @@ fn osstr_opt_user_override() {
let default = OsStr::new("default"); let default = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'") .arg(
.default_value_os(default)) Arg::from_usage("--opt [FILE] 'some arg'").default_value_os(default),
)
.get_matches_from_safe(vec!["", "--opt", "value"]); .get_matches_from_safe(vec!["", "--opt", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -91,8 +93,9 @@ fn osstr_positionals() {
let expected = OsStr::new("default"); let expected = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("[arg] 'some opt'") .arg(
.default_value_os(expected)) Arg::from_usage("[arg] 'some opt'").default_value_os(expected),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -106,8 +109,9 @@ fn osstr_positional_user_override() {
let default = OsStr::new("default"); let default = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value_os(default)) Arg::from_usage("[arg] 'some arg'").default_value_os(default),
)
.get_matches_from_safe(vec!["", "value"]); .get_matches_from_safe(vec!["", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -115,14 +119,17 @@ fn osstr_positional_user_override() {
assert_eq!(m.value_of("arg").unwrap(), "value"); assert_eq!(m.value_of("arg").unwrap(), "value");
} }
// --- Default if arg is present // --- Default if arg is present
#[test] #[test]
fn default_if_arg_present_no_default() { fn default_if_arg_present_no_default() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
.default_value_if("opt", None, "default")) "opt",
None,
"default",
))
.get_matches_from_safe(vec!["", "--opt", "some"]); .get_matches_from_safe(vec!["", "--opt", "some"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -133,9 +140,12 @@ fn default_if_arg_present_no_default() {
#[test] #[test]
fn default_if_arg_present_no_default_user_override() { fn default_if_arg_present_no_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
.default_value_if("opt", None, "default")) "opt",
None,
"default",
))
.get_matches_from_safe(vec!["", "--opt", "some", "other"]); .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -146,10 +156,12 @@ fn default_if_arg_present_no_default_user_override() {
#[test] #[test]
fn default_if_arg_present_no_arg_with_default() { fn default_if_arg_present_no_arg_with_default() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", None, "default")) .default_value("first")
.default_value_if("opt", None, "default"),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -160,10 +172,12 @@ fn default_if_arg_present_no_arg_with_default() {
#[test] #[test]
fn default_if_arg_present_with_default() { fn default_if_arg_present_with_default() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", None, "default")) .default_value("first")
.default_value_if("opt", None, "default"),
)
.get_matches_from_safe(vec!["", "--opt", "some"]); .get_matches_from_safe(vec!["", "--opt", "some"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -174,10 +188,12 @@ fn default_if_arg_present_with_default() {
#[test] #[test]
fn default_if_arg_present_with_default_user_override() { fn default_if_arg_present_with_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", None, "default")) .default_value("first")
.default_value_if("opt", None, "default"),
)
.get_matches_from_safe(vec!["", "--opt", "some", "other"]); .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -188,10 +204,12 @@ fn default_if_arg_present_with_default_user_override() {
#[test] #[test]
fn default_if_arg_present_no_arg_with_default_user_override() { fn default_if_arg_present_no_arg_with_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", None, "default")) .default_value("first")
.default_value_if("opt", None, "default"),
)
.get_matches_from_safe(vec!["", "other"]); .get_matches_from_safe(vec!["", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -204,9 +222,12 @@ fn default_if_arg_present_no_arg_with_default_user_override() {
#[test] #[test]
fn default_if_arg_present_with_value_no_default() { fn default_if_arg_present_with_value_no_default() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
.default_value_if("opt", Some("value"), "default")) "opt",
Some("value"),
"default",
))
.get_matches_from_safe(vec!["", "--opt", "value"]); .get_matches_from_safe(vec!["", "--opt", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -217,9 +238,12 @@ fn default_if_arg_present_with_value_no_default() {
#[test] #[test]
fn default_if_arg_present_with_value_no_default_fail() { fn default_if_arg_present_with_value_no_default_fail() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
.default_value_if("opt", Some("value"), "default")) "opt",
Some("value"),
"default",
))
.get_matches_from_safe(vec!["", "--opt", "other"]); .get_matches_from_safe(vec!["", "--opt", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -230,9 +254,12 @@ fn default_if_arg_present_with_value_no_default_fail() {
#[test] #[test]
fn default_if_arg_present_with_value_no_default_user_override() { fn default_if_arg_present_with_value_no_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
.default_value_if("opt", Some("some"), "default")) "opt",
Some("some"),
"default",
))
.get_matches_from_safe(vec!["", "--opt", "some", "other"]); .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -243,10 +270,12 @@ fn default_if_arg_present_with_value_no_default_user_override() {
#[test] #[test]
fn default_if_arg_present_with_value_no_arg_with_default() { fn default_if_arg_present_with_value_no_arg_with_default() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", Some("some"), "default")) .default_value("first")
.default_value_if("opt", Some("some"), "default"),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -257,10 +286,12 @@ fn default_if_arg_present_with_value_no_arg_with_default() {
#[test] #[test]
fn default_if_arg_present_with_value_no_arg_with_default_fail() { fn default_if_arg_present_with_value_no_arg_with_default_fail() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", Some("some"), "default")) .default_value("first")
.default_value_if("opt", Some("some"), "default"),
)
.get_matches_from_safe(vec!["", "--opt", "other"]); .get_matches_from_safe(vec!["", "--opt", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -271,10 +302,12 @@ fn default_if_arg_present_with_value_no_arg_with_default_fail() {
#[test] #[test]
fn default_if_arg_present_with_value_with_default() { fn default_if_arg_present_with_value_with_default() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", Some("some"), "default")) .default_value("first")
.default_value_if("opt", Some("some"), "default"),
)
.get_matches_from_safe(vec!["", "--opt", "some"]); .get_matches_from_safe(vec!["", "--opt", "some"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -285,10 +318,12 @@ fn default_if_arg_present_with_value_with_default() {
#[test] #[test]
fn default_if_arg_present_with_value_with_default_user_override() { fn default_if_arg_present_with_value_with_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", Some("some"), "default")) .default_value("first")
.default_value_if("opt", Some("some"), "default"),
)
.get_matches_from_safe(vec!["", "--opt", "some", "other"]); .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -299,10 +334,12 @@ fn default_if_arg_present_with_value_with_default_user_override() {
#[test] #[test]
fn default_if_arg_present_no_arg_with_value_with_default_user_override() { fn default_if_arg_present_no_arg_with_value_with_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", Some("some"), "default")) .default_value("first")
.default_value_if("opt", Some("some"), "default"),
)
.get_matches_from_safe(vec!["", "other"]); .get_matches_from_safe(vec!["", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -313,10 +350,12 @@ fn default_if_arg_present_no_arg_with_value_with_default_user_override() {
#[test] #[test]
fn default_if_arg_present_no_arg_with_value_with_default_user_override_fail() { fn default_if_arg_present_no_arg_with_value_with_default_user_override_fail() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_if("opt", Some("some"), "default")) .default_value("first")
.default_value_if("opt", Some("some"), "default"),
)
.get_matches_from_safe(vec!["", "--opt", "value", "other"]); .get_matches_from_safe(vec!["", "--opt", "value", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -329,14 +368,13 @@ fn default_if_arg_present_no_arg_with_value_with_default_user_override_fail() {
#[test] #[test]
fn default_ifs_arg_present() { fn default_ifs_arg_present() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("--flag 'some arg'")) .arg(Arg::from_usage("--flag 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_ifs(&[ .default_value("first")
("opt", Some("some"), "default"), .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]),
("flag", None, "flg"), )
]))
.get_matches_from_safe(vec!["", "--flag"]); .get_matches_from_safe(vec!["", "--flag"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -347,14 +385,13 @@ fn default_ifs_arg_present() {
#[test] #[test]
fn default_ifs_arg_present_user_override() { fn default_ifs_arg_present_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("--flag 'some arg'")) .arg(Arg::from_usage("--flag 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_ifs(&[ .default_value("first")
("opt", Some("some"), "default"), .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]),
("flag", None, "flg"), )
]))
.get_matches_from_safe(vec!["", "--flag", "value"]); .get_matches_from_safe(vec!["", "--flag", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -365,14 +402,13 @@ fn default_ifs_arg_present_user_override() {
#[test] #[test]
fn default_ifs_arg_present_order() { fn default_ifs_arg_present_order() {
let r = App::new("df") let r = App::new("df")
.arg( Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg( Arg::from_usage("--flag 'some arg'")) .arg(Arg::from_usage("--flag 'some arg'"))
.arg( Arg::from_usage("[arg] 'some arg'") .arg(
.default_value("first") Arg::from_usage("[arg] 'some arg'")
.default_value_ifs(&[ .default_value("first")
("opt", Some("some"), "default"), .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]),
("flag", None, "flg"), )
]))
.get_matches_from_safe(vec!["", "--opt=some", "--flag"]); .get_matches_from_safe(vec!["", "--opt=some", "--flag"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -386,19 +422,25 @@ fn conditional_reqs_fail() {
.version("1.0") .version("1.0")
.author("F0x06") .author("F0x06")
.about("Arg test") .about("Arg test")
.arg(Arg::with_name("target") .arg(
.takes_value(true) Arg::with_name("target")
.default_value("file") .takes_value(true)
.possible_values(&["file", "stdout"]) .default_value("file")
.long("target")) .possible_values(&["file", "stdout"])
.arg(Arg::with_name("input") .long("target"),
.takes_value(true) )
.required(true) .arg(
.long("input")) Arg::with_name("input")
.arg(Arg::with_name("output") .takes_value(true)
.takes_value(true) .required(true)
.required_if("target", "file") .long("input"),
.long("output")) )
.arg(
Arg::with_name("output")
.takes_value(true)
.required_if("target", "file")
.long("output"),
)
.get_matches_from_safe(vec!["test", "--input", "some"]); .get_matches_from_safe(vec!["test", "--input", "some"]);
assert!(m.is_err()); assert!(m.is_err());
@ -411,19 +453,25 @@ fn conditional_reqs_pass() {
.version("1.0") .version("1.0")
.author("F0x06") .author("F0x06")
.about("Arg test") .about("Arg test")
.arg(Arg::with_name("target") .arg(
.takes_value(true) Arg::with_name("target")
.default_value("file") .takes_value(true)
.possible_values(&["file", "stdout"]) .default_value("file")
.long("target")) .possible_values(&["file", "stdout"])
.arg(Arg::with_name("input") .long("target"),
.takes_value(true) )
.required(true) .arg(
.long("input")) Arg::with_name("input")
.arg(Arg::with_name("output") .takes_value(true)
.takes_value(true) .required(true)
.required_if("target", "file") .long("input"),
.long("output")) )
.arg(
Arg::with_name("output")
.takes_value(true)
.required_if("target", "file")
.long("output"),
)
.get_matches_from_safe(vec!["test", "--input", "some", "--output", "other"]); .get_matches_from_safe(vec!["test", "--input", "some", "--output", "other"]);
assert!(m.is_ok()); assert!(m.is_ok());
@ -431,3 +479,16 @@ fn conditional_reqs_pass() {
assert_eq!(m.value_of("output"), Some("other")); assert_eq!(m.value_of("output"), Some("other"));
assert_eq!(m.value_of("input"), Some("some")); assert_eq!(m.value_of("input"), Some("some"));
} }
#[test]
fn from_env_no_default() {
std::env::set_var("CLP_TEST_ENV", "from_env");
let r = App::new("df")
.arg(Arg::from_usage("[arg] 'some opt'").from_env("CLP_TEST_ENV"))
.get_matches_from_safe(vec![""]);
assert!(r.is_ok());
let m = r.unwrap();
// assert!(m.is_present("arg")); // TODO: should this be true?
assert_eq!(m.value_of("arg").unwrap(), "from_env");
}