Skip to content

Commit

Permalink
feat(flag_aliases): Ability to alias flags
Browse files Browse the repository at this point in the history
Added same alias funtionality for flags, now you can do:
```
Arg::with_name("flg")
    .long("flag")
    .short("f")
    .alias("not_visible_flag")
    .visible_alias("awesome_v_flag")
```

Signed-off-by: Salim Afiune <afiune@chef.io>
  • Loading branch information
Salim Afiune committed Oct 3, 2016
1 parent 2b2b4ea commit a616a39
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 24 deletions.
11 changes: 10 additions & 1 deletion src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,16 @@ impl<'a, 'b> Parser<'a, 'b>
return Ok(ret);
} else if let Some(flag) = self.flags
.iter()
.find(|v| v.long.is_some() && &*v.long.unwrap() == arg) {
.find(|v|
(v.long.is_some() &&
&*v.long.unwrap() == arg) ||
(v.aliases.is_some() &&
v.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == &*arg))
) {
debugln!("Found valid flag '{}'", flag.to_string());
// Only flags could be help or version, and we need to check the raw long
// so this is the first point to check
Expand Down
2 changes: 2 additions & 0 deletions src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// # use clap::{App, Arg};
/// let m = App::new("myprog")
/// .arg(Arg::with_name("test")
/// .long("test")
/// .aliases(&["do-stuff", "do-tests", "tests"])
/// .help("the file to add")
/// .required(false))
Expand Down Expand Up @@ -506,6 +507,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// # use clap::{App, Arg};
/// let m = App::new("myprog")
/// .arg(Arg::with_name("test")
/// .long("test")
/// .visible_aliases(&["something", "awesome", "cool"]))
/// .get_matches_from(vec!["myprog", "--awesome"]);
/// assert!(m.is_present("test"));
Expand Down
61 changes: 58 additions & 3 deletions src/args/arg_builder/flag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use args::settings::{ArgFlags, ArgSettings};
pub struct FlagBuilder<'n, 'e> {
pub name: &'n str,
pub long: Option<&'e str>,
pub aliases: Option<Vec<(&'e str, bool)>>,
pub help: Option<&'e str>,
pub blacklist: Option<Vec<&'e str>>,
pub requires: Option<Vec<&'e str>>,
Expand All @@ -31,6 +32,7 @@ impl<'n, 'e> Default for FlagBuilder<'n, 'e> {
FlagBuilder {
name: "",
long: None,
aliases: None,
help: None,
blacklist: None,
requires: None,
Expand Down Expand Up @@ -68,6 +70,7 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
name: a.name,
short: a.short,
long: a.long,
aliases: a.aliases.clone(),
help: a.help,
blacklist: a.blacklist.clone(),
overrides: a.overrides.clone(),
Expand All @@ -81,10 +84,27 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
impl<'n, 'e> Display for FlagBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(l) = self.long {
write!(f, "--{}", l)
try!(write!(f, "--{}", l));
} else {
write!(f, "-{}", self.short.unwrap())
try!(write!(f, "-{}", self.short.unwrap()));
}

// Write aliases such as [aliases: alias, new-alias]
if let Some(ref vec) = self.aliases {
try!(write!(f, " [aliases: "));
let mut it = vec.iter().peekable();
while let Some(&(val, b)) = it.next() {
if b {
try!(write!(f, "{}", val));
if it.peek().is_some() {
try!(write!(f, ", "));
}
}
}
try!(write!(f, "]"));
}

Ok(())
}
}

Expand All @@ -94,6 +114,7 @@ impl<'n, 'e> Clone for FlagBuilder<'n, 'e> {
name: self.name,
short: self.short,
long: self.long,
aliases: self.aliases.clone(),
help: self.help,
blacklist: self.blacklist.clone(),
overrides: self.overrides.clone(),
Expand Down Expand Up @@ -169,7 +190,19 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
self.long.is_some()
}
fn aliases(&self) -> Option<Vec<&'e str>> {
None
if let Some(ref aliases) = self.aliases {
let vis_aliases: Vec<_> =
aliases.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect();
if vis_aliases.is_empty() {
None
} else {
Some(vis_aliases)
}
} else {
None
}
}
}

Expand Down Expand Up @@ -197,4 +230,26 @@ mod test {

assert_eq!(&*format!("{}", f2), "-f");
}

#[test]
fn flagbuilder_display_single_alias() {
let mut f = FlagBuilder::new("flg");
f.long = Some("flag");
f.aliases = Some(vec![("als", true)]);

assert_eq!(&*format!("{}", f), "--flag [aliases: als]");
}

#[test]
fn flagbuilder_display_multiple_aliases() {
let mut f = FlagBuilder::new("flg");
f.short = Some('f');
f.aliases = Some(vec![
("alias_not_visible", false),
("f2", true),
("f3", true),
("f4", true)
]);
assert_eq!(&*format!("{}", f), "-f [aliases: f2, f3, f4]");
}
}
1 change: 1 addition & 0 deletions src/args/arg_builder/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ mod test {
assert_eq!(&*format!("{}", o), "--option <opt> [aliases: als]");
}

