Turn OptGroups into a main opt and a main and an aliased opts

This way opt_present("apple") will match no matter if the user passed -a or --apple
This commit is contained in:
Jordi Boggiano 2013-08-05 14:37:54 +02:00
parent 8a91ab9a61
commit 0aa51544ce

View file

@ -114,7 +114,8 @@ pub enum Occur {
pub struct Opt { pub struct Opt {
name: Name, name: Name,
hasarg: HasArg, hasarg: HasArg,
occur: Occur occur: Occur,
aliases: ~[Opt],
} }
fn mkname(nm: &str) -> Name { fn mkname(nm: &str) -> Name {
@ -127,29 +128,29 @@ fn mkname(nm: &str) -> Name {
/// Create an option that is required and takes an argument /// Create an option that is required and takes an argument
pub fn reqopt(name: &str) -> Opt { pub fn reqopt(name: &str) -> Opt {
return Opt {name: mkname(name), hasarg: Yes, occur: Req}; return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]};
} }
/// Create an option that is optional and takes an argument /// Create an option that is optional and takes an argument
pub fn optopt(name: &str) -> Opt { pub fn optopt(name: &str) -> Opt {
return Opt {name: mkname(name), hasarg: Yes, occur: Optional}; return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]};
} }
/// Create an option that is optional and does not take an argument /// Create an option that is optional and does not take an argument
pub fn optflag(name: &str) -> Opt { pub fn optflag(name: &str) -> Opt {
return Opt {name: mkname(name), hasarg: No, occur: Optional}; return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]};
} }
/** Create an option that is optional, does not take an argument, /** Create an option that is optional, does not take an argument,
* and may occur multiple times. * and may occur multiple times.
*/ */
pub fn optflagmulti(name: &str) -> Opt { pub fn optflagmulti(name: &str) -> Opt {
return Opt {name: mkname(name), hasarg: No, occur: Multi}; return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]};
} }
/// Create an option that is optional and takes an optional argument /// Create an option that is optional and takes an optional argument
pub fn optflagopt(name: &str) -> Opt { pub fn optflagopt(name: &str) -> Opt {
return Opt {name: mkname(name), hasarg: Maybe, occur: Optional}; return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]};
} }
/** /**
@ -157,7 +158,7 @@ pub fn optflagopt(name: &str) -> Opt {
* multiple times * multiple times
*/ */
pub fn optmulti(name: &str) -> Opt { pub fn optmulti(name: &str) -> Opt {
return Opt {name: mkname(name), hasarg: Yes, occur: Multi}; return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]};
} }
#[deriving(Clone, Eq)] #[deriving(Clone, Eq)]
@ -189,7 +190,20 @@ fn name_str(nm: &Name) -> ~str {
} }
fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> { fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
opts.iter().position(|opt| opt.name == nm) // search main options
let pos = opts.iter().position(|opt| opt.name == nm);
if pos.is_some() {
return pos
}
// search in aliases
for candidate in opts.iter() {
if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
return opts.iter().position(|opt| opt.name == candidate.name);
}
}
None
} }
/** /**
@ -488,8 +502,6 @@ pub mod groups {
use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req}; use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
use getopts::{Short, Yes}; use getopts::{Short, Yes};
use std::vec;
/** one group of options, e.g., both -h and --help, along with /** one group of options, e.g., both -h and --help, along with
* their shared description and properties * their shared description and properties
*/ */
@ -587,7 +599,7 @@ pub mod groups {
// translate OptGroup into Opt // translate OptGroup into Opt
// (both short and long names correspond to different Opts) // (both short and long names correspond to different Opts)
pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { pub fn long_to_short(lopt: &OptGroup) -> Opt {
let OptGroup{short_name: short_name, let OptGroup{short_name: short_name,
long_name: long_name, long_name: long_name,
hasarg: hasarg, hasarg: hasarg,
@ -595,24 +607,29 @@ pub mod groups {
_} = (*lopt).clone(); _} = (*lopt).clone();
match (short_name.len(), long_name.len()) { match (short_name.len(), long_name.len()) {
(0,0) => fail!("this long-format option was given no name"), (0,0) => fail!("this long-format option was given no name"),
(0,_) => ~[Opt {name: Long((long_name)), (0,_) => Opt {name: Long((long_name)),
hasarg: hasarg, hasarg: hasarg,
occur: occur}], occur: occur,
aliases: ~[]},
(1,0) => ~[Opt {name: Short(short_name.char_at(0)), (1,0) => Opt {name: Short(short_name.char_at(0)),
hasarg: hasarg, hasarg: hasarg,
occur: occur}], occur: occur,
aliases: ~[]},
(1,_) => ~[Opt {name: Short(short_name.char_at(0)), (1,_) => Opt {name: Long((long_name)),
hasarg: hasarg, hasarg: hasarg,
occur: occur}, occur: occur,
Opt {name: Long((long_name)), aliases: ~[Opt {
hasarg: hasarg, name: Short(short_name.char_at(0)),
occur: occur}], hasarg: hasarg,
occur: occur,
aliases: ~[]
}]},
(_,_) => fail!("something is wrong with the long-form opt") (_,_) => fail!("something is wrong with the long-form opt")
} }
} }
@ -620,7 +637,7 @@ pub mod groups {
* Parse command line args with the provided long format options * Parse command line args with the provided long format options
*/ */
pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result { pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
::getopts::getopts(args, vec::flat_map(opts, long_to_short)) ::getopts::getopts(args, opts.map(long_to_short))
} }
/** /**
@ -1454,7 +1471,8 @@ mod tests {
#[test] #[test]
fn test_groups_long_to_short() { fn test_groups_long_to_short() {
let short = ~[reqopt("b"), reqopt("banana")]; let mut short = reqopt("banana");
short.aliases = ~[reqopt("b")];
let verbose = groups::reqopt("b", "banana", "some bananas", "VAL"); let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
assert_eq!(groups::long_to_short(&verbose), short); assert_eq!(groups::long_to_short(&verbose), short);
@ -1462,10 +1480,16 @@ mod tests {
#[test] #[test]
fn test_groups_getopts() { fn test_groups_getopts() {
let mut banana = reqopt("banana");
banana.aliases = ~[reqopt("b")];
let mut apple = optopt("apple");
apple.aliases = ~[optopt("a")];
let mut kiwi = optflag("kiwi");
kiwi.aliases = ~[optflag("k")];
let short = ~[ let short = ~[
reqopt("b"), reqopt("banana"), banana,
optopt("a"), optopt("apple"), apple,
optflag("k"), optflagopt("kiwi"), kiwi,
optflagopt("p"), optflagopt("p"),
optmulti("l") optmulti("l")
]; ];
@ -1478,7 +1502,7 @@ mod tests {
groups::optmulti("l", "", "Desc", "VAL"), groups::optmulti("l", "", "Desc", "VAL"),
]; ];
let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k", let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k",
~"-p", ~"16", ~"l", ~"35"]; ~"-p", ~"16", ~"l", ~"35"];
// FIXME #4681: sort options here? // FIXME #4681: sort options here?
@ -1486,6 +1510,19 @@ mod tests {
== groups::getopts(sample_args, verbose)); == groups::getopts(sample_args, verbose));
} }
#[test]
fn test_groups_aliases_long_and_short() {
let opts = ~[
groups::optflagmulti("a", "apple", "Desc"),
];
let args = ~[~"-a", ~"--apple", ~"-a"];
let matches = groups::getopts(args, opts).unwrap();
assert_eq!(3, opt_count(&matches, "a"));
assert_eq!(3, opt_count(&matches, "apple"));
}
#[test] #[test]
fn test_groups_usage() { fn test_groups_usage() {
let optgroups = ~[ let optgroups = ~[