Skip to content

Commit e08fdfb

Browse files
committed
Auto merge of #423 - kbknapp:issue-418, r=kbknapp
Issue 418
2 parents e76d751 + b37c010 commit e08fdfb

File tree

9 files changed

+164
-35
lines changed

9 files changed

+164
-35
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
<a name="v2.1.0"></a>
2+
## v2.1.0 (2016-02-10)
3+
4+
5+
#### Features
6+
7+
* **Defult Values:** adds support for default values in args ([73211952](https://github.com/kbknapp/clap-rs/commit/73211952964a79d97b434dd567e6d7d34be7feb5), closes [#418](https://github.com/kbknapp/clap-rs/issues/418))
8+
9+
#### Documentation
10+
11+
* **Default Values:** adds better examples and notes for default values ([9facd74f](https://github.com/kbknapp/clap-rs/commit/9facd74f843ef3807c5d35259558a344e6c25905))
12+
13+
114
<a name="v2.0.6"></a>
215
### v2.0.6 (2016-02-09)
316

Cargo.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
name = "clap"
4-
version = "2.0.6"
4+
version = "2.1.0"
55
authors = ["Kevin K. <[email protected]>"]
66
exclude = ["examples/*", "clap-tests/*", "tests/*", "benches/*", "*.png", "clap-perf/*"]
77
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
@@ -14,10 +14,10 @@ keywords = ["argument", "command", "arg", "parser", "parse"]
1414
[dependencies]
1515
bitflags = "~0.4"
1616
vec_map = "~0.4"
17-
ansi_term = { version = "~0.7", optional = true }
18-
strsim = { version = "~0.4.0", optional = true }
19-
yaml-rust = { version = "~0.3", optional = true }
20-
clippy = { version = "~0.0.37", optional = true }
17+
ansi_term = { version = "~0.7.2", optional = true }
18+
strsim = { version = "~0.4.0", optional = true }
19+
yaml-rust = { version = "~0.3", optional = true }
20+
clippy = { version = "~0.0.41", optional = true }
2121

2222
[features]
2323
default = ["suggestions", "color"]

src/app/parser.rs

+39-21
Original file line numberDiff line numberDiff line change
@@ -171,15 +171,15 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
171171
if group.required {
172172
self.required.push(group.name.into());
173173
if let Some(ref reqs) = group.requires {
174-
self.required.extend(reqs);
174+
self.required.extend_from_slice(reqs);
175175
}
176176
if let Some(ref bl) = group.conflicts {
177-
self.blacklist.extend(bl);
177+
self.blacklist.extend_from_slice(bl);
178178
}
179179
}
180180
let mut found = false;
181181
if let Some(ref mut grp) = self.groups.get_mut(&group.name) {
182-
grp.args.extend(&group.args);
182+
grp.args.extend_from_slice(&group.args);
183183
grp.requires = group.requires.clone();
184184
grp.conflicts = group.conflicts.clone();
185185
grp.required = group.required;
@@ -216,6 +216,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
216216
self.required.iter()
217217
}
218218

219+
#[cfg_attr(feature = "lints", allow(for_kv_map))]
219220
pub fn get_required_from(&self,
220221
reqs: &[&'a str],
221222
matcher: Option<&ArgMatcher<'a>>)
@@ -535,6 +536,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
535536
}
536537
}
537538

539+
try!(self.add_defaults(matcher));
538540
try!(self.validate_blacklist(matcher));
539541
try!(self.validate_num_args(matcher));
540542
matcher.usage(self.create_usage(&[]));
@@ -730,13 +732,9 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
730732
let mut args = vec![];
731733

732734
for n in &self.groups.get(group).unwrap().args {
733-
if self.flags.iter().any(|f| &f.name == n) {
734-
args.push(*n);
735-
} else if self.opts.iter().any(|o| &o.name == n) {
736-
args.push(*n);
737-
} else if self.groups.contains_key(&**n) {
735+
if self.groups.contains_key(&*n) {
738736
g_vec.push(*n);
739-
} else if self.positionals.values().any(|p| &p.name == n) {
737+
} else {
740738
args.push(*n);
741739
}
742740
}
@@ -1237,11 +1235,10 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
12371235
fn _validate_blacklist_required<A>(&self, a: &A, matcher: &ArgMatcher) -> bool where A: AnyArg<'a, 'b> {
12381236
if let Some(bl) = a.blacklist() {
12391237
for n in bl.iter() {
1240-
if matcher.contains(n) {
1241-
return true;
1242-
} else if self.groups
1243-
.get(n)
1244-
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
1238+
if matcher.contains(n)
1239+
|| self.groups
1240+
.get(n)
1241+
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
12451242
return true;
12461243
}
12471244
}
@@ -1262,13 +1259,13 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
12621259
.filter(|o| o.long.is_some() && o.long.unwrap() == name)
12631260
.next() {
12641261
self.groups_for_arg(&*opt.name).and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
1265-
matcher.insert(&*opt.name.clone());
1262+
matcher.insert(&*opt.name);
12661263
} else if let Some(flg) = self.flags
12671264
.iter()
12681265
.filter(|f| f.long.is_some() && f.long.unwrap() == name)
12691266
.next() {
12701267
self.groups_for_arg(&*flg.name).and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
1271-
matcher.insert(&*flg.name.clone());
1268+
matcher.insert(&*flg.name);
12721269
}
12731270
}
12741271

@@ -1340,7 +1337,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
13401337
// args, and requirements
13411338
fn smart_usage(&self, usage: &mut String, used: &[&str]) {
13421339
let mut hs: Vec<&str> = self.required().map(|s| &**s).collect();
1343-
hs.extend(used);
1340+
hs.extend_from_slice(used);
13441341
let r_string = self.get_required_from(&hs, None)
13451342
.iter()
13461343
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
@@ -1378,6 +1375,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
13781375
self.write_help(&mut buf_w)
13791376
}
13801377

1378+
#[cfg_attr(feature = "lints", allow(for_kv_map))]
13811379
pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
13821380
if let Some(h) = self.meta.help_str {
13831381
return writeln!(w, "{}", h).map_err(Error::from);
@@ -1465,19 +1463,21 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
14651463
} else {
14661464
if flags {
14671465
try!(write!(w, "\nFLAGS:\n"));
1468-
for (_, f) in self.flags.iter()
1466+
for f in self.flags.iter()
14691467
.filter(|f| !f.settings.is_set(ArgSettings::Hidden))
14701468
.map(|f| (f.name, f))
1471-
.collect::<BTreeMap<_, _>>() {
1469+
.collect::<BTreeMap<_, _>>()
1470+
.values() {
14721471
try!(f.write_help(w, tab, longest));
14731472
}
14741473
}
14751474
if opts {
14761475
try!(write!(w, "\nOPTIONS:\n"));
1477-
for (_, o) in self.opts.iter()
1476+
for o in self.opts.iter()
14781477
.filter(|o| !o.settings.is_set(ArgSettings::Hidden))
14791478
.map(|o| (o.name, o))
1480-
.collect::<BTreeMap<_, _>>() {
1479+
.collect::<BTreeMap<_, _>>()
1480+
.values() {
14811481
try!(o.write_help(w, tab, longest_opt, self.is_set(AppSettings::HidePossibleValuesInHelp)));
14821482
}
14831483
}
@@ -1518,4 +1518,22 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
15181518
}
15191519
w.flush().map_err(Error::from)
15201520
}
1521+
1522+
fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
1523+
macro_rules! add_val {
1524+
($_self:ident, $a:ident, $m:ident) => {
1525+
if $m.get($a.name).is_none() {
1526+
try!($_self.add_val_to_arg($a, OsStr::new($a.default_val.as_ref().unwrap()), $m));
1527+
arg_post_processing!($_self, $a, $m);
1528+
}
1529+
};
1530+
}
1531+
for o in self.opts.iter().filter(|o| o.default_val.is_some()) {
1532+
add_val!(self, o, matcher);
1533+
}
1534+
for p in self.positionals.values().filter(|p| p.default_val.is_some()) {
1535+
add_val!(self, p, matcher);
1536+
}
1537+
Ok(())
1538+
}
15211539
}

src/args/arg.rs

+46-8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ pub struct Arg<'a, 'b> where 'a: 'b {
6666
pub settings: ArgFlags,
6767
#[doc(hidden)]
6868
pub val_delim: Option<char>,
69+
#[doc(hidden)]
70+
pub default_val: Option<&'a str>,
6971
}
7072

7173
impl<'a, 'b> Default for Arg<'a, 'b> {
@@ -88,6 +90,7 @@ impl<'a, 'b> Default for Arg<'a, 'b> {
8890
overrides: None,
8991
settings: ArgFlags::new(),
9092
val_delim: Some(','),
93+
default_val: None,
9194
}
9295
}
9396
}
@@ -1087,14 +1090,38 @@ impl<'a, 'b> Arg<'a, 'b> {
10871090
self
10881091
}
10891092

1090-
#[doc(hidden)]
1091-
pub fn setb(&mut self, s: ArgSettings) {
1092-
self.settings.set(s);
1093-
}
1094-
1095-
#[doc(hidden)]
1096-
pub fn unsetb(&mut self, s: ArgSettings) {
1097-
self.settings.unset(s);
1093+
/// Specifies the value of the argument when *not* specified at runtime.
1094+
///
1095+
/// **NOTE:** If the user *does not* use this argument at runtime, `ArgMatches::occurrences_of`
1096+
/// will return `0` even though the `value_of` will return the default specified.
1097+
///
1098+
/// **NOTE:** If the user *does not* use this argument at runtime `ArgMatches::is_present` will
1099+
/// still return `true`. If you wish to determine whether the argument was used at runtime or
1100+
/// not, consider `ArgMatches::occurrences_of` which will return `0` if the argument was *not*
1101+
/// used at runtmie.
1102+
///
1103+
/// **NOTE:** This implicitly sets `Arg::takes_value(true)`.
1104+
///
1105+
/// # Examples
1106+
///
1107+
/// ```rust
1108+
/// # use clap::{App, Arg};
1109+
/// let m = App::new("defvals")
1110+
/// .arg(Arg::with_name("opt")
1111+
/// .long("myopt")
1112+
/// .default_value("myval"))
1113+
/// .get_matches_from(vec![
1114+
/// "defvals"
1115+
/// ]);
1116+
///
1117+
/// assert_eq!(m.value_of("opt"), Some("myval"));
1118+
/// assert!(m.is_present("opt"));
1119+
/// assert_eq!(m.occurrences_of("opt"), 0);
1120+
/// ```
1121+
pub fn default_value(mut self, val: &'a str) -> Self {
1122+
self.setb(ArgSettings::TakesValue);
1123+
self.default_val = Some(val);
1124+
self
10981125
}
10991126

11001127
/// Checks if one of the `ArgSettings` settings is set for the argument
@@ -1113,6 +1140,16 @@ impl<'a, 'b> Arg<'a, 'b> {
11131140
self.unsetb(s);
11141141
self
11151142
}
1143+
1144+
#[doc(hidden)]
1145+
pub fn setb(&mut self, s: ArgSettings) {
1146+
self.settings.set(s);
1147+
}
1148+
1149+
#[doc(hidden)]
1150+
pub fn unsetb(&mut self, s: ArgSettings) {
1151+
self.settings.unset(s);
1152+
}
11161153
}
11171154

11181155
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>>
@@ -1136,6 +1173,7 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>>
11361173
overrides: a.overrides.clone(),
11371174
settings: a.settings.clone(),
11381175
val_delim: a.val_delim,
1176+
default_val: a.default_val,
11391177
}
11401178
}
11411179
}

