Builder::settings_

We use Json::Value to configure the builders so we can maintain
binary-compatibility easily.
This commit is contained in:
Christopher Dunn 2015-02-09 17:22:28 -06:00
parent 694dbcb328
commit a9e1ab302d
5 changed files with 149 additions and 44 deletions

View File

@ -92,13 +92,13 @@ features without losing binary-compatibility.
\code \code
// For convenience, use `writeString()` with a specialized builder. // For convenience, use `writeString()` with a specialized builder.
Json::StreamWriterBuilder wbuilder; Json::StreamWriterBuilder wbuilder;
wbuilder.settings["indentation"] = "\t"; wbuilder.settings_["indentation"] = "\t";
std::string document = Json::writeString(wbuilder, root); std::string document = Json::writeString(wbuilder, root);
// Here, using a specialized Builder, we discard comments and // Here, using a specialized Builder, we discard comments and
// record errors as we parse. // record errors as we parse.
Json::CharReaderBuilder rbuilder; Json::CharReaderBuilder rbuilder;
rbuilder.settings["collectComments"] = false; rbuilder.settings_["collectComments"] = false;
std::string errs; std::string errs;
bool ok = Json::parseFromStream(rbuilder, std::cin, &root, &errs); bool ok = Json::parseFromStream(rbuilder, std::cin, &root, &errs);
\endcode \endcode

View File

