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 ()
|
||||
{ ; }
|
||||
|
||||
@ -52,24 +58,32 @@ base::start (void)
|
||||
void
|
||||
base::finish (void)
|
||||
{
|
||||
if (m_required && !m_seen)
|
||||
if (!fulfilled ())
|
||||
throw invalid_required ();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
base::required (std::function<bool(void)> _required)
|
||||
{
|
||||
m_required = std::move (_required);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool
|
||||
base::required (void) const
|
||||
{
|
||||
return m_required;
|
||||
return m_required ();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool
|
||||
void
|
||||
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
|
||||
null::execute (void)
|
||||
|
45
cmdopt.hpp
45
cmdopt.hpp
@ -72,14 +72,17 @@ namespace cruft::cmdopt {
|
||||
const int m_index;
|
||||
};
|
||||
|
||||
namespace option { class base; }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace option {
|
||||
class base {
|
||||
public:
|
||||
base ();
|
||||
|
||||
// we deal almost exclusively with vtables, so disable copying
|
||||
// just in case we do something stupid.
|
||||
base () = default;
|
||||
base (const base&) = delete;
|
||||
base& operator= (const base&) = delete;
|
||||
|
||||
@ -92,14 +95,32 @@ namespace cruft::cmdopt {
|
||||
|
||||
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 (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;
|
||||
/// Sets the seen flag of the option to the value provided.
|
||||
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:
|
||||
bool m_required = false;
|
||||
std::function<bool(void)> m_required;
|
||||
bool m_seen = false;
|
||||
};
|
||||
|
||||
@ -184,6 +205,24 @@ namespace cruft::cmdopt {
|
||||
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
|
||||
{
|
||||
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
|
||||
void
|
||||
@ -260,6 +312,7 @@ main (int, char **) {
|
||||
test_numeric<uint64_t> (tap);
|
||||
test_bytes (tap);
|
||||
test_required (tap);
|
||||
test_fulfilled (tap);
|
||||
test_positional (tap);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user