feat(arg): allow other types besides Vec for multiple value settings

Breaking Change

Instead of requiring a Vec<&str> for various Arg::*_all() and
Arg::possible_values() methods this
commit now requires a generic IntoIterator<Item=AsRef<str>> which allows
things such as constant arrays. This change requires that any
Arg::*_all() methods be changed from vec!["val", "val"] -> let vals =
["val", "val"]; some_arg.possible_values(&vals) (or vals.iter()).

Closes #87
This commit is contained in:
Kevin K 2015-04-29 13:32:00 -04:00
parent 9e6af520a3
commit 0cc2f69839
6 changed files with 49 additions and 34 deletions

View file

@ -3,10 +3,13 @@ extern crate clap;
use clap::{App, Arg, SubCommand}; use clap::{App, Arg, SubCommand};
fn main() { fn main() {
let args = "-f --flag... 'tests flags' let args = "-f --flag... 'tests flags'
-o --option=[opt]... 'tests options' -o --option=[opt]... 'tests options'
[positional] 'tests positionals'"; [positional] 'tests positionals'";
let opt3_vals = ["fast", "slow"];
let pos3_vals = ["vi", "emacs"];
let matches = App::new("claptests") let matches = App::new("claptests")
// Test version from Cargo.toml // Test version from Cargo.toml
.version(&crate_version!()[..]) .version(&crate_version!()[..])
@ -17,8 +20,8 @@ fn main() {
Arg::from_usage("[flag2] -F 'tests flags with exclusions'").mutually_excludes("flag").requires("option2"), Arg::from_usage("[flag2] -F 'tests flags with exclusions'").mutually_excludes("flag").requires("option2"),
Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").mutually_excludes("option").requires("positional2"), Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").mutually_excludes("option").requires("positional2"),
Arg::from_usage("[positional2] 'tests positionals with exclusions'"), Arg::from_usage("[positional2] 'tests positionals with exclusions'"),
Arg::from_usage("-O [option3] 'tests options with specific value sets'").possible_values(vec!["fast", "slow"]), Arg::from_usage("-O [option3] 'tests options with specific value sets'").possible_values(&opt3_vals),
Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(vec!["vi", "emacs"]) Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(&pos3_vals)
]) ])
.subcommand(SubCommand::new("subcmd") .subcommand(SubCommand::new("subcmd")
.about("tests subcommands") .about("tests subcommands")

View file

@ -12,11 +12,12 @@ fn main() {
// //
// For this example, assume you want one positional argument of either "fast" or "slow" // For this example, assume you want one positional argument of either "fast" or "slow"
// i.e. the only possible ways to run the program are "myprog fast" or "myprog slow" // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
let mode_vals = ["fast", "slow"];
let matches = App::new("myapp").about("does awesome things") let matches = App::new("myapp").about("does awesome things")
.arg(Arg::with_name("MODE") .arg(Arg::with_name("MODE")
.help("What mode to run the program in") .help("What mode to run the program in")
.index(1) .index(1)
.possible_values(vec!["fast", "slow"]) .possible_values(&mode_vals)
.required(true)) .required(true))
.get_matches(); .get_matches();

View file

@ -33,13 +33,14 @@ arg_enum!{
fn main() { fn main() {
// Create the application like normal // Create the application like normal
let enum_vals = ["fast", "slow"];
let m = App::new("myapp") let m = App::new("myapp")
// Use a single positional argument that is required // Use a single positional argument that is required
.arg(Arg::from_usage("<type> 'The Foo to use'") .arg(Arg::from_usage("<type> 'The Foo to use'")
// You can define a list of possible values if you want the values to be // You can define a list of possible values if you want the values to be
// displayed in the help information. Whether you use possible_values() or // displayed in the help information. Whether you use possible_values() or
// not, the valid values will ALWAYS be displayed on a failed parse. // not, the valid values will ALWAYS be displayed on a failed parse.
.possible_values(vec!["Bar", "Baz", "Qux"])) .possible_values(&enum_vals))
// For the second positional, lets not use possible_values() just to show the difference // For the second positional, lets not use possible_values() just to show the difference
.arg_from_usage("<type2> 'The Oof to use'") .arg_from_usage("<type2> 'The Oof to use'")
.get_matches(); .get_matches();

View file

@ -38,11 +38,12 @@ impl FromStr for Vals {
fn main() { fn main() {
// Create the application like normal // Create the application like normal
let enum_vals = ["Foo", "Bar", "Baz", "Qux"];
let m = App::new("myapp") let m = App::new("myapp")
// Use a single positional argument that is required // Use a single positional argument that is required
.arg(Arg::from_usage("<type> 'The type to use'") .arg(Arg::from_usage("<type> 'The type to use'")
// Define the list of possible values // Define the list of possible values
.possible_values(vec!["Foo", "Bar", "Baz", "Qux"])) .possible_values(&enum_vals))
.get_matches(); .get_matches();
let t = value_t_or_exit!(m.value_of("type"), Vals); let t = value_t_or_exit!(m.value_of("type"), Vals);

View file

@ -1,3 +1,5 @@
use std::iter::IntoIterator;
use usageparser::{UsageParser, UsageToken}; use usageparser::{UsageParser, UsageToken};
/// The abstract representation of a command line argument used by the consumer of the library. /// The abstract representation of a command line argument used by the consumer of the library.
@ -379,7 +381,8 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.blacklist { if let Some(ref mut vec) = self.blacklist {
vec.push(name); vec.push(name);
} else { } else {
self.blacklist = Some(vec![name]); let v = vec![name];
self.blacklist = Some(v);
} }
self self
} }
@ -398,17 +401,18 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
/// ///
/// ```no_run /// ```no_run
/// # use clap::{App, Arg}; /// # use clap::{App, Arg};
/// let conf_excludes = ["debug", "input"];
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg") /// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .mutually_excludes_all( /// .mutually_excludes_all(&conf_excludes)
/// vec!["debug", "input"])
/// # ).get_matches(); /// # ).get_matches();
pub fn mutually_excludes_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> { pub fn mutually_excludes_all<T, I>(mut self, names: I)
-> Arg<'n, 'l, 'h, 'g, 'p, 'r>
where T: AsRef<str> + 'r,
I: IntoIterator<Item=&'r T> {
if let Some(ref mut vec) = self.blacklist { if let Some(ref mut vec) = self.blacklist {
for n in names { names.into_iter().map(|s| vec.push(s.as_ref())).collect::<Vec<_>>();
vec.push(n);
}
} else { } else {
self.blacklist = Some(names); self.blacklist = Some(names.into_iter().map(|s| s.as_ref()).collect::<Vec<_>>());
} }
self self
} }
@ -449,17 +453,18 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
/// ///
/// ```no_run /// ```no_run
/// # use clap::{App, Arg}; /// # use clap::{App, Arg};
/// let config_conflicts = ["debug", "input"];
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg") /// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .conflicts_with_all( /// .conflicts_with_all(&config_conflicts)
/// vec!["debug", "input"])
/// # ).get_matches(); /// # ).get_matches();
pub fn conflicts_with_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> { pub fn conflicts_with_all<T, I>(mut self, names: I)
-> Arg<'n, 'l, 'h, 'g, 'p, 'r>
where T: AsRef<str> + 'r,
I: IntoIterator<Item=&'r T> {
if let Some(ref mut vec) = self.blacklist { if let Some(ref mut vec) = self.blacklist {
for n in names { names.into_iter().map(|s| vec.push(s.as_ref())).collect::<Vec<_>>();
vec.push(n);
}
} else { } else {
self.blacklist = Some(names); self.blacklist = Some(names.into_iter().map(|s| s.as_ref()).collect::<Vec<_>>());
} }
self self
} }
@ -497,17 +502,18 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
/// ///
/// ```no_run /// ```no_run
/// # use clap::{App, Arg}; /// # use clap::{App, Arg};
/// let config_reqs = ["debug", "input"];
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg") /// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .requires_all( /// .requires_all(&config_reqs)
/// vec!["debug", "input"])
/// # ).get_matches(); /// # ).get_matches();
pub fn requires_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> { pub fn requires_all<T, I>(mut self, names: I)
-> Arg<'n, 'l, 'h, 'g, 'p, 'r>
where T: AsRef<str> + 'r,
I: IntoIterator<Item=&'r T> {
if let Some(ref mut vec) = self.requires { if let Some(ref mut vec) = self.requires {
for n in names { names.into_iter().map(|s| vec.push(s.as_ref())).collect::<Vec<_>>();
vec.push(n);
}
} else { } else {
self.requires = Some(names); self.requires = Some(names.into_iter().map(|s| s.as_ref()).collect::<Vec<_>>());
} }
self self
} }
@ -587,18 +593,20 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
/// ///
/// ```no_run /// ```no_run
/// # use clap::{App, Arg}; /// # use clap::{App, Arg};
/// let mode_vals = ["fast", "slow"];
/// # let matches = App::new("myprog") /// # let matches = App::new("myprog")
/// # .arg( /// # .arg(
/// # Arg::with_name("debug").index(1) /// # Arg::with_name("debug").index(1)
/// .possible_values(vec!["fast", "slow"]) /// .possible_values(&mode_vals)
/// # ).get_matches(); /// # ).get_matches();
pub fn possible_values(mut self, names: Vec<&'p str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> { pub fn possible_values<T, I>(mut self, names: I)
-> Arg<'n, 'l, 'h, 'g, 'p, 'r>
where T: AsRef<str> + 'p,
I: IntoIterator<Item=&'p T> {
if let Some(ref mut vec) = self.possible_vals { if let Some(ref mut vec) = self.possible_vals {
for n in names { names.into_iter().map(|s| vec.push(s.as_ref())).collect::<Vec<_>>();
vec.push(n);
}
} else { } else {
self.possible_vals = Some(names); self.possible_vals = Some(names.into_iter().map(|s| s.as_ref()).collect::<Vec<_>>());
} }
self self
} }

View file

@ -283,9 +283,10 @@ macro_rules! value_t_or_exit {
/// // Foo enum can now be used via Foo::Bar, or Foo::Baz, etc /// // Foo enum can now be used via Foo::Bar, or Foo::Baz, etc
/// // and implements std::str::FromStr to use with the value_t! macros /// // and implements std::str::FromStr to use with the value_t! macros
/// fn main() { /// fn main() {
/// let enum_vals = ["Bar", "Baz", "Qux"];
/// let m = App::new("app") /// let m = App::new("app")
/// .arg(Arg::from_usage("<foo> 'the foo'") /// .arg(Arg::from_usage("<foo> 'the foo'")
/// .possible_values(vec!["Bar", "Baz", "Qux"])) /// .possible_values(&enum_vals))
/// .get_matches(); /// .get_matches();
/// let f = value_t_or_exit!(m.value_of("foo"), Foo); /// let f = value_t_or_exit!(m.value_of("foo"), Foo);
/// ///