Skip to content

Commit

Permalink
Merge pull request #2049 from AndrejMitrovic/Fix5316
Browse files Browse the repository at this point in the history
std.getopt: Add character-separated elements support for arrays and associative arrays
  • Loading branch information
andralex committed Apr 1, 2014
2 parents 7a94226 + 9924b7a commit 74d3947
Showing 1 changed file with 145 additions and 16 deletions.
161 changes: 145 additions & 16 deletions std/getopt.d
Expand Up @@ -182,7 +182,18 @@ getopt(args, "output", &outputFiles);
Invoking the program with "--output=myfile.txt --output=yourfile.txt"
or "--output myfile.txt --output yourfile.txt" will set $(D
outputFiles) to [ "myfile.txt", "yourfile.txt" ] .)
outputFiles) to [ "myfile.txt", "yourfile.txt" ].
Alternatively you can set $(LREF arraySep) as the element separator:
---------
string[] outputFiles;
arraySep = ","; // defaults to "", separation by whitespace
getopt(args, "output", &outputFiles);
---------
With the above code you can invoke the program with
"--output=myfile.txt,yourfile.txt", or "--output myfile.txt,yourfile.txt".)
$(LI $(I Hash options.) If an option is bound to an associative
array, a string of the form "name=value" is expected as the next
Expand All @@ -194,8 +205,20 @@ getopt(args, "tune", &tuningParms);
---------
Invoking the program with e.g. "--tune=alpha=0.5 --tune beta=0.6" will
set $(D tuningParms) to [ "alpha" : 0.5, "beta" : 0.6 ]. In general,
keys and values can be of any parsable types.)
set $(D tuningParms) to [ "alpha" : 0.5, "beta" : 0.6 ].
Alternatively you can set $(LREF arraySep) as the element separator:
---------
double[string] tuningParms;
arraySep = ","; // defaults to "", separation by whitespace
getopt(args, "tune", &tuningParms);
---------
With the above code you can invoke the program with
"--tune=alpha=0.5,beta=0.6", or "--tune alpha=0.5,beta=0.6".
In general, the keys and values can be of any parsable types.
$(LI $(I Callback options.) An option can be bound to a function or
delegate with the signature $(D void function()), $(D void function(string option)),
Expand Down Expand Up @@ -553,16 +576,45 @@ void handleOption(R)(string option, R receiver, ref string[] args,
else static if (isArray!(typeof(*receiver)))
{
// array receiver
*receiver ~= [ to!(typeof((*receiver)[0]))(val) ];
import std.range : ElementEncodingType;
alias E = ElementEncodingType!(typeof(*receiver));

if (arraySep == "")
{
*receiver ~= to!E(val);
}
else
{
foreach (elem; val.splitter(arraySep).map!(a => to!E(a)))
*receiver ~= elem;
}
}
else static if (isAssociativeArray!(typeof(*receiver)))
{
// hash receiver
alias K = typeof(receiver.keys[0]);
alias V = typeof(receiver.values[0]);
auto j = std.string.indexOf(val, assignChar);
auto key = val[0 .. j], value = val[j + 1 .. $];
(*receiver)[to!(K)(key)] = to!(V)(value);

static Tuple!(K, V) getter(string input)
{
auto j = std.string.indexOf(input, assignChar);
auto key = input[0 .. j];
auto value = input[j + 1 .. $];
return tuple(to!K(key), to!V(value));
}

static void setHash(Range)(R receiver, Range range)
{
foreach (k, v; range.map!getter)
(*receiver)[k] = v;
}

import std.range : only;

if (arraySep == "")
setHash(receiver, val.only);
else
setHash(receiver, val.splitter(arraySep));
}
else
{
Expand All @@ -573,6 +625,61 @@ void handleOption(R)(string option, R receiver, ref string[] args,
}
}

// 5316 - arrays with arraySep
unittest
{
arraySep = ",";
scope (exit) arraySep = "";

string[] names;
auto args = ["program.name", "-nfoo,bar,baz"];
getopt(args, "name|n", &names);
assert(names == ["foo", "bar", "baz"], to!string(names));

names = names.init;
args = ["program.name", "-n" "foo,bar,baz"].dup;
getopt(args, "name|n", &names);
assert(names == ["foo", "bar", "baz"], to!string(names));

names = names.init;
args = ["program.name", "--name=foo,bar,baz"].dup;
getopt(args, "name|n", &names);
assert(names == ["foo", "bar", "baz"], to!string(names));

names = names.init;
args = ["program.name", "--name", "foo,bar,baz"].dup;
getopt(args, "name|n", &names);
assert(names == ["foo", "bar", "baz"], to!string(names));
}

// 5316 - associative arrays with arraySep
unittest
{
arraySep = ",";
scope (exit) arraySep = "";

int[string] values;
values = values.init;
auto args = ["program.name", "-vfoo=0,bar=1,baz=2"].dup;
getopt(args, "values|v", &values);
assert(values == ["foo":0, "bar":1, "baz":2], to!string(values));

values = values.init;
args = ["program.name", "-v", "foo=0,bar=1,baz=2"].dup;
getopt(args, "values|v", &values);
assert(values == ["foo":0, "bar":1, "baz":2], to!string(values));

values = values.init;
args = ["program.name", "--values=foo=0,bar=1,baz=2"];
getopt(args, "values|t", &values);
assert(values == ["foo":0, "bar":1, "baz":2], to!string(values));

values = values.init;
args = ["program.name", "--values", "foo=0,bar=1,baz=2"].dup;
getopt(args, "values|v", &values);
assert(values == ["foo":0, "bar":1, "baz":2], to!string(values));
}

/**
The option character (default '-').
Expand All @@ -595,6 +702,14 @@ string endOfOptions = "--";
*/
dchar assignChar = '=';

/**
The string used to separate the elements of an array or associative array
(default is "" which means the elements are separated by whitespace).
Defaults to "" but can be assigned to prior to calling $(D getopt).
*/
string arraySep = "";

enum autoIncrementChar = '+';

private struct configuration
Expand Down Expand Up @@ -715,16 +830,30 @@ unittest
"--output", "yourfile.txt"]).dup;
getopt(args, "output", &outputFiles);
assert(outputFiles.length == 2
&& outputFiles[0] == "myfile.txt" && outputFiles[0] == "myfile.txt");
&& outputFiles[0] == "myfile.txt" && outputFiles[1] == "yourfile.txt");

