# # # patch "option.cc" # from [50544b89a852d3b6c03a12c892797317d28f218e] # to [5f0054153bf1a32737a543bd8498acbf50390be3] # # patch "option.hh" # from [455df218328d318a9d31e93f84044545719bb6b3] # to [5d01ff49f79434cff28bc077861b76e705c298a2] # # patch "unit_tests.cc" # from [bc945be846ca5608c6bb05e8462262c69827b681] # to [6ece61d8eefd8dff76de7bcd02db5891c2c5f20b] # ============================================================ --- option.cc 50544b89a852d3b6c03a12c892797317d28f218e +++ option.cc 5f0054153bf1a32737a543bd8498acbf50390be3 @@ -79,6 +79,8 @@ concrete_option::concrete_option(std::st description = desc; splitname(names, longname, shortname); I(!description.empty() || !longname.empty() || !shortname.empty()); + // If an option has a name (ie, can be set), it must have a setter function + I(set || (longname.empty() && shortname.empty())); has_arg = arg; setter = set; resetter = reset; @@ -112,7 +114,7 @@ concrete_option_set::concrete_option_set } // essentially the opposite of std::bind1st -class discard_argument : public boost::function +class discard_argument { boost::function functor; public: @@ -127,7 +129,7 @@ concrete_option_set::operator()(string c concrete_option_set::operator()(string const & names, string const & desc, boost::function set, - boost::function reset()) + boost::function reset) { options.insert(concrete_option(names, desc, false, discard_argument(set), reset)); return *this; @@ -137,7 +139,7 @@ concrete_option_set::operator()(string c concrete_option_set::operator()(string const & names, string const & desc, boost::function set, - boost::function reset()) + boost::function reset) { options.insert(concrete_option(names, desc, true, set, reset)); return *this; @@ -463,6 +465,78 @@ std::string concrete_option_set::get_usa } // namespace option + +#ifdef BUILD_UNIT_TESTS +#include "unit_tests.hh" + +UNIT_TEST(option, concrete_options) +{ + bool b = false; + string s; + int i = -1; + vector v; + + option::concrete_option_set os; + os("--", "", option::setter(v), option::resetter(v)) + ("bool,b", "", option::setter(b), option::resetter(b, false)) + ("s", "", option::setter(s)) + ("int", "", option::setter(i)); + + { + char const * cmdline[] = {"progname", "pos", "-s", "str ing", "--int", "10", + "--int", "45", "--", "--bad", "foo", "-b"}; + os.from_command_line(12, cmdline); + } + BOOST_CHECK(!b); + BOOST_CHECK(i == 45); + BOOST_CHECK(s == "str ing"); + BOOST_CHECK(v.size() == 4);// pos --bad foo -b + os.reset(); + BOOST_CHECK(v.empty()); + + { + vector cmdline; + cmdline.push_back("--bool"); + cmdline.push_back("-s"); + cmdline.push_back("-s"); + cmdline.push_back("foo"); + os.from_command_line(cmdline); + } + BOOST_CHECK(b); + BOOST_CHECK(s == "-s"); + BOOST_CHECK(v.size() == 1); + BOOST_CHECK(v[0] == "foo"); + os.reset(); + BOOST_CHECK(!b); + + { + char const * cmdline[] = {"progname", "--bad_arg", "x"}; + BOOST_CHECK_THROW(os.from_command_line(3, cmdline), option::unknown_option); + } + + { + char const * cmdline[] = {"progname", "--bool=x"}; + BOOST_CHECK_THROW(os.from_command_line(2, cmdline), option::extra_arg); + } + + { + char const * cmdline[] = {"progname", "-bx"}; + BOOST_CHECK_THROW(os.from_command_line(2, cmdline), option::extra_arg); + } + + { + char const * cmdline[] = {"progname", "-s"}; + BOOST_CHECK_THROW(os.from_command_line(2, cmdline), option::missing_arg); + } + + { + char const * cmdline[] = {"progname", "--int=x"}; + BOOST_CHECK_THROW(os.from_command_line(2, cmdline), option::bad_arg); + } +} + +#endif // BUILD_UNIT_TESTS + // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- option.hh 455df218328d318a9d31e93f84044545719bb6b3 +++ option.hh 5d01ff49f79434cff28bc077861b76e705c298a2 @@ -86,12 +86,12 @@ namespace option { operator()(std::string const & names, std::string const & desc, boost::function set, - boost::function reset() = 0); + boost::function reset = 0); concrete_option_set & operator()(std::string const & names, std::string const & desc, boost::function set, - boost::function reset() = 0); + boost::function reset = 0); concrete_option_set operator | (concrete_option_set const & other) const; void reset() const; @@ -102,6 +102,74 @@ namespace option { concrete_option_set operator | (concrete_option const & a, concrete_option const & b); + // used by the setter() functions below + template + struct setter_class + { + T & item; + setter_class(T & i) + : item(i) + {} + void operator()(std::string s) + { + item = boost::lexical_cast(s); + } + }; + template<> + struct setter_class + { + bool & item; + setter_class(bool & i) + : item(i) + {} + void operator()() + { + item = true; + } + }; + template + struct setter_class > + { + std::vector & items; + setter_class(std::vector & i) + : items(i) + {} + void operator()(std::string s) + { + items.push_back(boost::lexical_cast(s)); + } + }; + template + struct resetter_class + { + T & item; + T value; + resetter_class(T & i, T const & v) + : item(i), value(v) + {} + void operator()() + { + item = value; + } + }; + + // convenience functions to generate a setter for a var + template inline + boost::function setter(T & item) + { + return setter_class(item); + } + inline boost::function setter(bool & item) + { + return setter_class(item); + } + // convenience function to generate a resetter for a var + template inline + boost::function resetter(T & item, T const & value = T()) + { + return resetter_class(item, value); + } + // because std::bind1st can't handle producing a nullary functor template struct binder_only ============================================================ --- unit_tests.cc bc945be846ca5608c6bb05e8462262c69827b681 +++ unit_tests.cc 6ece61d8eefd8dff76de7bcd02db5891c2c5f20b @@ -147,55 +147,6 @@ namespace { typedef basic_teebuf teebuf; } -template -struct setter_class -{ - T & item; - setter_class(T & i) - : item(i) - {} - void operator()(string s) - { - item = boost::lexical_cast(s); - } -}; - -template<> -struct setter_class -{ - bool & item; - setter_class(bool & i) - : item(i) - {} - void operator()() - { - item = true; - } -}; -template -struct setter_class > -{ - vector & items; - setter_class(vector & i) - : items(i) - {} - void operator()(string s) - { - items.push_back(boost::lexical_cast(s)); - } -}; - -template -boost::function setter(T & item) -{ - return setter_class(item); -} - -boost::function setter(bool & item) -{ - return setter_class(item); -} - test_suite * init_unit_test_suite(int argc, char * argv[]) { bool help(false); @@ -204,16 +155,17 @@ test_suite * init_unit_test_suite(int ar bool debug(false); string log; vector tests; + try { option::concrete_option_set os; - os("help,h", "display help message", setter(help)) - ("list-groups,l", "list all test groups", setter(list_groups)) - ("list-tests,L", "list all test cases", setter(list_tests)) - ("debug", "write verbose debug log to stderr", setter(debug)) + os("help,h", "display help message", option::setter(help)) + ("list-groups,l", "list all test groups", option::setter(list_groups)) + ("list-tests,L", "list all test cases", option::setter(list_tests)) + ("debug", "write verbose debug log to stderr", option::setter(debug)) ("log", "write verbose debug log to this file" - " (default is unit_tests.log)", setter(log)) - ("--", "", setter(tests)); + " (default is unit_tests.log)", option::setter(log)) + ("--", "", option::setter(tests)); os.from_command_line(argc, argv);