#[test]
fn optbuilder_display_multiple_aliases() {
let mut o = OptBuilder::new("opt");
o.long = Some("option");
Expand Down
95 changes: 75 additions & 20 deletions tests/arg_aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,30 @@ static SC_VISIBLE_ALIAS_HELP: &'static str = "test
Some help
USAGE:
test [OPTIONS]
test [FLAGS] [OPTIONS]
FLAGS:
-f, --flag
flag with aliases [aliases: v_flg, flag2, flg3]
OPTIONS:
--opt <opt> [aliases: visible]";
-o, --opt <opt>
help for option with alias [aliases: visible]";

static SC_INVISIBLE_ALIAS_HELP: &'static str = "test
Some help
USAGE:
test [OPTIONS]
test [FLAGS] [OPTIONS]
FLAGS:
-f, --flag flag with aliases
OPTIONS:
--opt <opt> ";
-o, --opt <opt> help for option with alias";

#[test]
fn single_alias_of_option_long() {
fn single_alias_of_option() {
let a = App::new("single_alias")
.arg(Arg::with_name("alias")
.long("alias")
Expand All @@ -41,7 +49,7 @@ fn single_alias_of_option_long() {
}

#[test]
fn multiple_aliases_of_option_long() {
fn multiple_aliases_of_option() {
let a = App::new("multiple_aliases")
.arg(Arg::with_name("aliases")
.long("aliases")
Expand Down Expand Up @@ -86,6 +94,49 @@ fn multiple_aliases_of_option_long() {
assert_eq!(als3.value_of("aliases").unwrap(), "value");
}

#[test]
fn single_alias_of_flag() {
let a = App::new("test")
.arg(Arg::with_name("flag")
.long("flag")
.alias("alias"))
.get_matches_from_safe(vec!["", "--alias"]);
assert!(a.is_ok());
let a = a.unwrap();
assert!(a.is_present("flag"));
}

#[test]
fn multiple_aliases_of_flag() {
let a = App::new("test")
.arg(Arg::with_name("flag")
.long("flag")
.aliases(&["invisible",
"set", "of",
"cool", "aliases"]));

let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]);
assert!(flag.is_ok());
let flag = flag.unwrap();

let inv = a.clone().get_matches_from_safe(vec!["", "--invisible"]);
assert!(inv.is_ok());
let inv = inv.unwrap();

let cool = a.clone().get_matches_from_safe(vec!["", "--cool"]);
assert!(cool.is_ok());
let cool = cool.unwrap();

let als = a.clone().get_matches_from_safe(vec!["", "--aliases"]);
assert!(als.is_ok());
let als = als.unwrap();

assert!(flag.is_present("flag"));
assert!(inv.is_present("flag"));
assert!(cool.is_present("flag"));
assert!(als.is_present("flag"));
}

#[test]
fn alias_on_a_subcommand_option() {
let m = App::new("test")
Expand All @@ -112,36 +163,40 @@ fn alias_on_a_subcommand_option() {
#[test]
fn invisible_arg_aliases_help_output() {
let app = App::new("clap-test")
.author("Salim Afiune")
.subcommand(SubCommand::with_name("test")
.about("Some help")
.arg(Arg::with_name("opt")
.long("opt")
.short("o")
.help("help for option with alias")
.takes_value(true)
.aliases(&["invisible", "als1", "more"])));
.aliases(&["invisible", "als1", "more"]))
.arg(Arg::with_name("flg")
.long("flag")
.short("f")
.help("flag with aliases")
.aliases(&["invisible", "flg1", "anyway"])));
test::check_subcommand_help(app, "test", SC_INVISIBLE_ALIAS_HELP);
}

#[test]
fn visible_arg_aliases_help_output() {
let app = App::new("clap-test")
.author("Salim Afiune")
.subcommand(SubCommand::with_name("test")
.about("Some help")
.arg(Arg::with_name("opt")
.long("opt")
.short("o")
.help("help for option with alias")
.takes_value(true)
.alias("invisible")
.visible_alias("visible")));
.visible_alias("visible"))
.arg(Arg::with_name("flg")
.long("flag")
.short("f")
.help("flag with aliases")
.visible_aliases(&["v_flg", "flag2", "flg3"])));
test::check_subcommand_help(app, "test", SC_VISIBLE_ALIAS_HELP);
}

#[test]
fn visible_arg_flag_aliases() {
let a = App::new("test")
.arg(Arg::with_name("opt")
.long("opt")
.aliases(&["invisible", "set", "of", "aliases"]))
.get_matches_from_safe(vec!["", "--aliases"]);
assert!(a.is_ok());
let a = a.unwrap();
assert!(a.is_present("opt"));
}

0 comments on commit a616a39

Please sign in to comment.