Browse Source

* implemented printing of the help

master
bergmann 5 years ago
parent
commit
5bd05d76ef
19 changed files with 489 additions and 63 deletions
  1. +15
    -2
      include/cppargs/group/group.h
  2. +18
    -0
      include/cppargs/group/group.inl
  3. +37
    -1
      include/cppargs/group/member_group.inl
  4. +0
    -4
      include/cppargs/group/simple_group.h
  5. +36
    -0
      include/cppargs/group/simple_group.inl
  6. +4
    -33
      include/cppargs/misc/misc.h
  7. +57
    -0
      include/cppargs/misc/misc.inl
  8. +38
    -0
      include/cppargs/misc/printing.h
  9. +75
    -0
      include/cppargs/misc/printing.inl
  10. +16
    -5
      include/cppargs/options/option.h
  11. +47
    -0
      include/cppargs/options/option.inl
  12. +11
    -0
      include/cppargs/parser/member_parser.h
  13. +20
    -1
      include/cppargs/parser/member_parser.inl
  14. +1
    -1
      include/cppargs/parser/parser.h
  15. +4
    -0
      include/cppargs/parser/parser.inl
  16. +3
    -1
      include/cppargs/parser/simple_parser.inl
  17. +8
    -8
      test/cppargs/member_parser.cpp
  18. +93
    -0
      test/cppargs/misc.cpp
  19. +6
    -7
      test/cppargs/simple_parser.cpp

+ 15
- 2
include/cppargs/group/group.h View File

@@ -12,8 +12,11 @@ namespace cppargs
*/
struct group_meta
{
const std::string name { "" }; //!< Name of the group.
const std::string description { "" }; //!< Description of the group.
std::string name { "" }; //!< Name of the group.
std::string description { "" }; //!< Description of the group.

inline group_meta& set_name (const std::string& value);
inline group_meta& set_description(const std::string& value);
};

/**
@@ -63,6 +66,16 @@ namespace cppargs
* @brief Destructor.
*/
virtual ~group() = default;

/**
* @brief Get all options assigned to this group.
*/
inline const option_vector_type& options() const;

/**
* @brief Get all subgroups assigned to this group.
*/
inline const group_vector_type& groups() const;
};

}

+ 18
- 0
include/cppargs/group/group.inl View File

@@ -46,6 +46,18 @@ namespace cppargs
{ groups.emplace_back(std::forward<X>(x)); }
};

group_meta& group_meta::set_name(const std::string& value)
{
name = value;
return *this;
}

group_meta& group_meta::set_description(const std::string& value)
{
description = value;
return *this;
}

template<typename... T_args>
group::group(
const group_meta& p_meta,
@@ -55,4 +67,10 @@ namespace cppargs
(void) (int[]) { 0, (group_init<T_args> { _options, _groups } (std::forward<T_args>(p_args)), 0)... };
}

const group::option_vector_type& group::options() const
{ return _options; }

const group::group_vector_type& group::groups() const
{ return _groups; }

}

+ 37
- 1
include/cppargs/group/member_group.inl View File

@@ -5,6 +5,42 @@
namespace cppargs
{

template<typename T_instance, typename T_arg>
struct member_verify_and_forward
{
template<typename T, typename T_enable = void>
struct check
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ static_assert(sizeof(X) == -1, "invalid group or option type"); }
};

template<typename T>
struct check<
std::unique_ptr<T>,
utl::mp::enable_if<utl::mp::is_base_of<member_owned_group<T_instance>, T>>>
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ return std::forward<X>(x); }
};

template<typename T>
struct check<
std::unique_ptr<T>,
utl::mp::enable_if<utl::mp::is_base_of<member_option<T_instance>, T>>>
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ return std::forward<X>(x); }
};

template<typename X>
constexpr decltype(auto) operator()(X&& x) const
{ return check<T_arg> { } (std::forward<X>(x)); }
};