@ -270,7 +270,9 @@ public:
class Factory { class Factory {
public: public:
/// \brief Allocate a CharReader via operator new(). /** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual CharReader* newCharReader() const = 0; virtual CharReader* newCharReader() const = 0;
}; // Factory }; // Factory
}; // CharReader }; // CharReader
@ -283,29 +285,39 @@ Usage:
\code \code
using namespace Json; using namespace Json;
CharReaderBuilder builder; CharReaderBuilder builder;
builder.collectComments_ = false; builder.settings_["collectComments"] = false;
Value value; Value value;
std::string errs; std::string errs;
bool ok = parseFromStream(builder, std::cin, &value, &errs); bool ok = parseFromStream(builder, std::cin, &value, &errs);
\endcode \endcode
*/ */
class CharReaderBuilder : public CharReader::Factory { class JSON_API CharReaderBuilder : public CharReader::Factory {
public: public:
/** default: true // Note: We use a Json::Value so that we can add data-members to this class
* // without a major version bump.
* It is possible to "allow" comments but still not "collect" them. /** Configuration of this builder.
*/ Available settings (case-sensitive):
bool collectComments_; - "collectComments": false or true (default=true)
/** default: all() - TODO: other features ...
* But don't trust these docs. You can examine 'settings_` yourself
* For historical reasons, Features is a separate structure. to see the defaults. You can also write and read them just like any
*/ JSON Value.
Features features_; */
Json::Value settings_;
CharReaderBuilder(); CharReaderBuilder();
virtual ~CharReaderBuilder(); virtual ~CharReaderBuilder();
virtual CharReader* newCharReader() const; virtual CharReader* newCharReader() const;
/** \return true if 'settings' are illegal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
*/
static void setDefaults(Json::Value* settings);
}; };
/** Consume entire stream and use its begin/end. /** Consume entire stream and use its begin/end.

View File

@ -64,7 +64,10 @@ public:
class JSON_API Factory { class JSON_API Factory {
public: public:
virtual ~Factory(); virtual ~Factory();
/// Do not take ownership of sout, but maintain a reference. /** \brief Allocate a CharReader via operator new().
* Do not take ownership of sout, but maintain a reference.
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual StreamWriter* newStreamWriter(std::ostream* sout) const = 0; virtual StreamWriter* newStreamWriter(std::ostream* sout) const = 0;
}; // Factory }; // Factory
}; // StreamWriter }; // StreamWriter
@ -77,41 +80,49 @@ std::string writeString(StreamWriter::Factory const& factory, Value const& root)
/** \brief Build a StreamWriter implementation. /** \brief Build a StreamWriter implementation.
\deprecated This is experimental and will be altered before the next release.
Usage: Usage:
\code \code
using namespace Json; using namespace Json;
Value value = ...; Value value = ...;
StreamWriterBuilder builder; StreamWriterBuilder builder;
builder.cs_ = StreamWriter::CommentStyle::None; builder.settings_["commentStyle"] = "None";
builder.indentation_ = " "; // or whatever you like builder.settings_["indentation"] = " "; // or whatever you like
std::unique_ptr<Json::StreamWriter> writer(
builder.newStreamWriter(&std::cout));
writer->write(value); writer->write(value);
std::cout << std::endl; // add lf and flush std::cout << std::endl; // add lf and flush
\endcode \endcode
*/ */
class JSON_API StreamWriterBuilder : public StreamWriter::Factory { class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
public: public:
// Note: We cannot add data-members to this class without a major version bump. // Note: We use a Json::Value so that we can add data-members to this class
// So these might as well be completely exposed. // without a major version bump.
/** Configuration of this builder.
/** \brief How to write comments. Available settings (case-sensitive):
* Default: All - "commentStyle": "None", "Some", or "All" (default="All")
*/ - "indentation": (default="\t")
StreamWriter::CommentStyle::Enum cs_; But don't trust these docs. You can examine 'settings_` yourself
/** \brief Write in human-friendly style. to see the defaults. You can also write and read them just like any
JSON Value.
If "", then skip all indentation and newlines. */
In that case, you probably want CommentStyle::None also. Json::Value settings_;
Default: "\t"
*/
std::string indentation_;
StreamWriterBuilder(); StreamWriterBuilder();
virtual ~StreamWriterBuilder(); virtual ~StreamWriterBuilder();
/// Do not take ownership of sout, but maintain a reference. /** Do not take ownership of sout, but maintain a reference.
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual StreamWriter* newStreamWriter(std::ostream* sout) const; virtual StreamWriter* newStreamWriter(std::ostream* sout) const;
/** \return true if 'settings' are illegal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
*/
static void setDefaults(Json::Value* settings);
}; };
/** \brief Build a StreamWriter implementation. /** \brief Build a StreamWriter implementation.
@ -126,6 +137,8 @@ public:
* w->write(value); * w->write(value);
* delete w; * delete w;
* \endcode * \endcode
*
* \deprecated Use StreamWriterBuilder
*/ */
class JSON_API OldCompressingStreamWriterBuilder : public StreamWriter::Factory class JSON_API OldCompressingStreamWriterBuilder : public StreamWriter::Factory
{ {

View File

@ -16,6 +16,7 @@
#include <istream> #include <istream>
#include <sstream> #include <sstream>
#include <memory> #include <memory>
#include <set>
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below #if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
#define snprintf _snprintf #define snprintf _snprintf
@ -912,14 +913,48 @@ public:
}; };
CharReaderBuilder::CharReaderBuilder() CharReaderBuilder::CharReaderBuilder()
: collectComments_(true) {
, features_(Features::all()) setDefaults(&settings_);
{} }
CharReaderBuilder::~CharReaderBuilder() CharReaderBuilder::~CharReaderBuilder()
{} {}
CharReader* CharReaderBuilder::newCharReader() const CharReader* CharReaderBuilder::newCharReader() const
{ {
return new OldReader(collectComments_, features_); if (!validate(NULL)) throw std::runtime_error("invalid settings");
// TODO: Maybe serialize the invalid settings into the exception.
bool collectComments = settings_["collectComments"].asBool();
Features features = Features::all();
// TODO: Fill in features.
return new OldReader(collectComments, features);
}
static void getValidReaderKeys(std::set<std::string>* valid_keys)
{
valid_keys->clear();
valid_keys->insert("collectComments");
}
bool CharReaderBuilder::validate(Json::Value* invalid) const
{
Json::Value my_invalid;
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
Json::Value& inv = *invalid;
bool valid = true;
std::set<std::string> valid_keys;
getValidReaderKeys(&valid_keys);
Value::Members keys = settings_.getMemberNames();
size_t n = keys.size();
for (size_t i = 0; i < n; ++i) {
std::string const& key = keys[i];
if (valid_keys.find(key) == valid_keys.end()) {
inv[key] = settings_[key];
}
}
return valid;
}
// static
void CharReaderBuilder::setDefaults(Json::Value* settings)
{
(*settings)["collectComments"] = true;
} }
////////////////////////////////// //////////////////////////////////

View File

@ -11,6 +11,7 @@
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#include <set>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
@ -950,23 +951,67 @@ StreamWriter::~StreamWriter()
StreamWriter::Factory::~Factory() StreamWriter::Factory::~Factory()
{} {}
StreamWriterBuilder::StreamWriterBuilder() StreamWriterBuilder::StreamWriterBuilder()
: cs_(StreamWriter::CommentStyle::All) {
, indentation_("\t") setDefaults(&settings_);
{} }
StreamWriterBuilder::~StreamWriterBuilder() StreamWriterBuilder::~StreamWriterBuilder()
{} {}
StreamWriter* StreamWriterBuilder::newStreamWriter(std::ostream* stream) const StreamWriter* StreamWriterBuilder::newStreamWriter(std::ostream* stream) const
{ {
if (!validate(NULL)) throw std::runtime_error("invalid settings");
// TODO: Maybe serialize the invalid settings into the exception.
std::string indentation = settings_["indentation"].asString();
std::string cs_str = settings_["commentStyle"].asString();
StreamWriter::CommentStyle::Enum cs = StreamWriter::CommentStyle::All;
if (cs_str == "All") {
cs = StreamWriter::CommentStyle::All;
} else if (cs_str == "None") {
cs = StreamWriter::CommentStyle::None;
} else {
return NULL;
}
std::string colonSymbol = " : "; std::string colonSymbol = " : ";
if (indentation_.empty()) { if (indentation.empty()) {
colonSymbol = ":"; colonSymbol = ":";
} }
std::string nullSymbol = "null"; std::string nullSymbol = "null";
std::string endingLineFeedSymbol = ""; std::string endingLineFeedSymbol = "";
return new BuiltStyledStreamWriter(stream, return new BuiltStyledStreamWriter(stream,
indentation_, cs_, indentation, cs,
colonSymbol, nullSymbol, endingLineFeedSymbol); colonSymbol, nullSymbol, endingLineFeedSymbol);
} }
static void getValidWriterKeys(std::set<std::string>* valid_keys)
{
valid_keys->clear();
valid_keys->insert("indentation");
valid_keys->insert("commentStyle");
}
bool StreamWriterBuilder::validate(Json::Value* invalid) const
{
Json::Value my_invalid;
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
Json::Value& inv = *invalid;
bool valid = true;
std::set<std::string> valid_keys;
getValidWriterKeys(&valid_keys);
Value::Members keys = settings_.getMemberNames();
size_t n = keys.size();
for (size_t i = 0; i < n; ++i) {
std::string const& key = keys[i];
if (valid_keys.find(key) == valid_keys.end()) {
inv[key] = settings_[key];
}
}
return valid;
}
// static
void StreamWriterBuilder::setDefaults(Json::Value* settings)
{
(*settings)["commentStyle"] = "All";
(*settings)["indentation"] = "\t";
}
/* /*
// This might become public someday. // This might become public someday.
class StreamWriterBuilderFactory { class StreamWriterBuilderFactory {