mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-04 07:04:39 +00:00
Merge pull request #121 from skrobinson/wip-add-scan-docs
Document and use Argument.scan where possible
This commit is contained in:
commit
4d03fc04b2
53
README.md
53
README.md
@ -53,7 +53,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
program.add_argument("square")
|
||||
.help("display the square of a given integer")
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
try {
|
||||
program.parse_args(argc, argv);
|
||||
@ -81,7 +81,7 @@ $ ./main 15
|
||||
Here's what's happening:
|
||||
|
||||
* The ```add_argument()``` method is used to specify which command-line options the program is willing to accept. In this case, I’ve named it square so that it’s in line with its function.
|
||||
* Command-line arguments are strings. Inorder to square the argument and print the result, we need to convert this argument to a number. In order to do this, we use the ```.action``` method and provide a lambda function that tries to convert user input into an integer.
|
||||
* Command-line arguments are strings. To square the argument and print the result, we need to convert this argument to a number. In order to do this, we use the ```.scan``` method to convert user input into an integer.
|
||||
* We can get the value stored by the parser for a given argument using ```parser.get<T>(key)``` method.
|
||||
|
||||
### Optional Arguments
|
||||
@ -209,12 +209,12 @@ argparse::ArgumentParser program;
|
||||
|
||||
program.add_argument("integer")
|
||||
.help("Input number")
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
program.add_argument("floats")
|
||||
.help("Vector of floats")
|
||||
.nargs(4)
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
try {
|
||||
program.parse_args(argc, argv);
|
||||
@ -243,7 +243,7 @@ argparse::ArgumentParser program("test");
|
||||
|
||||
program.add_argument("square")
|
||||
.help("display the square of a given number")
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
program.add_argument("--verbose")
|
||||
.default_value(false)
|
||||
@ -326,7 +326,7 @@ auto files = program.get<std::vector<std::string>>("--input_files"); // {"confi
|
||||
auto files = program.get<std::list<std::string>>("--input_files"); // {"config.yml", "System.xml"}
|
||||
```
|
||||
|
||||
Using ```.action```, one can quickly build a list of desired value types from command line arguments. Here's an example:
|
||||
Using ```.scan```, one can quickly build a list of desired value types from command line arguments. Here's an example:
|
||||
|
||||
```cpp
|
||||
argparse::ArgumentParser program("main");
|
||||
@ -335,7 +335,7 @@ program.add_argument("--query_point")
|
||||
.help("3D query point")
|
||||
.nargs(3)
|
||||
.default_value(std::vector<double>{0.0, 0.0, 0.0})
|
||||
.action([](const std::string& value) { return std::stod(value); });
|
||||
.scan<'g', double>();
|
||||
|
||||
try {
|
||||
program.parse_args(argc, argv); // Example: ./main --query_point 3.5 4.7 9.2
|
||||
@ -367,7 +367,7 @@ program.add_argument("-b")
|
||||
program.add_argument("-c")
|
||||
.nargs(2)
|
||||
.default_value(std::vector<float>{0.0f, 0.0f})
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
try {
|
||||
program.parse_args(argc, argv); // Example: ./main -abc 1.95 2.47
|
||||
@ -406,6 +406,37 @@ Here's what's happening:
|
||||
- argv is further parsed to identify the inputs mapped to ```-c```.
|
||||
- If argparse cannot find any arguments to map to c, then c defaults to {0.0, 0.0} as defined by ```.default_value```
|
||||
|
||||
### Converting to Numeric Types
|
||||
|
||||
For inputs, users can express a primitive type for the value.
|
||||
|
||||
The ```.scan<Shape, T>``` method attempts to convert the incoming `std::string` to `T` following the `Shape` conversion specifier. An `std::invalid_argument` or `std::range_error` exception is thrown for errors.
|
||||
|
||||
```cpp
|
||||
program.add_argument("-x")
|
||||
.scan<'d', int>();
|
||||
|
||||
program.add_argument("scale")
|
||||
.scan<'g', double>();
|
||||
```
|
||||
|
||||
`Shape` specifies what the input "looks like", and the type template argument specifies the return value of the predefined action. Acceptable types are floating point (i.e float, double, long double) and integral (i.e. signed char, short, int, long, long long).
|
||||
|
||||
The grammar follows `std::from_chars`, but does not exactly duplicate it. For example, hexadecimal numbers may begin with `0x` or `0X` and numbers with a leading zero may be handled as octal values.
|
||||
|
||||
| Shape | interpretation |
|
||||
| :--------: | ----------------------------------------- |
|
||||
| 'a' or 'A' | hexadecimal floating point |
|
||||
| 'e' or 'E' | scientific notation (floating point) |
|
||||
| 'f' or 'F' | fixed notation (floating point) |
|
||||
| 'g' or 'G' | general form (either fixed or scientific) |
|
||||
| | |
|
||||
| 'd' | decimal |
|
||||
| 'i' | `std::from_chars` grammar with base == 0 |
|
||||
| 'o' | octal (unsigned) |
|
||||
| 'u' | decimal (unsigned) |
|
||||
| 'x' or 'X' | hexadecimal (unsigned) |
|
||||
|
||||
### Gathering Remaining Arguments
|
||||
|
||||
`argparse` supports gathering "remaining" arguments at the end of the command, e.g., for use in a compiler:
|
||||
@ -521,7 +552,7 @@ Sometimes, several parsers share a common set of arguments. Rather than repeatin
|
||||
argparse::ArgumentParser parent_parser("main");
|
||||
parent_parser.add_argument("--parent")
|
||||
.default_value(0)
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
argparse::ArgumentParser foo_parser("foo");
|
||||
foo_parser.add_argument("foo");
|
||||
@ -570,7 +601,7 @@ argparse::ArgumentParser program("test");
|
||||
|
||||
program.add_argument("numbers")
|
||||
.nargs(3)
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
program.add_argument("-a")
|
||||
.default_value(false)
|
||||
@ -582,7 +613,7 @@ program.add_argument("-b")
|
||||
|
||||
program.add_argument("-c")
|
||||
.nargs(2)
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
program.add_argument("--files")
|
||||
.nargs(3);
|
||||
|
@ -26,7 +26,7 @@ TEST_CASE("Two int .append" * test_suite("append")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--factor")
|
||||
.append()
|
||||
.action([](auto s) { return stoi(s); });
|
||||
.scan<'i', int>();
|
||||
program.parse_args({ "test", "--factor", "2", "--factor", "5" });
|
||||
auto result { program.get<std::vector<int>>("--factor") };
|
||||
REQUIRE(result.at(0) == 2);
|
||||
|
@ -38,7 +38,7 @@ TEST_CASE("Parse compound toggle arguments with implicit values and nargs" *
|
||||
|
||||
program.add_argument("-c")
|
||||
.nargs(2)
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
program.add_argument("--input_files")
|
||||
.nargs(3);
|
||||
@ -65,7 +65,7 @@ TEST_CASE("Parse compound toggle arguments with implicit values and nargs and "
|
||||
|
||||
program.add_argument("numbers")
|
||||
.nargs(3)
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
program.add_argument("-a")
|
||||
.default_value(false)
|
||||
@ -77,7 +77,7 @@ TEST_CASE("Parse compound toggle arguments with implicit values and nargs and "
|
||||
|
||||
program.add_argument("-c")
|
||||
.nargs(2)
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
program.add_argument("--input_files")
|
||||
.nargs(3);
|
||||
@ -99,7 +99,7 @@ TEST_CASE("Parse out-of-order compound arguments" *
|
||||
|
||||
program.add_argument("-c")
|
||||
.nargs(2)
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
program.parse_args({ "./main", "-cab", "3.14", "2.718" });
|
||||
|
||||
@ -126,7 +126,7 @@ TEST_CASE("Parse out-of-order compound arguments. Second variation" *
|
||||
program.add_argument("-c")
|
||||
.nargs(2)
|
||||
.default_value(std::vector<float>{0.0f, 0.0f})
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
program.parse_args({"./main", "-cb"});
|
||||
|
||||
|
@ -33,7 +33,7 @@ TEST_CASE("Parse unknown optional argument" *
|
||||
|
||||
bfm.add_argument("-m", "--mem")
|
||||
.default_value(64ULL)
|
||||
.action([](const std::string& val) { return std::stoull(val); })
|
||||
.scan<'u', unsigned long long>()
|
||||
.help("memory in MB to give the VMM when loading");
|
||||
|
||||
REQUIRE_THROWS(bfm.parse_args({ "./test.exe", "-om" }));
|
||||
|
@ -31,7 +31,7 @@ TEST_CASE("Issues with implicit values #37" * test_suite("implicit_values")) {
|
||||
m_bfm.add_argument("-m", "--mem")
|
||||
.default_value(100)
|
||||
.required()
|
||||
.action([](const std::string &val) { return std::stoull(val); })
|
||||
.scan<'u', unsigned long long>()
|
||||
.help("memory in MB to give the VMM when loading");
|
||||
m_bfm.parse_args({ "test", "-l", "blah", "-d", "-u" });
|
||||
|
||||
|
@ -12,7 +12,7 @@ TEST_CASE("Parse negative integer" * test_suite("positional_arguments")) {
|
||||
|
||||
program.add_argument("number")
|
||||
.help("Input number")
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
program.parse_args({"./main", "-1"});
|
||||
REQUIRE(program.get<int>("number") == -1);
|
||||
@ -29,7 +29,7 @@ TEST_CASE("Parse negative integers into a vector" *
|
||||
program.add_argument("number")
|
||||
.help("Input number")
|
||||
.nargs(3)
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
program.parse_args({"./main", "-1", "-2", "3"});
|
||||
REQUIRE(program["number"] == std::vector<int>{-1, -2, 3});
|
||||
@ -44,7 +44,7 @@ TEST_CASE("Parse negative float" * test_suite("positional_arguments")) {
|
||||
|
||||
program.add_argument("number")
|
||||
.help("Input number")
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
|
||||
program.parse_args({"./main", "-1.0"});
|
||||
REQUIRE(program.get<float>("number") == -1.0);
|
||||
@ -61,7 +61,7 @@ TEST_CASE("Parse negative floats into a vector" *
|
||||
program.add_argument("number")
|
||||
.help("Input number")
|
||||
.nargs(3)
|
||||
.action([](const std::string& value) { return std::stod(value); });
|
||||
.scan<'g', double>();
|
||||
|
||||
program.parse_args({"./main", "-1.001", "-2.002", "3.003"});
|
||||
REQUIRE(program["number"] == std::vector<double>{-1.001, -2.002, 3.003});
|
||||
@ -76,7 +76,7 @@ TEST_CASE("Parse numbers in E notation" * test_suite("positional_arguments")) {
|
||||
|
||||
program.add_argument("number")
|
||||
.help("Input number")
|
||||
.action([](const std::string& value) { return std::stod(value); });
|
||||
.scan<'g', double>();
|
||||
|
||||
program.parse_args({"./main", "-1.2e3"});
|
||||
REQUIRE(program.get<double>("number") == -1200.0);
|
||||
@ -92,7 +92,7 @@ TEST_CASE("Parse numbers in E notation (capital E)" *
|
||||
|
||||
program.add_argument("number")
|
||||
.help("Input number")
|
||||
.action([](const std::string& value) { return std::stod(value); });
|
||||
.scan<'g', double>();
|
||||
|
||||
program.parse_args({"./main", "-1.32E4"});
|
||||
REQUIRE(program.get<double>("number") == -13200.0);
|
||||
|
@ -85,8 +85,7 @@ TEST_CASE("Parse optional arguments of many values" *
|
||||
test_suite("optional_arguments")) {
|
||||
GIVEN("a program that accepts an optional argument of many values") {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("-i").remaining().action(
|
||||
[](const std::string &value) { return std::stoi(value); });
|
||||
program.add_argument("-i").remaining().scan<'i', int>();
|
||||
|
||||
WHEN("provided no argument") {
|
||||
THEN("the program accepts it but gets nothing") {
|
||||
|
@ -21,7 +21,7 @@ TEST_CASE("Add parent to multiple parent parsers" *
|
||||
argparse::ArgumentParser parent_parser("main");
|
||||
parent_parser.add_argument("--parent")
|
||||
.default_value(0)
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
|
||||
argparse::ArgumentParser foo_parser("foo");
|
||||
foo_parser.add_argument("foo");
|
||||
|
@ -48,7 +48,7 @@ TEST_CASE("Parse a string argument without default value" *
|
||||
TEST_CASE("Parse an int argument with value" * test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--count")
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
program.parse_args({ "test", "--count", "5" });
|
||||
REQUIRE(program.get<int>("--count") == 5);
|
||||
}
|
||||
@ -58,7 +58,7 @@ TEST_CASE("Parse an int argument with default value" *
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--count")
|
||||
.default_value(2)
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
program.parse_args({ "test", "--count" });
|
||||
REQUIRE(program.get<int>("--count") == 2);
|
||||
}
|
||||
@ -66,7 +66,7 @@ TEST_CASE("Parse an int argument with default value" *
|
||||
TEST_CASE("Parse a float argument with value" * test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--ratio")
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
program.parse_args({ "test", "--ratio", "5.6645" });
|
||||
REQUIRE(program.get<float>("--ratio") == 5.6645f);
|
||||
}
|
||||
@ -76,7 +76,7 @@ TEST_CASE("Parse a float argument with default value" *
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--ratio")
|
||||
.default_value(3.14f)
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
program.parse_args({ "test", "--ratio" });
|
||||
REQUIRE(program.get<float>("--ratio") == 3.14f);
|
||||
}
|
||||
@ -84,7 +84,7 @@ TEST_CASE("Parse a float argument with default value" *
|
||||
TEST_CASE("Parse a double argument with value" * test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--ratio")
|
||||
.action([](const std::string& value) { return std::stod(value); });
|
||||
.scan<'g', double>();
|
||||
program.parse_args({ "test", "--ratio", "5.6645" });
|
||||
REQUIRE(program.get<double>("--ratio") == 5.6645);
|
||||
}
|
||||
@ -94,7 +94,7 @@ TEST_CASE("Parse a double argument with default value" *
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--ratio")
|
||||
.default_value(3.14)
|
||||
.action([](const std::string& value) { return std::stod(value); });
|
||||
.scan<'g', double>();
|
||||
program.parse_args({ "test", "--ratio" });
|
||||
REQUIRE(program.get<double>("--ratio") == 3.14);
|
||||
}
|
||||
@ -103,7 +103,7 @@ TEST_CASE("Parse a vector of integer arguments" * test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--vector")
|
||||
.nargs(5)
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
program.parse_args({ "test", "--vector", "1", "2", "3", "4", "5" });
|
||||
auto vector = program.get<std::vector<int>>("--vector");
|
||||
REQUIRE(vector.size() == 5);
|
||||
@ -118,7 +118,7 @@ TEST_CASE("Parse a vector of float arguments" * test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--vector")
|
||||
.nargs(5)
|
||||
.action([](const std::string& value) { return std::stof(value); });
|
||||
.scan<'g', float>();
|
||||
program.parse_args({ "test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5" });
|
||||
auto vector = program.get<std::vector<float>>("--vector");
|
||||
REQUIRE(vector.size() == 5);
|
||||
@ -132,7 +132,7 @@ TEST_CASE("Parse a vector of float arguments" * test_suite("parse_args")) {
|
||||
TEST_CASE("Parse a vector of float without default value" *
|
||||
test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--vector").scan<'f', float>().nargs(3);
|
||||
program.add_argument("--vector").scan<'g', float>().nargs(3);
|
||||
|
||||
WHEN("no value is provided") {
|
||||
program.parse_args({"test"});
|
||||
@ -164,7 +164,7 @@ TEST_CASE("Parse a vector of double arguments" * test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--vector")
|
||||
.nargs(5)
|
||||
.action([](const std::string& value) { return std::stod(value); });
|
||||
.scan<'g', double>();
|
||||
program.parse_args({ "test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5" });
|
||||
auto vector = program.get<std::vector<double>>("--vector");
|
||||
REQUIRE(vector.size() == 5);
|
||||
@ -178,8 +178,7 @@ TEST_CASE("Parse a vector of double arguments" * test_suite("parse_args")) {
|
||||
TEST_CASE("Parse a vector of string arguments" * test_suite("parse_args")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("--vector")
|
||||
.nargs(5)
|
||||
.action([](const std::string& value) { return value; });
|
||||
.nargs(5);
|
||||
program.parse_args({ "test", "--vector", "abc", "def", "ghi", "jkl", "mno" });
|
||||
auto vector = program.get<std::vector<std::string>>("--vector");
|
||||
REQUIRE(vector.size() == 5);
|
||||
|
@ -32,7 +32,7 @@ TEST_CASE("Parse positional arguments with optional arguments" *
|
||||
program.add_argument("input");
|
||||
program.add_argument("output").nargs(2);
|
||||
program.add_argument("--num_iterations")
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
program.parse_args({ "test", "rocket.mesh", "--num_iterations", "15", "thrust_profile.csv", "output.mesh" });
|
||||
REQUIRE(program.get<int>("--num_iterations") == 15);
|
||||
REQUIRE(program.get("input") == "rocket.mesh");
|
||||
@ -48,7 +48,7 @@ TEST_CASE("Parse positional arguments with optional arguments in the middle" *
|
||||
program.add_argument("input");
|
||||
program.add_argument("output").nargs(2);
|
||||
program.add_argument("--num_iterations")
|
||||
.action([](const std::string& value) { return std::stoi(value); });
|
||||
.scan<'i', int>();
|
||||
REQUIRE_THROWS(program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv", "--num_iterations", "15", "output.mesh" }));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user