template<
typename T_owner_instance,
typename T_my_instance,
@@ -16,7 +52,7 @@ namespace cppargs
const group_meta& p_meta,
resolve_instance_pred_type&& p_pred,
T_args&&... p_args)
: group (p_meta, std::forward<T_args>(p_args)...)
: group (p_meta, member_verify_and_forward<T_my_instance, T_args> { } (std::forward<T_args>(p_args))...)
, _predicate(p_pred)
{
for (auto& o : _options)


+ 0
- 4
include/cppargs/group/simple_group.h View File

@@ -8,10 +8,6 @@ namespace cppargs
struct simple_group
: public group
{
private:
template<typename T_arg>
using simple_verify_and_forward = verify_and_forward<simple_group, simple_option, T_arg>;

public:
/**
* @brief Constructor.


+ 36
- 0
include/cppargs/group/simple_group.inl View File

@@ -5,6 +5,42 @@
namespace cppargs
{

template<typename T_arg>
struct simple_verify_and_forward
{
template<typename T, typename T_enable = void>
struct check
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ static_assert(sizeof(X) == -1, "invalid group or option type"); }
};

template<typename T>
struct check<
std::unique_ptr<T>,
utl::mp::enable_if<utl::mp::is_base_of<simple_group, T>>>
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ return std::forward<X>(x); }
};

template<typename T>
struct check<
std::unique_ptr<T>,
utl::mp::enable_if<utl::mp::is_base_of<simple_option, T>>>
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ return std::forward<X>(x); }
};

template<typename X>
constexpr decltype(auto) operator()(X&& x) const
{ return check<T_arg> { } (std::forward<X>(x)); }
};

template<typename... T_args>
simple_group::simple_group(
const group_meta& p_meta,


+ 4
- 33
include/cppargs/misc/misc.h View File

@@ -1,44 +1,15 @@
#pragma once

#include <string>
#include <cpputils/mp.h>

namespace cppargs
{

template<typename T_group, typename T_option, typename T_arg>
struct verify_and_forward
template<typename T_value, typename T_enable = void>
struct argument_props
{
template<typename T, typename T_enable = void>
struct check
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ static_assert(sizeof(X) == -1, "invalid group or option type"); }
};

template<typename T>
struct check<
T,
utl::mp::enable_if<utl::mp::is_base_of<T_group, T>>>
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ return std::forward<X>(x); }
};

template<typename T>
struct check<
std::unique_ptr<T>,
utl::mp::enable_if<utl::mp::is_base_of<T_option, T>>>
{
template<typename X>
constexpr X&& operator()(X&& x) const
{ return std::forward<X>(x); }
};

template<typename X>
constexpr decltype(auto) operator()(X&& x) const
{ return check<T_arg> { } (std::forward<X>(x)); }
static std::string type(bool optional = false) = delete;
};

}

+ 57
- 0
include/cppargs/misc/misc.inl View File

@@ -0,0 +1,57 @@
#pragma once

#include <list>
#include <vector>

#include <cpputils/misc/type_helper.h>
#include <cppargs/misc/misc.h>

namespace cppargs
{

inline std::string enwrap_type(const std::string& type, bool optional)
{
auto opn = optional ? "(" : "<";
auto cls = optional ? ")" : ">";
return std::string(opn) + type + cls;
}

template<>
struct argument_props<std::string, void>
{
static std::string type(bool optional = false)
{ return enwrap_type("string", false); }
};

template<typename T_value>
struct argument_props<T_value, utl::mp::enable_if_c<!std::is_class<T_value>::value>>
{
static std::string type(bool optional = false)
{ return enwrap_type(utl::type_helper<T_value>::name(), false); }
};

template<typename T_value>
struct argument_props<std::list<T_value>, void>
{
static std::string type(bool optional = false)
{
return
argument_props<T_value>::type(false) + ' ' +
argument_props<T_value>::type(true) + ' ' +
enwrap_type("...", true);
}
};

template<typename T_value>
struct argument_props<std::vector<T_value>, void>
{
static std::string type(bool optional = false)
{
return
argument_props<T_value>::type(false) + ' ' +
argument_props<T_value>::type(true) + ' ' +
enwrap_type("...", true);
}
};

}

+ 38
- 0
include/cppargs/misc/printing.h View File

@@ -0,0 +1,38 @@
#pragma once

#include <cppargs/group/group.h>
#include <cppargs/options/option.h>

namespace cppargs
{

struct printing
{
public:
/**
* @brief Print the passed group to the passed stream.
*
* @param[in] os Stream to print group to.
* @param[in] g Group to print to stream.
*/
inline void operator()(std::ostream& os, const group& g) const;

private:
/**
* @brief Print the passed group to the passed stream.
*
* @param[in] os Stream to print group to.
* @param[in] g Group to print to stream.
*/
inline void print_group(std::ostream& os, const group& g) const;

/**
* @brief Print the passed option to the passed stream.
*
* @param[in] os Stream to print group to.
* @param[in] o Option to print to stream.
*/
inline void print_option(std::ostream& os, const option& o) const;
};

}

