Skip to content

Commit

Permalink
first working version with a function
Browse files Browse the repository at this point in the history
  • Loading branch information
smehringer committed Jul 26, 2019
1 parent 94e07f7 commit 8a3f4c8
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 10 deletions.
8 changes: 4 additions & 4 deletions include/seqan3/argument_parser/argument_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ class argument_parser
*/
template <typename option_type, Validator validator_type = detail::default_validator<option_type>>
//!\cond
requires (IStream<std::istringstream, option_type> ||
IStream<std::istringstream, typename option_type::value_type>) &&
requires (ArgumentParserCompatibleOption<option_type> ||
ArgumentParserCompatibleOption<typename option_type::value_type>) &&
std::Invocable<validator_type, option_type>
//!\endcond
void add_option(option_type & value,
Expand Down Expand Up @@ -279,8 +279,8 @@ class argument_parser
*/
template <typename option_type, Validator validator_type = detail::default_validator<option_type>>
//!\cond
requires (IStream<std::istringstream, option_type> ||
IStream<std::istringstream, typename option_type::value_type>) &&
requires (ArgumentParserCompatibleOption<option_type> ||
ArgumentParserCompatibleOption<typename option_type::value_type>) &&
std::Invocable<validator_type, option_type>
//!\endcond
void add_positional_option(option_type & value,
Expand Down
33 changes: 33 additions & 0 deletions include/seqan3/argument_parser/auxiliary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,44 @@
#include <vector>

#include <seqan3/core/detail/debug_stream_type.hpp>
#include <seqan3/core/type_traits/basic.hpp>
#include <seqan3/io/stream/concept.hpp>

namespace seqan3
{

template <typename enum_type>
SEQAN3_CONCEPT has_get_argument_conversion_table = requires
{
{ get_argument_conversion_table(enum_type{}) } -> std::unordered_map<std::string, enum_type>;
};

template <typename option_type>
SEQAN3_CONCEPT ArgumentParserCompatibleOption = IStream<std::istringstream, option_type> ||
has_get_argument_conversion_table<option_type>;

/*!\brief foo
* \tparam enum_type Type of the enum to be printed.
* \param s The seqan3::debug_stream.
* \param em The enum.
* \relates seqan3::debug_stream_type
*
* \details
*
* This prints out an alignment matrix which can be a score matrix or a trace matrix.
*/
template <typename char_t, typename enum_type>
//!\cond
requires has_get_argument_conversion_table<remove_cvref_t<enum_type>>
//!\endcond
inline debug_stream_type<char_t> & operator<<(debug_stream_type<char_t> & s, enum_type && em)
{
for (auto & [key, value] : get_argument_conversion_table(em))
if (em == value)
return s << key;
return s << "<UNKOWN_ENUM>";
}

/*!\brief Used to further specify argument_parser options/flags.
* \ingroup argument_parser
*
Expand Down
30 changes: 24 additions & 6 deletions include/seqan3/argument_parser/detail/format_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <seqan3/argument_parser/exceptions.hpp>
#include <seqan3/argument_parser/validators.hpp>
#include <seqan3/core/detail/reflection.hpp>
#include <seqan3/range/view/view_all.hpp>
#include <seqan3/range/view/get.hpp>
#include <seqan3/std/filesystem>

namespace seqan3::detail
Expand Down Expand Up @@ -240,9 +242,17 @@ class format_help_base : public format_base
std::string const & long_id,
std::string const & desc,
option_spec const & spec,
validator_type && validator)
validator_type && val)
{
parser_set_up_calls.push_back([this, &value, short_id, long_id, desc, spec, validator] ()
std::string msg = val.get_help_page_message();

if constexpr (has_get_argument_conversion_table<option_type>)
{
auto table = get_argument_conversion_table(value);
msg = (val | value_list_validator<option_type>{(view::all(table) | view::get<1>)}).get_help_page_message();
}

parser_set_up_calls.push_back([this, &value, short_id, long_id, desc, spec, msg] ()
{
if (!(spec & option_spec::HIDDEN) && (!(spec & option_spec::ADVANCED) || show_advanced_options))
derived_t().print_list_item(prep_id_for_help(short_id, long_id) +
Expand All @@ -251,7 +261,7 @@ class format_help_base : public format_base
((spec & option_spec::REQUIRED)
? std::string{" "}
: detail::to_string(" Default: ", value, ". ")) +
validator.get_help_page_message());
msg);
});
}

Expand Down Expand Up @@ -287,9 +297,17 @@ class format_help_base : public format_base
template <typename option_type, typename validator_type>
void add_positional_option(option_type & value,
std::string const & desc,
validator_type & validator)
validator_type & val)
{
positional_option_calls.push_back([this, &value, desc, validator] ()
std::string msg = val.get_help_page_message();

if constexpr (has_get_argument_conversion_table<option_type>)
{
auto table = get_argument_conversion_table(value);
msg = (val | value_list_validator<option_type>{(view::all(table) | view::get<1>)}).get_help_page_message();
}

positional_option_calls.push_back([this, &value, desc, msg] ()
{
++positional_option_count;
derived_t().print_list_item(detail::to_string("\\fBARGUMENT-", positional_option_count, "\\fP ",
Expand All @@ -299,7 +317,7 @@ class format_help_base : public format_base
((SequenceContainer<option_type> && !std::Same<option_type, std::string>)
? detail::to_string(" Default: ", value, ". ")
: std::string{" "}) +
validator.get_help_page_message());
msg);
});
}

Expand Down
18 changes: 18 additions & 0 deletions include/seqan3/argument_parser/detail/format_parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,24 @@ class format_parse : public format_base
get_type_name_as_string(value) + ".");
}

template <typename option_t>
//!\cond
requires has_get_argument_conversion_table<option_t>
//!\endcond
void retrieve_value(option_t & value, std::string const & in)
{
std::string tmp;
std::istringstream is{in};
is >> tmp;
auto it = get_argument_conversion_table(value).find(tmp);

if (it == get_argument_conversion_table(value).end())
throw type_conversion_failed("Argument " + in + " could not be casted to enum type " +
get_display_name_v<option_t>.str() + ".");
else
value = it->second;
}

//!\cond
void retrieve_value(std::string & value, std::string const & in)
{
Expand Down
1 change: 1 addition & 0 deletions include/seqan3/argument_parser/validators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <fstream>
#include <sstream>

#include <seqan3/argument_parser/auxiliary.hpp>
#include <seqan3/argument_parser/exceptions.hpp>
#include <seqan3/core/concept/core_language.hpp>
#include <seqan3/core/detail/to_string.hpp>
Expand Down
16 changes: 16 additions & 0 deletions test/unit/argument_parser/detail/format_help_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,23 @@ TEST(help_page_printing, do_not_print_hidden_options)
EXPECT_TRUE(ranges::equal((std_cout | std::view::filter(!is_space)), expected | std::view::filter(!is_space)));
}

enum class Foo
{
one,
two,
three
};

auto get_argument_conversion_table(Foo)
{
return std::unordered_map<std::string, Foo>{{{"one", Foo::one}, {"two", Foo::two}, {"three", Foo::three}}};
}

TEST(help_page_printing, full_information)
{
int8_t required_option{};
int8_t non_list_optional{1};
Foo enum_option_value{};

// Add synopsis, description, short description, positional option, option, flag, and example.
argument_parser parser6{"test_parser", 2, argv1};
Expand All @@ -208,6 +221,7 @@ TEST(help_page_printing, full_information)
parser6.info.description.push_back("description2");
parser6.info.short_description = "so short";
parser6.add_option(option_value, 'i', "int", "this is a int option.");
parser6.add_option(enum_option_value, 'e', "enum", "this is an enum option.");
parser6.add_option(required_option, 'r', "required-int", "this is another int option.", option_spec::REQUIRED);
parser6.add_section("Flags");
parser6.add_subsection("SubFlags");
Expand Down Expand Up @@ -236,6 +250,8 @@ TEST(help_page_printing, full_information)
basic_options_str +
"-i, --int (signed 32 bit integer)\n"
"this is a int option. Default: 5.\n"
"-e, --enum (Foo)\n"
"this is an enum option. Default: one. Value must be one of [three,two,one].\n"
"-r, --required-int (signed 8 bit integer)\n"
"this is another int option.\n"
"FLAGS\n"
Expand Down
39 changes: 39 additions & 0 deletions test/unit/argument_parser/format_parse_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,45 @@ TEST(parse_type_test, parse_error_double_option)
EXPECT_THROW(parser2.parse(), parser_invalid_argument);
}

namespace Bar
{

enum class Foo
{
one,
two,
three
};

auto get_argument_conversion_table(Foo)
{
return std::unordered_map<std::string, Foo>{{{"one", Foo::one}, {"two", Foo::two}, {"three", Foo::three}}};
}

} // namespace bar

TEST(parse_type_test, parse_success_enum_option)
{
Bar::Foo option_value{};

const char * argv[] = {"./argument_parser_test", "-e", "two"};
argument_parser parser{"test_parser", 3, argv, false};
parser.add_option(option_value, 'e', "enum-option", "this is an enum option.");

EXPECT_NO_THROW(parser.parse());
EXPECT_TRUE(option_value == Bar::Foo::two);
}

TEST(parse_type_test, parse_error_enum_option)
{
Bar::Foo option_value{};

const char * argv[] = {"./argument_parser_test", "-e", "four"};
argument_parser parser{"test_parser", 3, argv, false};
parser.add_option(option_value, 'e', "enum-option", "this is an enum option.");

EXPECT_THROW(parser.parse(), parser_invalid_argument);
}

TEST(parse_test, too_many_arguments_error)
{
Expand Down

0 comments on commit 8a3f4c8

Please sign in to comment.