cmdopt: add simple requires
constraint callbacks
This commit is contained in:
parent
ac168e86b5
commit
0a7adfb037
32
cmdopt.cpp
32
cmdopt.cpp
@ -20,6 +20,12 @@ using namespace cruft::cmdopt::option;
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
base::base ()
|
||||||
|
: m_required ([] () { return false; })
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
base::~base ()
|
base::~base ()
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
@ -52,24 +58,32 @@ base::start (void)
|
|||||||
void
|
void
|
||||||
base::finish (void)
|
base::finish (void)
|
||||||
{
|
{
|
||||||
if (m_required && !m_seen)
|
if (!fulfilled ())
|
||||||
throw invalid_required ();
|
throw invalid_required ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
base::required (std::function<bool(void)> _required)
|
||||||
|
{
|
||||||
|
m_required = std::move (_required);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool
|
bool
|
||||||
base::required (void) const
|
base::required (void) const
|
||||||
{
|
{
|
||||||
return m_required;
|
return m_required ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool
|
void
|
||||||
base::required (bool _required)
|
base::required (bool _required)
|
||||||
{
|
{
|
||||||
return m_required = _required;
|
m_required = [_required] (void) { return _required; };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,6 +103,16 @@ base::seen (bool _seen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool
|
||||||
|
base::fulfilled (void) const
|
||||||
|
{
|
||||||
|
if (!m_required ())
|
||||||
|
return true;
|
||||||
|
return seen ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
void
|
void
|
||||||
null::execute (void)
|
null::execute (void)
|
||||||
|
45
cmdopt.hpp
45
cmdopt.hpp
@ -72,14 +72,17 @@ namespace cruft::cmdopt {
|
|||||||
const int m_index;
|
const int m_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace option { class base; }
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
namespace option {
|
namespace option {
|
||||||
class base {
|
class base {
|
||||||
public:
|
public:
|
||||||
|
base ();
|
||||||
|
|
||||||
// we deal almost exclusively with vtables, so disable copying
|
// we deal almost exclusively with vtables, so disable copying
|
||||||
// just in case we do something stupid.
|
// just in case we do something stupid.
|
||||||
base () = default;
|
|
||||||
base (const base&) = delete;
|
base (const base&) = delete;
|
||||||
base& operator= (const base&) = delete;
|
base& operator= (const base&) = delete;
|
||||||
|
|
||||||
@ -92,14 +95,32 @@ namespace cruft::cmdopt {
|
|||||||
|
|
||||||
virtual const std::string& example (void) const = 0;
|
virtual const std::string& example (void) const = 0;
|
||||||
|
|
||||||
|
/// Sets a callback query to determine if the option is required.
|
||||||
|
///
|
||||||
|
/// The default is `return false;`
|
||||||
|
void required (std::function<bool(void)>);
|
||||||
|
/// Sets a constant value function for the required query.
|
||||||
|
/// The value provided will be unconditionally returned.
|
||||||
|
void required (bool);
|
||||||
|
/// Tests if the option is required by invoking the stored query.
|
||||||
bool required (void) const;
|
bool required (void) const;
|
||||||
bool required (bool);
|
|
||||||
|
|
||||||
|
/// Tests if the option has been seen.
|
||||||
|
///
|
||||||
|
/// Not to be confused with `fulfilled` which describes whether
|
||||||
|
/// the `seen` and `required` constraints are both satisfied.
|
||||||
bool seen (void) const;
|
bool seen (void) const;
|
||||||
|
/// Sets the seen flag of the option to the value provided.
|
||||||
bool seen (bool);
|
bool seen (bool);
|
||||||
|
|
||||||
|
/// Tests if all `required` and `seen` constraints have been
|
||||||
|
/// satisfied.
|
||||||
|
///
|
||||||
|
/// If there are no `required` constraints it return true.
|
||||||
|
bool fulfilled (void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_required = false;
|
std::function<bool(void)> m_required;
|
||||||
bool m_seen = false;
|
bool m_seen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -184,6 +205,24 @@ namespace cruft::cmdopt {
|
|||||||
seen (true);
|
seen (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns a callback that tests if this option has been set to
|
||||||
|
/// a specified value.
|
||||||
|
///
|
||||||
|
/// If the option has not been seen it is treated as
|
||||||
|
/// unconditionally not equal.
|
||||||
|
///
|
||||||
|
/// The returned function is handy to use in the `required`
|
||||||
|
/// clauses of dependent options.
|
||||||
|
template <typename TargetT>
|
||||||
|
std::function<bool(void)>
|
||||||
|
is (TargetT &&_target)&
|
||||||
|
{
|
||||||
|
return [&, target = std::forward<TargetT>(_target)] (void) {
|
||||||
|
return seen () && m_data == target;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& example (void) const override
|
const std::string& example (void) const override
|
||||||
{
|
{
|
||||||
return detail::value_example<T> ();
|
return detail::value_example<T> ();
|
||||||
|
@ -220,6 +220,58 @@ test_required (cruft::TAP::logger &tap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fulfilled (cruft::TAP::logger &tap)
|
||||||
|
{
|
||||||
|
// Test that a value option that has no requirements/seen constraints and no provided value is fullfilled.
|
||||||
|
{
|
||||||
|
cruft::cmdopt::parser p;
|
||||||
|
bool b_val;
|
||||||
|
auto &b_opt = p.add<cruft::cmdopt::option::value<bool>> ('b', "bool", "boolean value", b_val);
|
||||||
|
static constexpr char const* argv[] = { "./cpptest", };
|
||||||
|
tap.expect_nothrow ([&] () {
|
||||||
|
p.scan (std::size (argv), argv);
|
||||||
|
}, "fullfilled, empty, scan");
|
||||||
|
tap.expect (b_opt.fulfilled (), "fulfilled, empty, value");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an unseen dependent option means the option is unfulfilled.
|
||||||
|
{
|
||||||
|
cruft::cmdopt::parser p;
|
||||||
|
int a_val = 0, b_val = 0;
|
||||||
|
auto &a_opt = p.add<cruft::cmdopt::option::value<int>> ('a', "ay", "int value", a_val);
|
||||||
|
auto &b_opt = p.add<cruft::cmdopt::option::value<int>> ('b', "be", "int value", b_val);
|
||||||
|
|
||||||
|
b_opt.required(a_opt.is (1));
|
||||||
|
|
||||||
|
static constexpr char const* argv[] = { "./cpptest", "-a", "1"};
|
||||||
|
tap.expect_throw<cruft::cmdopt::invalid_required> ([&] () {
|
||||||
|
p.scan (std::size (argv), argv);
|
||||||
|
}, "fullfilled, unseen dependent, scan");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a seen dependent opion means the option is fulfilled.
|
||||||
|
{
|
||||||
|
cruft::cmdopt::parser p;
|
||||||
|
int a_val = 0, b_val = 0;
|
||||||
|
auto &a_opt = p.add<cruft::cmdopt::option::value<int>> ('a', "ay", "int value", a_val);
|
||||||
|
auto &b_opt = p.add<cruft::cmdopt::option::value<int>> ('b', "be", "int value", b_val);
|
||||||
|
|
||||||
|
b_opt.required(a_opt.is (1));
|
||||||
|
|
||||||
|
static constexpr char const* argv[] = { "./cpptest", "-a", "1", "-b", "10"};
|
||||||
|
tap.expect_nothrow ([&] () {
|
||||||
|
p.scan (std::size (argv), argv);
|
||||||
|
}, "fullfilled, unseen dependent, scan");
|
||||||
|
|
||||||
|
tap.expect_eq (a_val, 1, "fulfilled, dependent value");
|
||||||
|
tap.expect_eq (b_val, 10, "fulfilled, dependent value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
@ -260,6 +312,7 @@ main (int, char **) {
|
|||||||
test_numeric<uint64_t> (tap);
|
test_numeric<uint64_t> (tap);
|
||||||
test_bytes (tap);
|
test_bytes (tap);
|
||||||
test_required (tap);
|
test_required (tap);
|
||||||
|
test_fulfilled (tap);
|
||||||
test_positional (tap);
|
test_positional (tap);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user