args = (["program.name", "--tune=alpha=0.5",
"--tune", "beta=0.6"]).dup;
double[string] tuningParms;
getopt(args, "tune", &tuningParms);
assert(args.length == 1);
assert(tuningParms.length == 2);
assert(approxEqual(tuningParms["alpha"], 0.5));
assert(approxEqual(tuningParms["beta"], 0.6));
outputFiles = [];
arraySep = ",";
args = (["program.name", "--output", "myfile.txt,yourfile.txt"]).dup;
getopt(args, "output", &outputFiles);
assert(outputFiles.length == 2
&& outputFiles[0] == "myfile.txt" && outputFiles[1] == "yourfile.txt");
arraySep = "";

foreach (testArgs;
[["program.name", "--tune=alpha=0.5", "--tune", "beta=0.6"],
["program.name", "--tune=alpha=0.5,beta=0.6"],
["program.name", "--tune", "alpha=0.5,beta=0.6"]])
{
arraySep = ",";
double[string] tuningParms;
getopt(testArgs, "tune", &tuningParms);
assert(testArgs.length == 1);
assert(tuningParms.length == 2);
assert(approxEqual(tuningParms["alpha"], 0.5));
assert(approxEqual(tuningParms["beta"], 0.6));
arraySep = "";
}

uint verbosityLevel = 1;
void myHandler(string option)
Expand Down

0 comments on commit 74d3947

Please sign in to comment.