src/args/arg_builder/option.rs

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct OptBuilder<'n, 'e> {
2626
pub overrides: Option<Vec<&'e str>>,
2727
pub settings: ArgFlags,
2828
pub val_delim: Option<char>,
29+
pub default_val: Option<&'n str>,
2930
}
3031

3132
impl<'n, 'e> Default for OptBuilder<'n, 'e> {
@@ -46,6 +47,7 @@ impl<'n, 'e> Default for OptBuilder<'n, 'e> {
4647
overrides: None,
4748
settings: ArgFlags::new(),
4849
val_delim: Some(','),
50+
default_val: None,
4951
}
5052
}
5153
}
@@ -79,6 +81,7 @@ impl<'n, 'e> OptBuilder<'n, 'e> {
7981
requires: a.requires.clone(),
8082
possible_vals: a.possible_vals.clone(),
8183
settings: a.settings.clone(),
84+
default_val: a.default_val,
8285
..Default::default()
8386
};
8487
if let Some(ref vec) = ob.val_names {
@@ -159,6 +162,9 @@ impl<'n, 'e> OptBuilder<'n, 'e> {
159162
} else {
160163
try!(write!(w, "{}", h));
161164
}
165+
if let Some(ref pv) = self.default_val {
166+
try!(write!(w, " [default: {}]", pv));
167+
}
162168
if !skip_pv {
163169
if let Some(ref pv) = self.possible_vals {
164170
try!(write!(w, " [values: {}]", pv.join(", ")));

src/args/arg_builder/positional.rs

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct PosBuilder<'n, 'e> {
2626
pub overrides: Option<Vec<&'e str>>,
2727
pub settings: ArgFlags,
2828
pub val_delim: Option<char>,
29+
pub default_val: Option<&'n str>,
2930
}
3031

3132
impl<'n, 'e> Default for PosBuilder<'n, 'e> {
@@ -45,6 +46,7 @@ impl<'n, 'e> Default for PosBuilder<'n, 'e> {
4546
overrides: None,
4647
settings: ArgFlags::new(),
4748
val_delim: Some(','),
49+
default_val: None,
4850
}
4951
}
5052
}
@@ -80,6 +82,7 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
8082
help: a.help,
8183
val_delim: a.val_delim,
8284
settings: a.settings.clone(),
85+
default_val: a.default_val,
8386
..Default::default()
8487
};
8588
if a.max_vals.is_some()
@@ -117,6 +120,9 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
117120
} else {
118121
try!(write!(w, "{}", h));
119122
}
123+
if let Some(ref pv) = self.default_val {
124+
try!(write!(w, " [default: {}]", pv));
125+
}
120126
if !skip_pv {
121127
if let Some(ref pv) = self.possible_vals {
122128
try!(write!(w, " [values: {}]", pv.join(", ")));

src/args/group.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ impl<'a> Debug for ArgGroup<'a> {
298298
impl<'a, 'z> From<&'z ArgGroup<'a>> for ArgGroup<'a> {
299299
fn from(g: &'z ArgGroup<'a>) -> Self {
300300
ArgGroup {
301-
name: g.name.clone(),
301+
name: g.name,
302302
required: g.required,
303303
args: g.args.clone(),
304304
requires: g.requires.clone(),

tests/opts.rs

+24
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,27 @@ fn opts_using_mixed2() {
133133
assert!(m.is_present("color"));
134134
assert_eq!(m.value_of("color").unwrap(), "other");
135135
}
136+
137+
#[test]
138+
fn default_values_default() {
139+
let r = App::new("df")
140+
.arg( Arg::from_usage("-o [opt] 'some opt'")
141+
.default_value("default"))
142+
.get_matches_from_safe(vec![""]);
143+
assert!(r.is_ok());
144+
let m = r.unwrap();
145+
assert!(m.is_present("o"));
146+
assert_eq!(m.value_of("o").unwrap(), "default");
147+
}
148+
149+
#[test]
150+
fn default_values_user_value() {
151+
let r = App::new("df")
152+
.arg( Arg::from_usage("-o [opt] 'some opt'")
153+
.default_value("default"))
154+
.get_matches_from_safe(vec!["", "-o", "value"]);
155+
assert!(r.is_ok());
156+
let m = r.unwrap();
157+
assert!(m.is_present("o"));
158+
assert_eq!(m.value_of("o").unwrap(), "value");
159+
}

0 commit comments

Comments
 (0)