Skip to content

Commit b891da9

Browse files
committed
fable: Accept // comments in JSON files
This can be configured by a Conan package option named "allow_comments", which is set to True by default.
1 parent 1a390ac commit b891da9

File tree

8 files changed

+68
-13
lines changed

8 files changed

+68
-13
lines changed

engine/conanfile.py

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class CloeEngine(ConanFile):
1414
"pedantic": [True, False],
1515
}
1616
default_options = {
17+
"fable:allow_comments": True,
18+
19+
# These don't change the output.
1720
"test": True,
1821
"pedantic": True,
1922
}

fable/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ target_link_libraries(${target}
3939
CONAN_PKG::nlohmann_json
4040
)
4141

42+
option(AllowComments "Allow comments when parsing JSON?" ON)
43+
if(AllowComments)
44+
target_compile_definitions(${target} PRIVATE PARSE_JSON_WITH_COMMENTS=true)
45+
else()
46+
target_compile_definitions(${target} PRIVATE PARSE_JSON_WITH_COMMENTS=false)
47+
endif()
48+
4249
# Testing ------------------------------------------------------------
4350
option(BuildTests "Build tests?" ON)
4451
if(BuildTests)

fable/conanfile.py

+3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ class Fable(ConanFile):
99
description = "JSON schema and configuration library"
1010
settings = "os", "compiler", "build_type", "arch"
1111
options = {
12+
"allow_comments": [True, False],
1213
"shared": [True, False],
1314
"fPIC": [True, False],
1415
"test": [True, False],
1516
}
1617
default_options = {
18+
"allow_comments": True,
1719
"shared": False,
1820
"fPIC": True,
1921
"test": True,
@@ -53,6 +55,7 @@ def _configure_cmake(self):
5355
self._cmake = CMake(self)
5456
self._cmake.definitions["CMAKE_EXPORT_COMPILE_COMMANDS"] = True
5557
self._cmake.definitions["FABLE_VERSION"] = self.version
58+
self._cmake.definitions["AllowComments"] = self.options.allow_comments
5659
self._cmake.definitions["BuildTests"] = self.options.test
5760
self._cmake.configure()
5861
return self._cmake

fable/include/fable/json.hpp

+32
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@
3232

3333
namespace fable {
3434

35+
/**
36+
* When parsing JSON from fable, should comments be allowed or lead to an
37+
* exception? Value is controlled by `PARSE_JSON_WITH_COMMENTS` define.
38+
* Default value is true.
39+
*
40+
* This does not automatically apply to use of `Json::parse`. Instead you
41+
* should use the parse_json helper function defined in this file.
42+
*/
43+
extern bool NLOHMANN_JSON_ALLOW_COMMENTS;
44+
45+
/**
46+
* When parsing JSON from fable, should exceptions be used?
47+
* Default value is set by `PARSE_JSON_WITH_COMMENTS` define.
48+
*
49+
* This is here for completeness. The fable library will not work
50+
* correctly if exceptions are disabled, so this should always be set to true.
51+
*/
52+
extern bool NLOHMANN_JSON_USE_EXCEPTIONS;
53+
3554
/**
3655
* The Json type maps to nlohmann::json.
3756
*
@@ -75,6 +94,19 @@ using JsonType = Json::value_t;
7594
*/
7695
std::string to_string(JsonType);
7796

97+
/**
98+
* Return the result of Json::parse, with the options to use exceptions and
99+
* allow comments as set in this library, from NLOHMANN_JSON_USE_EXCEPTIONS and
100+
* NLOHMANN_JSON_ALLOW_COMMENTS.
101+
*
102+
* See the documentation on each of these global variables for more details.
103+
*/
104+
template <typename InputType>
105+
inline Json parse_json(InputType&& input) {
106+
return Json::parse(std::forward<InputType>(input), nullptr, NLOHMANN_JSON_USE_EXCEPTIONS,
107+
NLOHMANN_JSON_ALLOW_COMMENTS);
108+
}
109+
78110
} // namespace fable
79111

80112
#endif // FABLE_JSON_HPP_

fable/include/fable/utility/gtest.hpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ inline void assert_schema_eq(const Confable& x, const Json& expect) {
4747
}
4848

4949
inline void assert_schema_eq(const Confable& x, const char expect[]) {
50-
assert_eq(x.schema().json_schema(), Json::parse(expect));
50+
assert_eq(x.schema().json_schema(), parse_json(expect));
5151
}
5252

5353
inline void assert_validate(const Confable& x, const Conf& input) {
@@ -60,15 +60,15 @@ inline void assert_validate(const Confable& x, const Conf& input) {
6060
}
6161

6262
inline void assert_validate(const Confable& x, const char json_input[]) {
63-
assert_validate(x, Conf{Json::parse(json_input)});
63+
assert_validate(x, Conf{parse_json(json_input)});
6464
}
6565

6666
inline void assert_invalidate(const Confable& x, const Conf& input) {
6767
ASSERT_THROW(x.schema().validate(input), SchemaError);
6868
}
6969

7070
inline void assert_invalidate(const Confable& x, const char json_input[]) {
71-
assert_invalidate(x, Conf{Json::parse(json_input)});
71+
assert_invalidate(x, Conf{parse_json(json_input)});
7272
}
7373

7474
template <typename T>
@@ -78,7 +78,7 @@ inline void assert_to_json(const T& x, const Json& expect) {
7878

7979
template <typename T>
8080
inline void assert_to_json(const T& x, const char json_expect[]) {
81-
assert_to_json(x, Json::parse(json_expect));
81+
assert_to_json(x, parse_json(json_expect));
8282
}
8383

8484
inline void assert_from_conf_throw(Confable& x, const Conf& input) {
@@ -88,7 +88,7 @@ inline void assert_from_conf_throw(Confable& x, const Conf& input) {
8888
}
8989

9090
inline void assert_from_conf_throw(Confable& x, const char json_input[]) {
91-
assert_from_conf_throw(x, Conf{Json::parse(json_input)});
91+
assert_from_conf_throw(x, Conf{parse_json(json_input)});
9292
}
9393

9494
template <typename T>
@@ -98,7 +98,7 @@ inline void assert_from_conf(T& x, const Conf& input) {
9898

9999
template <typename T>
100100
inline void assert_from_conf(T& x, const char json_input[]) {
101-
assert_from_conf(x, Conf{Json::parse(json_input)});
101+
assert_from_conf(x, Conf{parse_json(json_input)});
102102
}
103103

104104
template <typename T>
@@ -109,7 +109,7 @@ inline void assert_from_eq_to(T& x, const Json& identity) {
109109

110110
template <typename T>
111111
inline void assert_from_eq_to(T& x, const char json_input[]) {
112-
assert_from_eq_to(x, Json::parse(json_input));
112+
assert_from_eq_to(x, parse_json(json_input));
113113
}
114114

115115
} // namespace fable

fable/src/fable/conf.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <boost/filesystem.hpp> // for path
3131

3232
#include <fable/error.hpp> // for ConfError, WrongType, MissingProperty
33+
#include <fable/json.hpp> // for NLOHMANN_JSON_ALLOW_COMMENTS
3334

3435
namespace fable {
3536

@@ -39,7 +40,7 @@ Conf::Conf(const std::string& file) : file_(file) {
3940
throw Error("could not open file {}: {}", file, strerror(errno));
4041
}
4142
try {
42-
ifs >> data_;
43+
data_ = parse_json(ifs);
4344
} catch (std::exception& e) {
4445
throw Error("unable to parse file {}: {}", file, e.what());
4546
}

fable/src/fable/json.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,23 @@
2020
* \see fable/json.hpp
2121
*/
2222

23+
#ifndef PARSE_JSON_USE_EXCEPTIONS
24+
#define PARSE_JSON_USE_EXCEPTIONS true
25+
#endif
26+
27+
#ifndef PARSE_JSON_WITH_COMMENTS
28+
#define PARSE_JSON_WITH_COMMENTS true
29+
#endif
30+
2331
#include <fable/json.hpp>
2432

2533
#include <string> // for string
2634

2735
namespace fable {
2836

37+
bool NLOHMANN_JSON_USE_EXCEPTIONS = PARSE_JSON_USE_EXCEPTIONS;
38+
bool NLOHMANN_JSON_ALLOW_COMMENTS = PARSE_JSON_WITH_COMMENTS;
39+
2940
std::string to_string(JsonType type) {
3041
switch (type) {
3142
case JsonType::null:

fable/src/fable/utility.cpp

+3-5
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ Json read_json_from_file(const char* filepath) {
4040
throw std::runtime_error(std::string("could not open file: ") + filepath);
4141
}
4242

43-
Json j;
44-
ifs >> j;
45-
return j;
43+
return parse_json(ifs);
4644
}
4745

4846
Json read_json_from_stdin() {
@@ -64,7 +62,7 @@ Json read_json_with_interpolation(const std::string& filepath_or_stdin, const En
6462
std::istreambuf_iterator<char> begin(std::cin), end;
6563
std::string s(begin, end);
6664
s = interpolate_vars(s, env);
67-
return Json::parse(s);
65+
return parse_json(s);
6866
} else {
6967
std::ifstream ifs(filepath_or_stdin);
7068
if (ifs.fail()) {
@@ -73,7 +71,7 @@ Json read_json_with_interpolation(const std::string& filepath_or_stdin, const En
7371
std::istreambuf_iterator<char> begin(ifs), end;
7472
std::string s(begin, end);
7573
s = interpolate_vars(s, env);
76-
return Json::parse(s);
74+
return parse_json(s);
7775
}
7876
}
7977

0 commit comments

Comments
 (0)