1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
extern crate argonaut;
use std::env;
use std::iter;
use argonaut::{ArgDef, parse, ParseError};
use std::process;
use std::collections::HashSet;
fn main() {
// Properly set exit codes after the program has cleaned up.
if let Some(exit_code) = argonaut_main() {
process::exit(exit_code);
}
}
fn argonaut_main() -> Option<i32> {
let args = env::args().skip(1).collect::<Vec<_>>();
// Set up the variables that will be parsed into.
let mut first = String::new();
let mut second = String::new();
let mut third = false;
// Types that are FromStr + Debug can be set by the parser, so here
// we need to tell it that we want a String.
let mut cool_thing: Option<String> = None;
let mut stars = 0;
let mut verbose = false;
// And here we need to tell what elements should be collected into the collection.
let mut numbers: Vec<i32> = Vec::new();
// All set/linear collections in std::collections are supported.
//
// To add more targets, implement CollectionTarget for your collection type.
let mut includes: HashSet<String> = HashSet::new();
// Prepare a description of the program.
//
// The default help formatter removes initial/final empty lines, and
// strips the lines, so the text can be written with convenient indentation.
let description = "
Test program for an argument parsing library.
Showcases the features of the library.
";
// Starts parsing arguments with the program name 'argonaut', and the
// definitions in the vector.
//
// If the definitions are invalid (both subcommands and positional arguments
// defined, names used twice, etc.), the function will PANIC!.
match parse("argonaut", &args, vec![
// Declare a positional argument with the name 'first', that should
// store its value in the String variable 'first'.
ArgDef::positional("first", &mut first)
// This describes the argument in the generated help messages.
.help("The first argument."),
ArgDef::positional("second", &mut second)
.help("The second argument."),
// Declare a positional argument that will try to parse its value
// as a `bool` using `FromStr`.
ArgDef::positional("third-is-better", &mut third)
.help("Whether the third argument is better than the rest."),
// Declare that 0 or more trailing arguments should be parsed as i32
// and added to the vector 'numbers'.
ArgDef::trail("numbers", true, &mut numbers)
.help("A bunch of numbers used for nefarious machinations."),
// Declare an '--include' option that takes a String value and adds
// it to the HashSet 'includes'.
// The option can be given multiple times to add more values.
ArgDef::collect("include", &mut includes)
// Adds '-i' as an alias for this option.
.short("i")
// Sets the parameter name for this option to 'file' in the generated
// help messages.
// ('--include file' instead of '--include INCLUDE')
.param("file")
.help("Which files to include in the cake."),
// Declare a '--cool THING' setting, that sets an optional setting
// to a value.
// Settings can only be set ONCE.
ArgDef::setting("cool", &mut cool_thing).param("thing")
.help("Something that you think is cool enough to pass."),
// Declare a '--star' counter, that counts the number of times '--star'
// or '-s' was passed, and increments 'stars' each time.
// Counter arguments can be passed multiple times.
ArgDef::count("star", &mut stars).short("s")
.help("How many stars does this library deserve?"),
// Declare a '--verbose' flag, that sets a value to 'true' if passed.
ArgDef::flag("verbose", &mut verbose).short("v")
.help("Print as much information as possible."),
// Declare a '--help' 'interrupt' argument, that uses 'description' as a
// description of the program.
//
// When '--help' is passed, the parse is interrupted and
// Err(Interrupted("help")) will be returned.
//
// As this 'interrupts' the parsing, the required values,
// 'one', 'two' and 'third-is-better', will not have been set.
ArgDef::default_help(description).short("h"),
// Declare a default '--version' argument that prints the SemVer version
// from 'Cargo.toml' and interrupts.
ArgDef::default_version(),
]) {
// If the parse has succeeded, all required (positional) values will
// have been assigned to their target variables.
//
// If any subcommands are defined, they may return an error code, so
// that process::exit can be called after everything is cleaned up.
Ok(_optional_error_code) => {},
// If the parse receives an 'interrupt' flag, the required values will
// not have been set, and the program should exit.
Err(ParseError::Interrupted(_)) => {
return None;
},
// The regular 'parse' function will print out information about errors
// and print a usage string if an error is encountered, so in this case
// a general error code should just be returned.
Err(_) => {
return Some(1);
}
};
// If the parse did not return an error, all required values will have been
// set to a value from an argument by this point.
println!("First: {}", first);
println!("Second: {}", second);
println!("Third is better?: {}", third);
println!("");
println!("Numbers: {:?}", numbers);
println!("Included files: {:?}", includes);
if verbose {
println!("VERBOSE!");
}
if let Some(cool) = cool_thing {
println!("Got a real cool {} :u!", cool);
} else {
println!("Nothing's cool anymore");
}
println!("Library rating: {}", iter::repeat('*').take(stars).collect::<String>());
None
}