+ 75
- 0
include/cppargs/misc/printing.inl View File

@@ -0,0 +1,75 @@
#pragma once

#include <cpputils/misc/indent.h>
#include <cppargs/misc/printing.h>

namespace cppargs
{

void printing::operator()(std::ostream& os, const group& g) const
{ print_group(os, g); }

void printing::print_group(std::ostream& os, const group& g) const
{
using namespace ::utl;

/* meta */
if (!g.meta.name.empty())
{
os << indent << "-= " << g.meta.name << " =-"
<< std::endl;
}
if (!g.meta.description.empty())
{
os << indent << g.meta.description
<< std::endl;
}

os << incindent;

/* options */
bool has_option = false;
for (auto& o : g.options())
{
if (!has_option)
has_option = true;
else
os << std::endl;
print_option(os, *o);
}
if (has_option)
os << std::endl;

os << decindent;

/* groups */
for (auto& i : g.groups())
{
print_group(os, *i);
}
}

void printing::print_option(std::ostream& os, const option& o) const
{
using namespace ::utl;
auto& m = o.meta;
os << indent;
if (m.short_name != '\0')
os << '-' << m.short_name;
if (m.short_name != '\0' && !m.long_name.empty())
os << '|';
if (!m.long_name.empty())
os << "--" << m.long_name;
if (!m.arguments.empty())
os << " " << m.arguments;
os << incindent;
if (!m.description.empty())
os << indent << m.description;
if (!m.default_value.empty())
os << indent << "Default value: " << m.default_value;
if (m.mandatory)
os << indent << "This option is mandatory.";
os << decindent;
}

}

+ 16
- 5
include/cppargs/options/option.h View File

@@ -11,11 +11,22 @@ namespace cppargs
*/
struct option_meta
{
const std::string long_name { "" }; //!< long name of the option (without the prepending --)
const char short_name { '\0' }; //!< short option of the option (without the prependding -)
const std::string description { "" }; //!< description for this option
const std::string default_value { "" }; //!< default value for this option
const bool optional { true }; //!< TRUE if this option is optional, FALSE otherwise
char short_name { '\0' }; //!< short option of the option (without the prependding -)
std::string long_name { "" }; //!< long name of the option (without the prepending --)
std::string description { "" }; //!< description for this option
std::string arguments { "" }; //!< arguments to pass to this option
std::string default_value { "" }; //!< default value for this option
bool mandatory { false }; //!< TRUE if this option is optional, FALSE otherwise

inline option_meta& set_short_name (char value);
inline option_meta& set_long_name (const std::string& value);
inline option_meta& set_description (const std::string& value);
inline option_meta& set_arguments (const std::string& value);
inline option_meta& set_default_value (const std::string& value);
inline option_meta& set_mandatory (bool value = true);

template<typename T_value>
static option_meta prepare_arguments(const option_meta& meta);
};

/**


+ 47
- 0
include/cppargs/options/option.inl View File

@@ -1,10 +1,57 @@
#pragma once

#include <cppargs/misc/misc.inl>

#include "option.h"

namespace cppargs
{

option_meta& option_meta::set_short_name(char value)
{
short_name = value;
return *this;
}

option_meta& option_meta::set_long_name(const std::string& value)
{
long_name = value;
return *this;
}

option_meta& option_meta::set_description(const std::string& value)
{
description = value;
return *this;
}

option_meta& option_meta::set_arguments(const std::string& value)
{
arguments = value;
return *this;
}

option_meta& option_meta::set_default_value(const std::string& value)
{
default_value = value;
return *this;
}

option_meta& option_meta::set_mandatory(bool value)
{
mandatory = value;
return *this;
}

template<typename T_value>
option_meta option_meta::prepare_arguments(const option_meta& meta)
{
option_meta m = meta;
if (m.arguments.empty())
m.arguments = argument_props<T_value>::type();
return m;
}

option::option(const option_meta& p_meta)
: meta(p_meta)
{ }


+ 11
- 0
include/cppargs/parser/member_parser.h View File

@@ -24,6 +24,17 @@ namespace cppargs
template<typename T_instance, typename T_object, typename T_value>
static constexpr decltype(auto) make_member_option(const option_meta& meta, T_value T_object::*member);

/**
* @brief Create new group.
*
* @param[in] meta Meta data of the new option.
* @param[in] args Subgroups and options.
*
* @return Created group.
*/
template<typename T_instance, typename... T_args>
static constexpr decltype(auto) make_group(const group_meta& meta, T_args&&... args);

