From a8f3f038c03eb1393110dfdb1e6bdf1be6a3fb62 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Aug 2013 14:37:54 +0200 Subject: [PATCH] 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 --- src/libextra/getopts.rs | 99 ++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 31 deletions(-) diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 5ec6713509e..1b65528923a 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -114,7 +114,8 @@ pub enum Occur { pub struct Opt { name: Name, hasarg: HasArg, - occur: Occur + occur: Occur, + aliases: ~[Opt], } fn mkname(nm: &str) -> Name { @@ -127,29 +128,29 @@ fn mkname(nm: &str) -> Name { /// Create an option that is required and takes an argument 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 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 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, * and may occur multiple times. */ 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 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 */ 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)] @@ -189,7 +190,20 @@ fn name_str(nm: &Name) -> ~str { } fn find_opt(opts: &[Opt], nm: Name) -> Option { - 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::{Short, Yes}; - use std::vec; - /** one group of options, e.g., both -h and --help, along with * their shared description and properties */ @@ -587,7 +599,7 @@ pub fn optmulti(short_name: &str, long_name: &str, // translate OptGroup into Opt // (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, long_name: long_name, hasarg: hasarg, @@ -595,24 +607,29 @@ pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { _} = (*lopt).clone(); 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)), - hasarg: hasarg, - occur: occur}], + (0,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, - (1,0) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}], + (1,0) => Opt {name: Short(short_name.char_at(0)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, - (1,_) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}, - Opt {name: Long((long_name)), - hasarg: hasarg, - occur: occur}], + (1,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[Opt { + name: Short(short_name.char_at(0)), + 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 fn long_to_short(lopt: &OptGroup) -> ~[Opt] { * Parse command line args with the provided long format options */ 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 @@ fn test_groups_optmulti() { #[test] 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"); assert_eq!(groups::long_to_short(&verbose), short); @@ -1462,10 +1480,16 @@ fn test_groups_long_to_short() { #[test] 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 = ~[ - reqopt("b"), reqopt("banana"), - optopt("a"), optopt("apple"), - optflag("k"), optflagopt("kiwi"), + banana, + apple, + kiwi, optflagopt("p"), optmulti("l") ]; @@ -1478,7 +1502,7 @@ fn test_groups_getopts() { 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"]; // FIXME #4681: sort options here? @@ -1486,6 +1510,19 @@ fn test_groups_getopts() { == 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] fn test_groups_usage() { let optgroups = ~[