Skip to content

Commit d612e36

Browse files
authored
Merge pull request #77 from Magisus/po-allow-unregistered
(maint) Allow unregistered options in boost::program_options interface
2 parents aa71b03 + 9e25ad4 commit d612e36

File tree

5 files changed

+36
-6
lines changed

5 files changed

+36
-6
lines changed

lib/inc/hocon/config_object.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ namespace hocon {
4545
*/
4646
virtual shared_value attempt_peek_with_partial_resolve(std::string const& key) const = 0;
4747

48+
/**
49+
* Construct a list of keys in the _value map.
50+
* Use a vector rather than set, because most of the time we just want to iterate over them.
51+
*/
52+
virtual std::vector<std::string> key_set() const = 0;
53+
4854
// map interface
4955
using iterator = std::unordered_map<std::string, shared_value>::const_iterator;
5056
virtual bool is_empty() const = 0;

lib/inc/hocon/program_options.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,21 @@ namespace hocon { namespace program_options {
2525

2626
for (const auto& entry : cfg->entry_set()) {
2727
po::option opt;
28-
29-
// TODO: enforce unregistered variable flag based on allow_unregistered setting
30-
3128
if (prefix.empty()) {
3229
opt.string_key = entry.first;
3330
} else {
3431
opt.string_key = prefix + "." + entry.first;
3532
}
3633

34+
// Skips options that are not registered in the description.
35+
// This is different behavior than the built in program_options
36+
// parsers, which pass the options along somehow. But for now
37+
// it stops an exception from being thrown if there is an unknown
38+
// item in the config file.
39+
if (allow_unregistered && !desc.find_nothrow(opt.string_key, false)) {
40+
continue;
41+
}
42+
3743
if (entry.second->value_type() == config_value::type::LIST) {
3844
// if this is a list, we want to check if any of the entries are
3945
// objects. If so, we need to further expand those sub-trees, with

lib/inc/internal/values/config_delayed_merge_object.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ namespace hocon {
1818

1919
resolve_status get_resolve_status() const override { return resolve_status::UNRESOLVED; }
2020

21+
std::vector<std::string> key_set() const override { throw not_resolved(); }
22+
2123
// map interface
2224
bool is_empty() const override { throw not_resolved(); }
2325
size_t size() const override { throw not_resolved(); }

lib/inc/internal/values/simple_config_object.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ namespace hocon {
7070
* Construct a list of keys in the _value map.
7171
* Use a vector rather than set, because most of the time we just want to iterate over them.
7272
*/
73-
std::vector<std::string> key_set() const;
73+
std::vector<std::string> key_set() const override;
7474

7575
/**
7676
* Construct a list of the values from the provided map.

lib/tests/program_options.cc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,30 @@ TEST_CASE("arrays with only values are converted to boost::po") {
3131
REQUIRE(vm.count("foo") == 1);
3232
}
3333

34-
TEST_CASE("arrays with objects are converted to paths in boost::po") {
34+
TEST_CASE("unregistered keys cause an exception when `allow_unregistered` is false") {
35+
po::options_description opts("");
36+
opts.add_options()("foo", "description");
37+
po::variables_map vm;
38+
REQUIRE_THROWS(po::store(parse_string(string("{foo : baz, bar : quux}"), opts, false), vm));
39+
}
40+
41+
TEST_CASE("unregistered keys are ignored when `allow_unregistered` is true") {
42+
po::options_description opts("");
43+
opts.add_options()("foo", "description");
44+
po::variables_map vm;
45+
po::store(parse_string(string("{foo : baz, bar : quux}"), opts, true), vm);
46+
REQUIRE(vm.count("foo") == 1);
47+
REQUIRE(vm.count("bar") == 0);
48+
}
49+
50+
TEST_CASE("arrays with objects cause an exception in boost::po") {
3551
po::options_description opts("");
3652
opts.add_options()("foo", "description");
3753
po::variables_map vm;
3854
REQUIRE_THROWS(po::store(parse_string(string("{foo : [ { bar : baz } ]}"), opts), vm));
3955
}
4056

41-
TEST_CASE("Arrays mixed with objects produce both a field and a nested path in boost:po") {
57+
TEST_CASE("Arrays mixed with objects cause an exception in boost:po") {
4258
po::options_description opts("");
4359
opts.add_options()
4460
("foo", po::value<vector<string>>(), "description");

0 commit comments

Comments
 (0)