/**
* @brief Create new group.
*


+ 20
- 1
include/cppargs/parser/member_parser.inl View File

@@ -1,8 +1,11 @@
#pragma once

#include <cpputils/misc/type_helper.h>

#include <cppargs/parser/parser.h>
#include <cppargs/options/member.h>
#include <cppargs/misc/option_parser.h>

#include <cppargs/group/member_group.inl>

namespace cppargs
@@ -24,7 +27,23 @@ namespace cppargs

using predicate_type = decltype(predicate);
using member_predicate_option_type = member_predicate_option<instance_type, value_type, predicate_type>;
return std::make_unique<member_predicate_option_type>(meta, std::move(predicate));
return std::make_unique<member_predicate_option_type>(
option_meta::prepare_arguments<T_value>(meta),
std::move(predicate));
}

template<typename T_instance, typename... T_args>
constexpr decltype(auto) member_parser_base::make_group(const group_meta& meta, T_args&&... args)
{
using owner_instance_type = T_instance;
using my_instance_type = T_instance;

auto predicate = [](owner_instance_type* instance)
{ return instance; };

using predicate_type = decltype(predicate);
using group_type = member_group<owner_instance_type, my_instance_type, predicate_type>;
return std::make_unique<group_type>(meta, std::move(predicate), std::forward<T_args>(args)...);
}

template<typename T_instance, typename T_object, typename T_value, typename... T_args>


+ 1
- 1
include/cppargs/parser/parser.h View File

@@ -64,7 +64,7 @@ namespace cppargs
*
* @param[in] os Stream to write help to.
*/
void print_help(std::ostream& os) const;
inline void print_help(std::ostream& os) const;
};

}

+ 4
- 0
include/cppargs/parser/parser.inl View File

@@ -2,6 +2,7 @@

#include <cppargs/parser/parser.h>
#include <cppargs/group/group.inl>
#include <cppargs/misc/printing.inl>

namespace cppargs
{
@@ -92,4 +93,7 @@ namespace cppargs
}
}

void parser::print_help(std::ostream& os) const
{ printing { } (os, _group); }

}

+ 3
- 1
include/cppargs/parser/simple_parser.inl View File

@@ -45,7 +45,9 @@ namespace cppargs

using predicate_type = decltype(predicate);
using simple_predicate_option_type = simple_predicate_option<predicate_type>;
return std::make_unique<simple_predicate_option_type>(meta, std::move(predicate));
return std::make_unique<simple_predicate_option_type>(
option_meta::prepare_arguments<T_value>(meta),
std::move(predicate));
}

}

+ 8
- 8
test/cppargs/member_parser.cpp View File

@@ -18,9 +18,9 @@ TEST(member_parser, simple_object)
simple s;
parser p(
nullptr,
parser::make_member_option<simple>({ "int", 'i' }, &simple::i),
parser::make_member_option<simple>({ "string", 's' }, &simple::s),
parser::make_member_option<simple>({ "double", 'd' }, &simple::d)
parser::make_member_option<simple>({ 'i', "int" }, &simple::i),
parser::make_member_option<simple>({ 's', "string" }, &simple::s),
parser::make_member_option<simple>({ 'd', "double" }, &simple::d)
);

