Commit 37667f523d1fe9b343ca0d6bde8bb780baed3126

Authored by Henry Schreiner
Committed by GitHub
1 parent adbd2aa7

Adding simple flag callback (#33)

* Addind simple flag callback

* Give flag function a new name, old name only on C++14

* Fixing reference to destroyed function

* Better GCC 4.7 support, travis prepared for C++17 (not used yet)

* Updating documentation
.ci/travis.sh
... ... @@ -3,8 +3,18 @@ set -evx
3 3  
4 4 mkdir build || true
5 5 cd build
6   -cmake .. -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
  6 +cmake .. -DCLI_CXX_STD=11 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
7 7 cmake --build . -- -j2
8 8 ctest --output-on-failure
  9 +if [ -n "$CLI_CXX_STD" ] && [ "$CLI_CXX_STD" -ge "14" ] ; then
  10 + cmake .. -DCLI_CXX_STD=14 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
  11 + cmake --build . -- -j2
  12 + ctest --output-on-failure
  13 +fi
  14 +if [ -n "$CLI_CXX_STD" ] && [ "$CLI_CXX_STD" -ge "17" ] ; then
  15 + cmake .. -DCLI_CXX_STD=17 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
  16 + cmake --build . -- -j2
  17 + ctest --output-on-failure
  18 +fi
9 19  
10 20 set +evx
... ...
.travis.yml
... ... @@ -20,6 +20,7 @@ matrix:
20 20 env:
21 21 - COMPILER=3.9
22 22 - CHECK_STYLE=yes
  23 + - CLI_CXX_STD=14
23 24 - compiler: clang
24 25 addons:
25 26 apt:
... ... @@ -41,6 +42,7 @@ matrix:
41 42 env:
42 43 - COMPILER=6
43 44 - COVERALLS=yes
  45 + - CLI_CXX_STD=14
44 46 - compiler: gcc
45 47 addons:
46 48 apt:
... ... @@ -48,7 +50,6 @@ matrix:
48 50 - g++-4.7
49 51 env:
50 52 - COMPILER=4.7
51   - - CXXFLAGS=-D_GLIBCXX_USE_NANOSLEEP
52 53 - os: osx
53 54 install:
54 55 - python -c 'import sys; print(sys.version_info[:])'
... ...
CHANGELOG.md
1 1 ## Version 1.2 (in progress)
2 2  
  3 +* Added functional form of flag [#33](https://github.com/CLIUtils/CLI11/pull/33), automatic on C++14
3 4 * Fixed Config file search if passed on command line [#30](https://github.com/CLIUtils/CLI11/issues/30)
4 5 * Added `CLI11_PARSE(app, argc, argv)` macro for simple parse commands (does not support returning arg)
5 6 * The name string can now contain spaces around commas [#29](https://github.com/CLIUtils/CLI11/pull/29)
... ...
CMakeLists.txt
... ... @@ -4,9 +4,11 @@ project(CLI11 CXX)
4 4  
5 5 SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
6 6  
  7 +set(CLI_CXX_STD "11" CACHE STRING "The CMake standard to require")
  8 +
7 9 if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
8 10 set(CUR_PROJ ON)
9   - set(CMAKE_CXX_STANDARD 11)
  11 + set(CMAKE_CXX_STANDARD ${CLI_CXX_STD})
10 12 set(CMAKE_CXX_EXTENSIONS OFF)
11 13 set(CMAKE_CXX_STANDARD_REQUIRED ON)
12 14  
... ...
README.md
... ... @@ -120,6 +120,10 @@ app.add_flag(option_name,
120 120 int_or_bool = nothing,
121 121 help_string="")
122 122  
  123 +app.add_flag_function(option_name,
  124 + function <void(size_t count)>,
  125 + help_string="")
  126 +
123 127 app.add_set(option_name,
124 128 variable_to_bind_to,
125 129 set_of_possible_options,
... ... @@ -133,6 +137,8 @@ App* subcom = app.add_subcommand(name, discription);
133 137  
134 138 An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`. The set options allow your users to pick from a set of predefined options.
135 139  
  140 +On a C++14 compiler, you can pass a callback function directly to `.add_flag`, while in C++11 mode you'll need to use `.add_flag_function` if you want a callback function. The function will be given the number of times the flag was passed. You can throw a `CLI::ParseError` to signal a failure.
  141 +
136 142 ### Example
137 143  
138 144 * `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--one`
... ...
include/CLI/App.hpp
... ... @@ -370,6 +370,33 @@ class App {
370 370 return opt;
371 371 }
372 372  
  373 + /// Add option for callback
  374 + Option *add_flag_function(std::string name,
  375 + std::function<void(size_t)> function, ///< A function to call, void(size_t)
  376 + std::string description = "") {
  377 +
  378 + CLI::callback_t fun = [function](CLI::results_t res) {
  379 + auto count = static_cast<size_t>(res.size());
  380 + function(count);
  381 + return true;
  382 + };
  383 +
  384 + Option *opt = add_option(name, fun, description, false);
  385 + if(opt->get_positional())
  386 + throw IncorrectConstruction("Flags cannot be positional");
  387 + opt->set_custom_option("", 0);
  388 + return opt;
  389 + }
  390 +
  391 +#if __cplusplus >= 201402L
  392 + /// Add option for callback (C++14 or better only)
  393 + Option *add_flag(std::string name,
  394 + std::function<void(size_t)> function, ///< A function to call, void(size_t)
  395 + std::string description = "") {
  396 + return add_flag_function(name, function, description);
  397 + }
  398 +#endif
  399 +
373 400 /// Add set of options (No default)
374 401 template <typename T>
375 402 Option *add_set(std::string name,
... ...
include/CLI/Timer.hpp
... ... @@ -3,6 +3,12 @@
3 3 // Distributed under the 3-Clause BSD License. See accompanying
4 4 // file LICENSE or https://github.com/CLIUtils/CLI11 for details.
5 5  
  6 +// On GCC < 4.8, the following define is often missing. Due to the
  7 +// fact that this library only uses sleep_for, this should be safe
  8 +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 && __GNUC_MINOR__ < 8
  9 +#define _GLIBCXX_USE_NANOSLEEP
  10 +#endif
  11 +
6 12 #include <chrono>
7 13 #include <functional>
8 14 #include <iostream>
... ...
tests/AppTest.cpp
... ... @@ -243,6 +243,56 @@ TEST_F(TApp, RequiredFlags) {
243 243 run();
244 244 }
245 245  
  246 +TEST_F(TApp, CallbackFlags) {
  247 +
  248 + int value = 0;
  249 +
  250 + auto func = [&value](size_t x) { value = x; };
  251 +
  252 + app.add_flag_function("-v", func);
  253 +
  254 + run();
  255 + EXPECT_EQ(value, 0);
  256 +
  257 + app.reset();
  258 + args = {"-v"};
  259 + run();
  260 + EXPECT_EQ(value, 1);
  261 +
  262 + app.reset();
  263 + args = {"-vv"};
  264 + run();
  265 + EXPECT_EQ(value, 2);
  266 +
  267 + EXPECT_THROW(app.add_flag_function("hi", func), CLI::IncorrectConstruction);
  268 +}
  269 +
  270 +#if __cplusplus >= 201402L
  271 +TEST_F(TApp, CallbackFlagsAuto) {
  272 +
  273 + int value = 0;
  274 +
  275 + auto func = [&value](size_t x) { value = x; };
  276 +
  277 + app.add_flag("-v", func);
  278 +
  279 + run();
  280 + EXPECT_EQ(value, 0);
  281 +
  282 + app.reset();
  283 + args = {"-v"};
  284 + run();
  285 + EXPECT_EQ(value, 1);
  286 +
  287 + app.reset();
  288 + args = {"-vv"};
  289 + run();
  290 + EXPECT_EQ(value, 2);
  291 +
  292 + EXPECT_THROW(app.add_flag("hi", func), CLI::IncorrectConstruction);
  293 +}
  294 +#endif
  295 +
246 296 TEST_F(TApp, Positionals) {
247 297  
248 298 std::string posit1;
... ...