OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * This library lets you define parsers for parsing raw command-line arguments | 6 * Parser support for transforming raw command-line arguments |
7 * into a set of options and values using [GNU][] and [POSIX][] style options. | 7 * into a set of options and values. |
Bob Nystrom
2013/08/27 17:58:10
I know it's a chore, but can you word wrap these d
Kathy Walrath
2013/08/28 08:00:59
How strongly do you feel about that? I'm willing t
Bob Nystrom
2013/08/28 17:00:11
Pretty strongly. The main reason I pushed for mark
| |
8 * | 8 * |
9 * ## Installing ## | 9 * This library supports |
10 * [GNU][] and [POSIX][] style options, | |
11 * and it works in both server-side and client-side apps. | |
10 * | 12 * |
11 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` | 13 * For information on installing and importing this library, see the |
12 * file. | 14 * [args package on pub.dartlang.org] |
15 * (http://pub.dartlang.org/packages/args). | |
13 * | 16 * |
14 * dependencies: | 17 * ## Defining options |
15 * args: any | |
16 * | 18 * |
17 * Then run `pub install`. | 19 * To use this library, first create an [ArgParser] object to contain |
18 * | |
19 * For more information, see the | |
20 * [args package on pub.dartlang.org](http://pub.dartlang.org/packages/args). | |
21 * | |
22 * ## Defining options ## | |
23 * | |
24 * To use this library, you create an [ArgParser] object which will contain | |
25 * the set of options you support: | 20 * the set of options you support: |
Bob Nystrom
2013/08/27 17:58:10
You mention "set of options" on the next sentence
Kathy Walrath
2013/08/28 08:00:59
Done.
| |
26 * | 21 * |
27 * var parser = new ArgParser(); | 22 * var parser = new ArgParser(); |
28 * | 23 * |
29 * Then you define a set of options on that parser using [addOption()] and | 24 * Then define a set of options on that parser using [addOption()] and |
30 * [addFlag()]. The minimal way to create an option is: | 25 * [addFlag()]. Here's the minimal way to create an option named "name": |
31 * | 26 * |
32 * parser.addOption('name'); | 27 * parser.addOption('name'); |
33 * | 28 * |
34 * This creates an option named "name". Options must be given a value on the | 29 * For a simple on-off option, you can instead use a flag: |
Bob Nystrom
2013/08/27 17:58:10
This is a bit confusing because it makes it seem l
Kathy Walrath
2013/08/28 08:00:59
Done.
| |
35 * command line. If you have a simple on/off flag, you can instead use: | |
36 * | 30 * |
37 * parser.addFlag('name'); | 31 * parser.addFlag('name'); |
38 * | 32 * |
39 * Flag options will, by default, accept a 'no-' prefix to negate the option. | 33 * Flag options, by default, accept a 'no-' prefix to negate the option. |
40 * This can be disabled like so: | 34 * You can disable the 'no-' prefix using the `negatable` parameter: |
41 * | 35 * |
42 * parser.addFlag('name', negatable: false); | 36 * parser.addFlag('name', negatable: false); |
43 * | 37 * |
44 * (From here on out "option" will refer to both "regular" options and flags. | 38 * **Terminology note:** |
45 * In cases where the distinction matters, we'll use "non-flag option".) | 39 * From here on out, the term _option_ refers to |
40 * both regular options and flags. | |
41 * In cases where the distinction matters, | |
42 * this documentation uses the term _non-flag option._ | |
46 * | 43 * |
47 * Options may have an optional single-character abbreviation: | 44 * Options can have an optional single-character abbreviation, |
45 * specified with the `abbr` parameter: | |
48 * | 46 * |
49 * parser.addOption('mode', abbr: 'm'); | 47 * parser.addOption('mode', abbr: 'm'); |
50 * parser.addFlag('verbose', abbr: 'v'); | 48 * parser.addFlag('verbose', abbr: 'v'); |
51 * | 49 * |
52 * They may also specify a default value. The default value will be used if the | 50 * Options can also have a default value, |
51 * specified with the `defaultsTo` parameter. | |
52 * The default value is used when the | |
53 * option isn't provided: | 53 * option isn't provided: |
Bob Nystrom
2013/08/27 17:58:10
"option isn't provided" is a bit unclear. It could
Kathy Walrath
2013/08/28 08:00:59
Done.
| |
54 * | 54 * |
55 * parser.addOption('mode', defaultsTo: 'debug'); | 55 * parser.addOption('mode', defaultsTo: 'debug'); |
56 * parser.addFlag('verbose', defaultsTo: false); | 56 * parser.addFlag('verbose', defaultsTo: false); |
57 * | 57 * |
58 * The default value for non-flag options can be any [String]. For flags, it | 58 * The default value for non-flag options can be any [String]. For flags, it |
59 * must be a [bool]. | 59 * must be a [bool]. |
60 * | 60 * |
61 * To validate non-flag options, you may provide an allowed set of values. When | 61 * To validate a non-flag option, |
62 * you do, it will throw a [FormatException] when you parse the arguments if | 62 * you can use the `allowed` parameter |
63 * the value for an option is not in the allowed set: | 63 * to provide an allowed set of values. When |
64 * you do, a [FormatException] occurs during parsing if | |
Bob Nystrom
2013/08/27 17:58:10
"occurs" is vague and passive. How about "the pars
Kathy Walrath
2013/08/28 08:00:59
Done.
| |
65 * the value for an option is not in the allowed set. | |
66 * Here's an example of specifying allowed values: | |
64 * | 67 * |
65 * parser.addOption('mode', allowed: ['debug', 'release']); | 68 * parser.addOption('mode', allowed: ['debug', 'release']); |
66 * | 69 * |
67 * You can provide a callback when you define an option. When you later parse | 70 * You can use the `callback` parameter |
68 * a set of arguments, the callback for that option will be invoked with the | 71 * to associate a function with an option. Later, when |
69 * value provided for it: | 72 * parsing occurs, the callback function is invoked with the |
73 * value of the option: | |
70 * | 74 * |
71 * parser.addOption('mode', callback: (mode) => print('Got mode $mode)); | 75 * parser.addOption('mode', callback: (mode) => print('Got mode $mode)); |
72 * parser.addFlag('verbose', callback: (verbose) { | 76 * parser.addFlag('verbose', callback: (verbose) { |
73 * if (verbose) print('Verbose'); | 77 * if (verbose) print('Verbose'); |
74 * }); | 78 * }); |
75 * | 79 * |
76 * The callback for each option will *always* be called when you parse a set of | 80 * The callback for each option is *always* called when a set of arguments |
Bob Nystrom
2013/08/27 17:58:10
This might be clearer plural: "the callbacks for e
Kathy Walrath
2013/08/28 08:00:59
Done.
| |
77 * arguments. If the option isn't provided in the args, the callback will be | 81 * is parsed. If the option isn't provided in the args, the callback is |
78 * passed the default value, or `null` if there is none set. | 82 * passed the default value, or `null` if no default value is set. |
79 * | 83 * |
80 * ## Parsing arguments ## | 84 * ## Parsing arguments |
81 * | 85 * |
82 * Once you have an [ArgParser] set up with some options and flags, you use it | 86 * Once you have an [ArgParser] set up with some options and flags, you use it |
83 * by calling [ArgParser.parse()] with a set of arguments: | 87 * by calling [ArgParser.parse()] with a set of arguments: |
84 * | 88 * |
85 * var results = parser.parse(['some', 'command', 'line', 'args']); | 89 * var results = parser.parse(['some', 'command', 'line', 'args']); |
86 * | 90 * |
87 * These will usually come from `new Options().arguments`, but you can pass in | 91 * These arguments usually come from dart:io's Options class |
88 * any list of strings. It returns an instance of [ArgResults]. This is a | 92 * (`new Options().arguments`), |
89 * map-like object that will return the value of any parsed option. | 93 * but you can pass in any list of strings. |
94 * The parse()) method returns an instance of [ArgResults], | |
95 * a map-like object that returns the value of any parsed option. | |
Bob Nystrom
2013/08/27 17:58:10
"returns..." -> "contains the values of the parsed
Kathy Walrath
2013/08/28 08:00:59
Done.
| |
90 * | 96 * |
91 * var parser = new ArgParser(); | 97 * var parser = new ArgParser(); |
92 * parser.addOption('mode'); | 98 * parser.addOption('mode'); |
93 * parser.addFlag('verbose', defaultsTo: true); | 99 * parser.addFlag('verbose', defaultsTo: true); |
94 * var results = parser.parse('['--mode', 'debug', 'something', 'else']); | 100 * var results = parser.parse(['--mode', 'debug', 'something', 'else']); |
95 * | 101 * |
96 * print(results['mode']); // debug | 102 * print(results['mode']); // debug |
97 * print(results['verbose']); // true | 103 * print(results['verbose']); // true |
98 * | 104 * |
99 * The [parse()] method will stop as soon as it reaches `--` or anything that | 105 * The parse() method stops as soon as it reaches `--` by itself |
100 * it doesn't recognize as an option, flag, or option value. If there are still | 106 * or anything that it doesn't recognize as an option, flag, or option value. |
101 * arguments left, they will be provided to you in | 107 * If arguments still remain, they go into |
102 * [ArgResults.rest]. | 108 * [ArgResults.rest]. |
103 * | 109 * |
104 * print(results.rest); // ['something', 'else'] | 110 * print(results.rest); // ['something', 'else'] |
Bob Nystrom
2013/08/27 17:58:10
This is no longer always the case. If you call par
Kathy Walrath
2013/08/28 08:00:59
Done.
| |
105 * | 111 * |
106 * ## Specifying options ## | 112 * ## Specifying options |
107 * | 113 * |
108 * To actually pass in options and flags on the command line, use GNU or POSIX | 114 * To actually pass in options and flags on the command line, use GNU or POSIX |
109 * style. If you define an option like: | 115 * style. Consider this option: |
110 * | 116 * |
111 * parser.addOption('name', abbr: 'n'); | 117 * parser.addOption('name', abbr: 'n'); |
112 * | 118 * |
113 * Then a value for it can be specified on the command line using any of: | 119 * You can specify its value on the command line using any of the following: |
114 * | 120 * |
115 * --name=somevalue | 121 * --name=somevalue |
116 * --name somevalue | 122 * --name somevalue |
117 * -nsomevalue | 123 * -nsomevalue |
118 * -n somevalue | 124 * -n somevalue |
119 * | 125 * |
120 * Given this flag: | 126 * Consider this flag: |
121 * | 127 * |
122 * parser.addFlag('name', abbr: 'n'); | 128 * parser.addFlag('name', abbr: 'n'); |
123 * | 129 * |
124 * You can set it on using one of: | 130 * You can set it to true using one of the following: |
125 * | 131 * |
126 * --name | 132 * --name |
127 * -n | 133 * -n |
128 * | 134 * |
129 * Or set it off using: | 135 * You can set it to false using the following: |
130 * | 136 * |
131 * --no-name | 137 * --no-name |
132 * | 138 * |
133 * Multiple flag abbreviation can also be collapsed into a single argument. If | 139 * Multiple flag abbreviations can be collapsed into a single argument. |
134 * you define: | 140 * Say you define these flags: |
135 * | 141 * |
136 * parser.addFlag('verbose', abbr: 'v'); | 142 * parser.addFlag('verbose', abbr: 'v'); |
137 * parser.addFlag('french', abbr: 'f'); | 143 * parser.addFlag('french', abbr: 'f'); |
138 * parser.addFlag('iambic-pentameter', abbr: 'i'); | 144 * parser.addFlag('iambic-pentameter', abbr: 'i'); |
139 * | 145 * |
140 * Then all three flags could be set using: | 146 * You can set all three flags at once: |
141 * | 147 * |
142 * -vfi | 148 * -vfi |
143 * | 149 * |
144 * By default, an option has only a single value, with later option values | 150 * By default, an option has only a single value, with later option values |
145 * overriding earlier ones; for example: | 151 * overriding earlier ones; for example: |
146 * | 152 * |
147 * var parser = new ArgParser(); | 153 * var parser = new ArgParser(); |
148 * parser.addOption('mode'); | 154 * parser.addOption('mode'); |
149 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); | 155 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); |
150 * print(results['mode']); // prints 'off' | 156 * print(results['mode']); // prints 'off' |
151 * | 157 * |
152 * If you need multiple values, set the [allowMultiple] flag. In that | 158 * If you need multiple values, set the `allowMultiple` parameter. In that |
153 * case the option can occur multiple times and when parsing arguments a | 159 * case the option can occur multiple times, and the parse() method returns a |
154 * List of values will be returned: | 160 * list of values: |
155 * | 161 * |
156 * var parser = new ArgParser(); | 162 * var parser = new ArgParser(); |
157 * parser.addOption('mode', allowMultiple: true); | 163 * parser.addOption('mode', allowMultiple: true); |
158 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); | 164 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); |
159 * print(results['mode']); // prints '[on, off]' | 165 * print(results['mode']); // prints '[on, off]' |
160 * | 166 * |
161 * ## Defining commands ## | 167 * ## Defining commands ## |
162 * | 168 * |
163 * In addition to *options*, you can also define *commands*. A command is a | 169 * In addition to *options*, you can also define *commands*. A command is a |
164 * named argument that has its own set of options. For example, when you run: | 170 * named argument that has its own set of options. For example, |
171 * consider this shell command: | |
165 * | 172 * |
166 * $ git commit -a | 173 * $ git commit -a |
167 * | 174 * |
168 * The executable is `git`, the command is `commit`, and the `-a` option is an | 175 * The executable is `git`, the command is `commit`, and the `-a` option is an |
169 * option passed to the command. You can add a command like so: | 176 * option passed to the command. You can add a command using |
177 * the [addCommand] method: | |
170 * | 178 * |
171 * var parser = new ArgParser(); | 179 * var parser = new ArgParser(); |
172 * var command = parser.addCommand('commit'); | 180 * var command = parser.addCommand('commit'); |
173 * | 181 * |
174 * It returns another [ArgParser] which you can then use to define options | 182 * The addCommand() method |
183 * returns another [ArgParser], which you can then use to define options | |
175 * specific to that command. If you already have an [ArgParser] for the | 184 * specific to that command. If you already have an [ArgParser] for the |
176 * command's options, you can pass it to [addCommand]: | 185 * command's options, you can pass it to addCommand: |
177 * | 186 * |
178 * var parser = new ArgParser(); | 187 * var parser = new ArgParser(); |
179 * var command = new ArgParser(); | 188 * var command = new ArgParser(); |
180 * parser.addCommand('commit', command); | 189 * parser.addCommand('commit', command); |
181 * | 190 * |
182 * The [ArgParser] for a command can then define whatever options or flags: | 191 * The [ArgParser] for a command can then define options or flags: |
183 * | 192 * |
184 * command.addFlag('all', abbr: 'a'); | 193 * command.addFlag('all', abbr: 'a'); |
185 * | 194 * |
186 * You can add multiple commands to the same parser so that a user can select | 195 * You can add multiple commands to the same parser so that a user can select |
187 * one from a range of possible commands. When an argument list is parsed, | 196 * one from a range of possible commands. When parsing an argument list, |
188 * you can then determine which command was entered and what options were | 197 * you can then determine which command was entered and what options were |
189 * provided for it. | 198 * provided for it. |
190 * | 199 * |
191 * var results = parser.parse(['commit', '-a']); | 200 * var results = parser.parse(['commit', '-a']); |
192 * print(results.command.name); // "commit" | 201 * print(results.command.name); // "commit" |
193 * print(results.command['a']); // true | 202 * print(results.command['all']); // true |
194 * | 203 * |
195 * Options for a command must appear after the command in the argument list. | 204 * Options for a command must appear after the command in the argument list. |
196 * For example, given the above parser, "git -a commit" is *not* valid. The | 205 * For example, given the above parser, "git -a commit" is *not* valid. The |
197 * parser will try to find the right-most command that accepts an option. For | 206 * parser tries to find the right-most command that accepts an option. For |
198 * example: | 207 * example: |
199 * | 208 * |
200 * var parser = new ArgParser(); | 209 * var parser = new ArgParser(); |
201 * parser.addFlag('all', abbr: 'a'); | 210 * parser.addFlag('all', abbr: 'a'); |
202 * var command = new ArgParser().addCommand('commit'); | 211 * var command = parser.addCommand('commit'); |
203 * parser.addFlag('all', abbr: 'a'); | 212 * command.addFlag('all', abbr: 'a'); |
213 * | |
204 * var results = parser.parse(['commit', '-a']); | 214 * var results = parser.parse(['commit', '-a']); |
205 * print(results.command['a']); // true | 215 * print(results.command['all']); // true |
206 * | 216 * |
207 * Here, both the top-level parser and the "commit" command can accept a "-a" | 217 * Here, both the top-level parser and the "commit" command can accept a "-a" |
208 * (which is probably a bad command line interface, admittedly). In that case, | 218 * (which is probably a bad command line interface, admittedly). In that case, |
209 * when "-a" appears after "commit", it will be applied to that command. If it | 219 * when "-a" appears after "commit", it is applied to that command. If it |
210 * appears to the left of "commit", it will be given to the top-level parser. | 220 * appears to the left of "commit", it is given to the top-level parser. |
211 * | 221 * |
212 * ## Displaying usage ## | 222 * ## Displaying usage |
213 * | 223 * |
214 * This library can also be used to automatically generate nice usage help | 224 * This library can automatically generate nice usage help |
215 * text like you get when you run a program with `--help`. To use this, you | 225 * text like you get when you run a program with `--help`. To use this, you |
216 * will also want to provide some help text when you create your options. To | 226 * should provide some help text when you create your options. To |
217 * define help text for the entire option, do: | 227 * define help text for an entire option, use the `help` parameter: |
218 * | 228 * |
219 * parser.addOption('mode', help: 'The compiler configuration', | 229 * parser.addOption('mode', help: 'The compiler configuration', |
220 * allowed: ['debug', 'release']); | 230 * allowed: ['debug', 'release']); |
221 * parser.addFlag('verbose', help: 'Show additional diagnostic info'); | 231 * parser.addFlag('verbose', help: 'Show additional diagnostic info'); |
222 * | 232 * |
223 * For non-flag options, you can also provide detailed help for each expected | 233 * For non-flag options, you can also provide detailed help for each expected |
224 * value using a map: | 234 * value by using the `allowedHelp` parameter: |
225 * | 235 * |
226 * parser.addOption('arch', help: 'The architecture to compile for', | 236 * parser.addOption('arch', help: 'The architecture to compile for', |
227 * allowedHelp: { | 237 * allowedHelp: { |
228 * 'ia32': 'Intel x86', | 238 * 'ia32': 'Intel x86', |
229 * 'arm': 'ARM Holding 32-bit chip' | 239 * 'arm': 'ARM Holding 32-bit chip' |
230 * }); | 240 * }); |
231 * | 241 * |
232 * If you define a set of options like the above, then calling this: | 242 * To display the help, use the ArgParser getUsage() method: |
233 * | 243 * |
234 * print(parser.getUsage()); | 244 * print(parser.getUsage()); |
235 * | 245 * |
236 * Will display something like: | 246 * The resulting string looks something like this: |
237 * | 247 * |
238 * --mode The compiler configuration | 248 * --mode The compiler configuration |
239 * [debug, release] | 249 * [debug, release] |
240 * | 250 * |
241 * --[no-]verbose Show additional diagnostic info | 251 * --[no-]verbose Show additional diagnostic info |
242 * --arch The architecture to compile for | 252 * --arch The architecture to compile for |
243 * | 253 * |
244 * [arm] ARM Holding 32-bit chip | 254 * [arm] ARM Holding 32-bit chip |
245 * [ia32] Intel x86 | 255 * [ia32] Intel x86 |
246 * | 256 * |
247 * To assist the formatting of the usage help, single line help text will | 257 * To assist the formatting of the usage help, single-line help text |
248 * be followed by a single new line. Options with multi-line help text | 258 * is followed by a single new line. Options with multi-line help text |
249 * will be followed by two new lines. This provides spatial diversity between | 259 * are followed by two new lines. This provides spatial diversity between |
250 * options. | 260 * options. |
251 * | 261 * |
252 * [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.h tml#tag_12_02 | 262 * [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.h tml#tag_12_02 |
253 * [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Inte rfaces | 263 * [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Inte rfaces |
254 * [pub]: http://pub.dartlang.org | |
255 */ | 264 */ |
256 library args; | 265 library args; |
257 | 266 |
258 import 'package:unmodifiable_collection/unmodifiable_collection.dart'; | 267 import 'package:unmodifiable_collection/unmodifiable_collection.dart'; |
259 | 268 |
260 import 'src/parser.dart'; | 269 import 'src/parser.dart'; |
261 import 'src/usage.dart'; | 270 import 'src/usage.dart'; |
262 import 'src/options.dart'; | 271 import 'src/options.dart'; |
263 export 'src/options.dart'; | 272 export 'src/options.dart'; |
264 | 273 |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 'Could not find an option named "$name".'); | 448 'Could not find an option named "$name".'); |
440 } | 449 } |
441 | 450 |
442 return _options[name]; | 451 return _options[name]; |
443 } | 452 } |
444 | 453 |
445 /** Get the names of the options as an [Iterable]. */ | 454 /** Get the names of the options as an [Iterable]. */ |
446 Iterable<String> get options => _options.keys; | 455 Iterable<String> get options => _options.keys; |
447 } | 456 } |
448 | 457 |
OLD | NEW |