| 1 |
--Tango Arguments - Flexible argument string parsing. |
|---|
| 2 |
|
|---|
| 3 |
-Introduction |
|---|
| 4 |
|
|---|
| 5 |
Arguments is a module for parsing argument strings, such as command line arguments passed to main(). It is an extrememly flexible module, able to accomodate a wide variety of desired parsing behavior. Arguments follows a declarative paradigm, requiring the programmer to tell it some basic information about the arguments and any possible parameters. However, it also will parse a given string using a default set of actions that covers most basic use cases. |
|---|
| 6 |
|
|---|
| 7 |
Here's the most basic example of using Arguments: |
|---|
| 8 |
|
|---|
| 9 |
void main(char[][] cmdl) |
|---|
| 10 |
{ |
|---|
| 11 |
auto args = new Arguments(cmdl[1..$]); |
|---|
| 12 |
} |
|---|
| 13 |
|
|---|
| 14 |
And that's it. If the program were called with, say, a command line like: |
|---|
| 15 |
|
|---|
| 16 |
myProgram -a=read --files text1.txt text2.txt |
|---|
| 17 |
|
|---|
| 18 |
Then you would be able to perform the following operations: |
|---|
| 19 |
|
|---|
| 20 |
if ("a" in args) |
|---|
| 21 |
char[] action = args["a"][0]; |
|---|
| 22 |
... do something cool |
|---|
| 23 |
|
|---|
| 24 |
if ("files" in args) |
|---|
| 25 |
char[][] processFiles = args["files"]; |
|---|
| 26 |
|
|---|
| 27 |
And so on. This is the basic operation mode of Arguments, and it's designed to get you up and running quickly with a minimum of fuss. However, there is a lot more going on under the hood than just this, if you tell Arguments a little bit of information beforehand, it becomes quite powerful in it's ability to decipher argument strings into something coherant for your particular program. |
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
Here's a slightly more complex example: |
|---|
| 31 |
|
|---|
| 32 |
void main(char[][] cmdl) |
|---|
| 33 |
{ |
|---|
| 34 |
auto args = new Arguments; |
|---|
| 35 |
args.define("a").parameter; |
|---|
| 36 |
args.define("b"); |
|---|
| 37 |
args.parse(cmdl[1..$]); |
|---|
| 38 |
} |
|---|
| 39 |
|
|---|
| 40 |
Here, we've told Arguments a little bit of what we're expecting, by using the .define method. This method is what allows you to set up argument definitions, and there are quite a variety of chaining methods that you can use along with a define. We'll get into them all a little later on. For now, let's accept that .define("a").parameter tells us that the argument "a" expects to get a parameter, and that .define("b") tells us that while we can expect to see a "b", it doesn't take any parameters. |
|---|
| 41 |
|
|---|
| 42 |
With that information, if the program were called with a command line like: |
|---|
| 43 |
|
|---|
| 44 |
myProgram -b -a hello |
|---|
| 45 |
|
|---|
| 46 |
Then we can know that we now have '"b" in args' and that 'args["a"] contains "hello"', as one would reasonably expect. |
|---|
| 47 |
|
|---|
| 48 |
But wait, you say. Isn't that the same thing that would have happened if I hadn't made any definitions at all? Why did I waste my time calling .define? |
|---|
| 49 |
|
|---|
| 50 |
You are indeed astute, young grasshopper. Your efforts in calling .define were not in vain, however, and here's why. |
|---|
| 51 |
|
|---|
| 52 |
Assume that instead of the above command line, you were instead called like this: |
|---|
| 53 |
|
|---|
| 54 |
myProgram -ab hello |
|---|
| 55 |
|
|---|
| 56 |
Which you want to have parsed the same way as the previous command line. Well, without having defined your arguments beforehand, Arguments would have parsed that as: |
|---|
| 57 |
|
|---|
| 58 |
"a" in args |
|---|
| 59 |
"b" in args |
|---|
| 60 |
args["b"][0] = "hello" |
|---|
| 61 |
|
|---|
| 62 |
Which isn't quite right. However, we did tell Arguments about how we wanted our command line parsed beforehand, and because it already knows that "a" takes a parameter but that "b" does not, it will have parsed that line the same as the previous. In other words, because we gave it a little bit of information beforehand, the command lines: |
|---|
| 63 |
|
|---|
| 64 |
myProgram -b -a hello |
|---|
| 65 |
myProgram -ab hello |
|---|
| 66 |
|
|---|
| 67 |
Will not appear any differently to our program, transparently to us using Arguments, those two command lines are the same. This is some of the power and flexibility of Arguments. But that just barely scratches the surface. |
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
-Background |
|---|
| 71 |
|
|---|
| 72 |
Arguments was designed to be as flexible as possible, and to support a wide variety of command-line paradigms while still maintaining a declarative nature, as opposed to format-string style parsers that are inheriently less flexible with regards to positioning, and also require the user to have some knowledge of some arcane syntax. It does, however, follow a few conventions which the user should be familiar with. |
|---|
| 73 |
|
|---|
| 74 |
-Terminology |
|---|
| 75 |
|
|---|
| 76 |
argument |
|---|
| 77 |
an argument is one particular item that will be queryable post-parse. Given a command string '-a -b --cde', all of "a", "b", and "cde" are arguments. There are also two distinct types of arguments, long and short. |
|---|
| 78 |
short argument |
|---|
| 79 |
a short argument is a single character, prefixed by the short-argument prefix (by default, this is "-"). Short arguments may be collected together, for example, "-a -b" and "-ab" are identical. |
|---|
| 80 |
long argument |
|---|
| 81 |
a long argument is a series of characters, prefixed by the long-argument prefix (by default, this is "--"). Long arguments may not be collected together. |
|---|
| 82 |
|
|---|
| 83 |
parameter |
|---|
| 84 |
a parameter is an attribute of one particular argument. There may be multiple parameters for any given argument. Given a command string '-a 1' and assuming a basic parse, "a" is an argument, and "1" is a parameter to "a". |
|---|
| 85 |
standard parameter |
|---|
| 86 |
parameters can also directly follow arguments if they are delimited by a delimiter (by default, they are ":" and "="). So, '-a 1', '-a:1', and '-a=1' are all identical. |
|---|
| 87 |
implicit parameters |
|---|
| 88 |
a parameter that has no associated argument. This can happen if all arguments are defined not to take any parameters, or if no arguments were given at all. implicit arguments are availble after parse in args[null]. |
|---|
| 89 |
|
|---|
| 90 |
-The function of command line arguments |
|---|
| 91 |
|
|---|
| 92 |
Command line arguments typically provide information that customizes the program execution. These given arguments may be required or optional, the Arguments module itself does not presume to tell you how your program should function, it's up to you to tell it how you want it to work. |
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
--Reference |
|---|
| 96 |
|
|---|
| 97 |
-Overview |
|---|
| 98 |
|
|---|
| 99 |
First, you import the Arguments module. |
|---|
| 100 |
|
|---|
| 101 |
import tango.whatever.Arguments; |
|---|
| 102 |
|
|---|
| 103 |
The, you create a new Arguments instance: |
|---|
| 104 |
|
|---|
| 105 |
auto args = new Arguments; |
|---|
| 106 |
|
|---|
| 107 |
If you pass the Arguments constructor the string you'd like it to parse, you can be done right here. |
|---|
| 108 |
|
|---|
| 109 |
auto args = new Arguments(cmdl[1..$]); |
|---|
| 110 |
|
|---|
| 111 |
Otherwise, after creating your new arguments, you will then set up any needed configuration: |
|---|
| 112 |
|
|---|
| 113 |
args.prefixLong ~= ["%%"]; |
|---|
| 114 |
args.define("x").required.parameters(0,1); |
|---|
| 115 |
|
|---|
| 116 |
And then finally, call parse: |
|---|
| 117 |
|
|---|
| 118 |
args.parse(cmdl[1..$]); |
|---|
| 119 |
|
|---|
| 120 |
After which, can you then access the information parsed from your command line string. |
|---|
| 121 |
|
|---|
| 122 |
if ("x" in args) {} |
|---|
| 123 |
char[] myVal = (args["value"][0]); |
|---|
| 124 |
etc.. |
|---|
| 125 |
|
|---|
| 126 |
-args.prefixShort |
|---|
| 127 |
|
|---|
| 128 |
-args.prefixLong |
|---|
| 129 |
|
|---|
| 130 |
-args.delimiters |
|---|
| 131 |
|
|---|
| 132 |
-args.reset |
|---|
| 133 |
|
|---|
| 134 |
-args.remove |
|---|
| 135 |
|
|---|
| 136 |
-args.count |
|---|
| 137 |
|
|---|
| 138 |
-args.define |
|---|
| 139 |
|
|---|
| 140 |
--define.parameters |
|---|
| 141 |
--define.defaults |
|---|
| 142 |
--define.delimiters |
|---|
| 143 |
--define.required |
|---|
| 144 |
--define.aliases |
|---|
| 145 |
--define.conflicts |
|---|
| 146 |
--define.requires |
|---|
| 147 |
--define.callback |
|---|
| 148 |
--define.validation |
|---|
| 149 |
|
|---|
| 150 |
-how to generate help text |
|---|
| 151 |
|
|---|
| 152 |
-some sample use cases |
|---|
| 153 |
long arguments with single hyphen |
|---|
| 154 |
myProg -pf -> (args["pf") |
|---|
| 155 |
|
|---|
| 156 |
different prefixes |
|---|
| 157 |
myProg +f +rgb |
|---|
| 158 |
myProg /file |
|---|
| 159 |
|
|---|
| 160 |
no delimiters |
|---|
| 161 |
myProg -ffile1.txt |
|---|