Skip to content

Commit 0aa5154

Browse files
committed
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
1 parent 8a91ab9 commit 0aa5154

File tree

1 file changed

+72
-35
lines changed

1 file changed

+72
-35
lines changed

src/libextra/getopts.rs

Lines changed: 72 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ pub enum Occur {
114114
pub struct Opt {
115115
name: Name,
116116
hasarg: HasArg,
117-
occur: Occur
117+
occur: Occur,
118+
aliases: ~[Opt],
118119
}
119120

120121
fn mkname(nm: &str) -> Name {
@@ -127,37 +128,37 @@ fn mkname(nm: &str) -> Name {
127128

128129
/// Create an option that is required and takes an argument
129130
pub fn reqopt(name: &str) -> Opt {
130-
return Opt {name: mkname(name), hasarg: Yes, occur: Req};
131+
return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]};
131132
}
132133

133134
/// Create an option that is optional and takes an argument
134135
pub fn optopt(name: &str) -> Opt {
135-
return Opt {name: mkname(name), hasarg: Yes, occur: Optional};
136+
return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]};
136137
}
137138

138139
/// Create an option that is optional and does not take an argument
139140
pub fn optflag(name: &str) -> Opt {
140-
return Opt {name: mkname(name), hasarg: No, occur: Optional};
141+
return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]};
141142
}
142143

143144
/** Create an option that is optional, does not take an argument,
144145
* and may occur multiple times.
145146
*/
146147
pub fn optflagmulti(name: &str) -> Opt {
147-
return Opt {name: mkname(name), hasarg: No, occur: Multi};
148+
return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]};
148149
}
149150

150151
/// Create an option that is optional and takes an optional argument
151152
pub fn optflagopt(name: &str) -> Opt {
152-
return Opt {name: mkname(name), hasarg: Maybe, occur: Optional};
153+
return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]};
153154
}
154155

155156
/**
156157
* Create an option that is optional, takes an argument, and may occur
157158
* multiple times
158159
*/
159160
pub fn optmulti(name: &str) -> Opt {
160-
return Opt {name: mkname(name), hasarg: Yes, occur: Multi};
161+
return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]};
161162
}
162163

163164
#[deriving(Clone, Eq)]
@@ -189,7 +190,20 @@ fn name_str(nm: &Name) -> ~str {
189190
}
190191

191192
fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
192-
opts.iter().position(|opt| opt.name == nm)
193+
// search main options
194+
let pos = opts.iter().position(|opt| opt.name == nm);
195+
if pos.is_some() {
196+
return pos
197+
}
198+
199+
// search in aliases
200+
for candidate in opts.iter() {
201+
if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
202+
return opts.iter().position(|opt| opt.name == candidate.name);
203+
}
204+
}
205+
206+
None
193207
}
194208

195209
/**
@@ -488,8 +502,6 @@ pub mod groups {
488502
use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
489503
use getopts::{Short, Yes};
490504

491-
use std::vec;
492-
493505
/** one group of options, e.g., both -h and --help, along with
494506
* their shared description and properties
495507
*/
@@ -587,40 +599,45 @@ pub mod groups {
587599

588600
// translate OptGroup into Opt
589601
// (both short and long names correspond to different Opts)
590-
pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] {
602+
pub fn long_to_short(lopt: &OptGroup) -> Opt {
591603
let OptGroup{short_name: short_name,
592604
long_name: long_name,
593605
hasarg: hasarg,
594606
occur: occur,
595607
_} = (*lopt).clone();
596608

597609
match (short_name.len(), long_name.len()) {
598-
(0,0) => fail!("this long-format option was given no name"),
599-
600-
(0,_) => ~[Opt {name: Long((long_name)),
601-
hasarg: hasarg,
602-
occur: occur}],
603-
604-
(1,0) => ~[Opt {name: Short(short_name.char_at(0)),
605-
hasarg: hasarg,
606-
occur: occur}],
607-
608-
(1,_) => ~[Opt {name: Short(short_name.char_at(0)),
609-
hasarg: hasarg,
610-
occur: occur},
611-
Opt {name: Long((long_name)),
612-
hasarg: hasarg,
613-
occur: occur}],
614-
615-
(_,_) => fail!("something is wrong with the long-form opt")
610+
(0,0) => fail!("this long-format option was given no name"),
611+
612+
(0,_) => Opt {name: Long((long_name)),
613+
hasarg: hasarg,
614+
occur: occur,
615+
aliases: ~[]},
616+
617+
(1,0) => Opt {name: Short(short_name.char_at(0)),
618+
hasarg: hasarg,
619+
occur: occur,
620+
aliases: ~[]},
621+
622+
(1,_) => Opt {name: Long((long_name)),
623+
hasarg: hasarg,
624+
occur: occur,
625+
aliases: ~[Opt {
626+
name: Short(short_name.char_at(0)),
627+
hasarg: hasarg,
628+
occur: occur,
629+
aliases: ~[]
630+
}]},
631+
632+
(_,_) => fail!("something is wrong with the long-form opt")
616633
}
617634
}
618635

619636
/*
620637
* Parse command line args with the provided long format options
621638
*/
622639
pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
623-
::getopts::getopts(args, vec::flat_map(opts, long_to_short))
640+
::getopts::getopts(args, opts.map(long_to_short))
624641
}
625642

626643
/**
@@ -1454,18 +1471,25 @@ mod tests {
14541471
14551472
#[test]
14561473
fn test_groups_long_to_short() {
1457-
let short = ~[reqopt("b"), reqopt("banana")];
1474+
let mut short = reqopt("banana");
1475+
short.aliases = ~[reqopt("b")];
14581476
let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
14591477
14601478
assert_eq!(groups::long_to_short(&verbose), short);
14611479
}
14621480
14631481
#[test]
14641482
fn test_groups_getopts() {
1483+
let mut banana = reqopt("banana");
1484+
banana.aliases = ~[reqopt("b")];
1485+
let mut apple = optopt("apple");
1486+
apple.aliases = ~[optopt("a")];
1487+
let mut kiwi = optflag("kiwi");
1488+
kiwi.aliases = ~[optflag("k")];
14651489
let short = ~[
1466-
reqopt("b"), reqopt("banana"),
1467-
optopt("a"), optopt("apple"),
1468-
optflag("k"), optflagopt("kiwi"),
1490+
banana,
1491+
apple,
1492+
kiwi,
14691493
optflagopt("p"),
14701494
optmulti("l")
14711495
];
@@ -1478,14 +1502,27 @@ mod tests {
14781502
groups::optmulti("l", "", "Desc", "VAL"),
14791503
];
14801504
1481-
let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k",
1505+
let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k",
14821506
~"-p", ~"16", ~"l", ~"35"];
14831507
14841508
// FIXME #4681: sort options here?
14851509
assert!(getopts(sample_args, short)
14861510
== groups::getopts(sample_args, verbose));
14871511
}
14881512
1513+
#[test]
1514+
fn test_groups_aliases_long_and_short() {
1515+
let opts = ~[
1516+
groups::optflagmulti("a", "apple", "Desc"),
1517+
];
1518+
1519+
let args = ~[~"-a", ~"--apple", ~"-a"];
1520+
1521+
let matches = groups::getopts(args, opts).unwrap();
1522+
assert_eq!(3, opt_count(&matches, "a"));
1523+
assert_eq!(3, opt_count(&matches, "apple"));
1524+
}
1525+
14891526
#[test]
14901527
fn test_groups_usage() {
14911528
let optgroups = ~[

0 commit comments

Comments
 (0)