std::vector<const char*> args({
@@ -55,12 +55,12 @@ TEST(member_parser, grouped_object)
grouped g;
parser p(
nullptr,
parser::make_member_option<grouped>({ "int", 'i' }, &grouped::i),
parser::make_member_option<grouped>({ "string", 's' }, &grouped::s),
parser::make_member_option<grouped>({ "double", 'd' }, &grouped::d),
parser::make_member_option<grouped>({ 'i', "int" }, &grouped::i),
parser::make_member_option<grouped>({ 's', "string" }, &grouped::s),
parser::make_member_option<grouped>({ 'd', "double" }, &grouped::d),
parser::make_member_group<grouped> ({ }, &grouped::g1,
parser::make_member_option<grouped::group1>({ "list", 'l' }, &grouped::group1::list),
parser::make_member_option<grouped::group1>({ "vector", 'v' }, &grouped::group1::vec))
parser::make_member_option<grouped::group1>({ 'l', "list" }, &grouped::group1::list),
parser::make_member_option<grouped::group1>({ 'v', "vector" }, &grouped::group1::vec))
);

std::vector<const char*> args({


+ 93
- 0
test/cppargs/misc.cpp View File

@@ -0,0 +1,93 @@
#include <vector>
#include <gtest/gtest.h>

#include <cppargs.h>

struct config
{
std::string config;

struct database
{
std::string host;
uint16_t port;
std::string password;
}
database;

struct logging
{
std::string file;
std::string level;
std::string name;
}
logging;
};

using parser = ::cppargs::member_parser<config>;

TEST(misc, print_help)
{
parser p(
nullptr,

parser::make_member_option<config>(
::cppargs::option_meta()
.set_short_name ('c')
.set_long_name ("config")
.set_arguments (::cppargs::enwrap_type("filename", false))
.set_description("Specify a configuration file to load config values from.")
.set_mandatory (true),
&config::config),

// parser::make_group<std::string>({ }),

/* database */
parser::make_member_group<config>(
::cppargs::group_meta()
.set_name("Database")
.set_description("The following parameters are database related."),
&config::database,
parser::make_member_option<struct config::database>(
::cppargs::option_meta()
.set_long_name ("database:host")
.set_description("Database host to connect to."),
&config::database::host),
parser::make_member_option<struct config::database>(
::cppargs::option_meta()
.set_long_name ("database:port")
.set_description("Database port to connect to."),
&config::database::port),
parser::make_member_option<struct config::database>(
::cppargs::option_meta()
.set_long_name ("database:password")
.set_description("Password to use for authenticatiom"),
&config::database::password)),

/* logging */
parser::make_member_group<config>(
::cppargs::group_meta()
.set_name("Logging"),
&config::logging,
parser::make_member_option<struct config::logging>(
::cppargs::option_meta()
.set_long_name ("logging:file")
.set_arguments (::cppargs::enwrap_type("filename", false))
.set_description("File to write log output to."),
&config::logging::file),
parser::make_member_option<struct config::logging>(
::cppargs::option_meta()
.set_long_name ("logging:level")
.set_description("Log Level."),
&config::logging::level),
parser::make_member_option<struct config::logging>(
::cppargs::option_meta()
.set_long_name ("logging:name")
.set_description("Default name of the logger."),
&config::logging::name)));

std::ostringstream ss;
p.print_help(ss);

std::cout << ss.str();
}

+ 6
- 7
test/cppargs/simple_parser.cpp View File

@@ -7,11 +7,10 @@ using parser = ::cppargs::simple_parser;

TEST(simple_parser, short_name_seperate_arg)
{

std::string s;
parser p(
nullptr,
parser::make_reference_option({ "string", 's' }, s)
parser::make_reference_option({ 's', "string" }, s)
);

std::vector<const char*> args({
@@ -27,7 +26,7 @@ TEST(simple_parser, long_name_seperate_arg)
int i;
parser p(
nullptr,
parser::make_reference_option({ "int", 'i' }, i)
parser::make_reference_option({ 'i', "int" }, i)
);

std::vector<const char*> args({
@@ -43,7 +42,7 @@ TEST(simple_parser, short_name_same_arg)
double d;
parser p(
nullptr,
parser::make_reference_option({ "double", 'd' }, d)
parser::make_reference_option({ 'd', "double" }, d)
);

std::vector<const char*> args({
@@ -59,7 +58,7 @@ TEST(simple_parser, long_name_same_arg)
std::string s;
parser p(
nullptr,
parser::make_reference_option({ "string", 's' }, s)
parser::make_reference_option({ 's', "string" }, s)
);

std::vector<const char*> args({
@@ -75,7 +74,7 @@ TEST(simple_parser, vector_extra_arg)
std::vector<int> vec;
parser p(
parser::make_predicate_option({ }, [](auto){ }),
parser::make_reference_option({ "vec", 'v' }, vec)
parser::make_reference_option({ 'v', "vec" }, vec)
);

std::vector<const char*> args({
@@ -91,7 +90,7 @@ TEST(simple_parser, vector_same_arg)
std::vector<int> vec;
parser p(
parser::make_predicate_option({ }, [](auto){ }),
parser::make_reference_option({ "vec", 'v' }, vec)
parser::make_reference_option({ 'v', "vec" }, vec)
);

std::vector<const char*> args({


Loading…
Cancel
Save