Replace stream-based dumping interface with an outputrange-based interface (#154)
Replace stream-based dumping interface with an outputrange-based interface merged-on-behalf-of: Cameron Ross <elpenguino@gmail.com>
This commit is contained in:
parent
8f9dafdef3
commit
8e0ca41eb5
|
@ -14,5 +14,5 @@ void main()
|
|||
writeln("The answer is ", root["Answer"].as!int);
|
||||
|
||||
//Dump the loaded document to output.yaml.
|
||||
Dumper("output.yaml").dump(root);
|
||||
dumper(File("output.yaml", "w").lockingTextWriter).dump(root);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ void main()
|
|||
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
|
||||
"0123456789abcdefABCDEF");
|
||||
|
||||
auto dumper = Dumper("output.yaml");
|
||||
auto dumper = dumper(File("output.yaml", "w").lockingTextWriter);
|
||||
dumper.representer = representer;
|
||||
dumper.resolver = resolver;
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ void main(string[] args) //@safe
|
|||
{
|
||||
if(dump)
|
||||
{
|
||||
Dumper(file ~ ".dump").dump(nodes);
|
||||
dumper(File(file ~ ".dump", "w").lockingTextWriter).dump(nodes);
|
||||
}
|
||||
}
|
||||
void runGetBenchmark() @safe
|
||||
|
|
|
@ -297,15 +297,17 @@ void main(string[] args)
|
|||
//Generate and dump the nodes.
|
||||
Node[] generated = generate(configFile);
|
||||
|
||||
auto dumper = Dumper(args[1]);
|
||||
auto dumper = dumper(File(args[1], "w").lockingTextWriter);
|
||||
auto encoding = config["encoding"];
|
||||
dumper.encoding = encoding == "utf-16" ? Encoding.UTF_16:
|
||||
encoding == "utf-32" ? Encoding.UTF_32:
|
||||
Encoding.UTF_8;
|
||||
|
||||
dumper.indent = config["indent"].as!uint;
|
||||
dumper.textWidth = config["text-width"].as!uint;
|
||||
dumper.dump(generated);
|
||||
switch(encoding.as!string)
|
||||
{
|
||||
case "utf-16": dumper.dump!wchar(generated); break;
|
||||
case "utf-32": dumper.dump!dchar(generated); break;
|
||||
default: dumper.dump!char(generated); break;
|
||||
}
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
|
|
|
@ -31,7 +31,6 @@ dyaml_src = [
|
|||
'source/dyaml/resolver.d',
|
||||
'source/dyaml/scanner.d',
|
||||
'source/dyaml/serializer.d',
|
||||
'source/dyaml/stream.d',
|
||||
'source/dyaml/style.d',
|
||||
'source/dyaml/tagdirective.d',
|
||||
'source/dyaml/test/common.d',
|
||||
|
|
|
@ -11,13 +11,11 @@
|
|||
*/
|
||||
module dyaml.dumper;
|
||||
|
||||
|
||||
//import std.stream;
|
||||
import std.array;
|
||||
import std.range.primitives;
|
||||
import std.typecons;
|
||||
|
||||
import dyaml.stream;
|
||||
import dyaml.emitter;
|
||||
import dyaml.encoding;
|
||||
import dyaml.event;
|
||||
import dyaml.exception;
|
||||
import dyaml.linebreak;
|
||||
|
@ -34,9 +32,15 @@ import dyaml.tagdirective;
|
|||
* User specified Representer and/or Resolver can be used to support new
|
||||
* tags / data types.
|
||||
*
|
||||
* Setters are provided to affect output details (style, encoding, etc.).
|
||||
* Setters are provided to affect output details (style, etc.).
|
||||
*/
|
||||
struct Dumper
|
||||
auto dumper(Range)(auto ref Range output)
|
||||
if (isOutputRange!(Range, char) || isOutputRange!(Range, wchar) || isOutputRange!(Range, dchar))
|
||||
{
|
||||
return Dumper!Range(output);
|
||||
}
|
||||
|
||||
struct Dumper(Range)
|
||||
{
|
||||
private:
|
||||
//Resolver to resolve tags.
|
||||
|
@ -45,9 +49,7 @@ struct Dumper
|
|||
Representer representer_;
|
||||
|
||||
//Stream to write to.
|
||||
YStream stream_;
|
||||
//True if this Dumper owns stream_ and needs to destroy it in the destructor.
|
||||
bool weOwnStream_;
|
||||
Range stream_;
|
||||
|
||||
//Write scalars in canonical form?
|
||||
bool canonical_;
|
||||
|
@ -57,8 +59,6 @@ struct Dumper
|
|||
uint textWidth_ = 80;
|
||||
//Line break to use.
|
||||
LineBreak lineBreak_ = LineBreak.Unix;
|
||||
//Character encoding to use.
|
||||
Encoding encoding_ = Encoding.UTF_8;
|
||||
//YAML version string.
|
||||
string YAMLVersion_ = "1.1";
|
||||
//Tag directives to use.
|
||||
|
@ -73,45 +73,21 @@ struct Dumper
|
|||
|
||||
public:
|
||||
@disable this();
|
||||
@disable bool opEquals(ref Dumper);
|
||||
@disable int opCmp(ref Dumper);
|
||||
@disable bool opEquals(ref Dumper!Range);
|
||||
@disable int opCmp(ref Dumper!Range);
|
||||
|
||||
/**
|
||||
* Construct a Dumper writing to a file.
|
||||
*
|
||||
* Params: filename = File name to write to.
|
||||
*
|
||||
* Throws: YAMLException if the file can not be dumped to (e.g. cannot be opened).
|
||||
*/
|
||||
this(string filename) @safe
|
||||
{
|
||||
name_ = filename;
|
||||
//try{this(new File(filename, FileMode.OutNew));}
|
||||
try{this(new YFile(filename));}
|
||||
//catch(StreamException e)
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new YAMLException("Unable to open file " ~ filename ~
|
||||
" for YAML dumping: " ~ e.msg);
|
||||
}
|
||||
// need to destroy the File we constructed.
|
||||
weOwnStream_ = true;
|
||||
}
|
||||
|
||||
///Construct a Dumper writing to a _stream. This is useful to e.g. write to memory.
|
||||
this(YStream stream) @safe
|
||||
this(Range stream) @safe
|
||||
{
|
||||
resolver_ = new Resolver();
|
||||
representer_ = new Representer();
|
||||
stream_ = stream;
|
||||
}
|
||||
|
||||
///Destroy the Dumper.
|
||||
@trusted ~this()
|
||||
{
|
||||
if(weOwnStream_) { destroy(stream_); }
|
||||
}
|
||||
|
||||
///Set stream _name. Used in debugging messages.
|
||||
@property void name(string name) pure @safe nothrow
|
||||
{
|
||||
|
@ -159,12 +135,6 @@ struct Dumper
|
|||
lineBreak_ = lineBreak;
|
||||
}
|
||||
|
||||
///Set character _encoding to use. UTF-8 by default.
|
||||
@property void encoding(Encoding encoding) pure @safe nothrow
|
||||
{
|
||||
encoding_ = encoding;
|
||||
}
|
||||
|
||||
///Always explicitly write document start?
|
||||
@property void explicitStart(bool explicit) pure @safe nothrow
|
||||
{
|
||||
|
@ -218,7 +188,7 @@ struct Dumper
|
|||
///
|
||||
@safe unittest
|
||||
{
|
||||
Dumper dumper = Dumper("example.yaml");
|
||||
auto dumper = dumper(new Appender!string());
|
||||
string[string] directives;
|
||||
directives["!short!"] = "tag:long.org,2011:";
|
||||
//This will emit tags starting with "tag:long.org,2011"
|
||||
|
@ -239,12 +209,13 @@ struct Dumper
|
|||
* Throws: YAMLException on error (e.g. invalid nodes,
|
||||
* unable to write to file/stream).
|
||||
*/
|
||||
void dump(Node[] documents ...) @safe
|
||||
void dump(CharacterType = char)(Node[] documents ...) @trusted
|
||||
if (isOutputRange!(Range, CharacterType))
|
||||
{
|
||||
try
|
||||
{
|
||||
auto emitter = new Emitter(stream_, canonical_, indent_, textWidth_, lineBreak_);
|
||||
auto serializer = Serializer(emitter, resolver_, encoding_, explicitStart_,
|
||||
auto emitter = new Emitter!(Range, CharacterType)(stream_, canonical_, indent_, textWidth_, lineBreak_);
|
||||
auto serializer = Serializer!(Range, CharacterType)(emitter, resolver_, explicitStart_,
|
||||
explicitEnd_, YAMLVersion_, tags_);
|
||||
foreach(ref document; documents)
|
||||
{
|
||||
|
@ -266,11 +237,11 @@ struct Dumper
|
|||
*
|
||||
* Throws: YAMLException if unable to emit.
|
||||
*/
|
||||
void emit(Event[] events) @safe
|
||||
void emit(CharacterType = char)(Event[] events) @safe
|
||||
{
|
||||
try
|
||||
{
|
||||
auto emitter = Emitter(stream_, canonical_, indent_, textWidth_, lineBreak_);
|
||||
auto emitter = Emitter!(Range, CharacterType)(stream_, canonical_, indent_, textWidth_, lineBreak_);
|
||||
foreach(ref event; events)
|
||||
{
|
||||
emitter.emit(event);
|
||||
|
@ -287,24 +258,23 @@ struct Dumper
|
|||
@safe unittest
|
||||
{
|
||||
auto node = Node([1, 2, 3, 4, 5]);
|
||||
Dumper("example.yaml").dump(node);
|
||||
dumper(new Appender!string()).dump(node);
|
||||
}
|
||||
///Write multiple YAML documents to a file
|
||||
@safe unittest
|
||||
{
|
||||
auto node1 = Node([1, 2, 3, 4, 5]);
|
||||
auto node2 = Node("This document contains only one string");
|
||||
Dumper("example.yaml").dump(node1, node2);
|
||||
dumper(new Appender!string()).dump(node1, node2);
|
||||
//Or with an array:
|
||||
Dumper("example.yaml").dump([node1, node2]);
|
||||
dumper(new Appender!string()).dump([node1, node2]);
|
||||
}
|
||||
///Write to memory
|
||||
@safe unittest
|
||||
{
|
||||
import dyaml.stream;
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node([1, 2, 3, 4, 5]);
|
||||
Dumper(stream).dump(node);
|
||||
dumper(stream).dump(node);
|
||||
}
|
||||
///Use a custom representer/resolver to support custom data types and/or implicit tags
|
||||
@safe unittest
|
||||
|
@ -313,7 +283,7 @@ struct Dumper
|
|||
auto representer = new Representer();
|
||||
auto resolver = new Resolver();
|
||||
//Add representer functions / resolver expressions here...
|
||||
auto dumper = Dumper("example.yaml");
|
||||
auto dumper = dumper(new Appender!string());
|
||||
dumper.representer = representer;
|
||||
dumper.resolver = resolver;
|
||||
dumper.dump(node);
|
||||
|
@ -321,10 +291,9 @@ struct Dumper
|
|||
// Explicit document start/end markers
|
||||
@safe unittest
|
||||
{
|
||||
import dyaml.stream;
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node([1, 2, 3, 4, 5]);
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.explicitEnd = true;
|
||||
dumper.explicitStart = true;
|
||||
dumper.YAMLVersion = null;
|
||||
|
@ -337,10 +306,9 @@ struct Dumper
|
|||
// No explicit document start/end markers
|
||||
@safe unittest
|
||||
{
|
||||
import dyaml.stream;
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node([1, 2, 3, 4, 5]);
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.explicitEnd = false;
|
||||
dumper.explicitStart = false;
|
||||
dumper.YAMLVersion = null;
|
||||
|
|
|
@ -23,7 +23,6 @@ import std.system;
|
|||
import std.typecons;
|
||||
import std.utf;
|
||||
|
||||
import dyaml.stream;
|
||||
import dyaml.encoding;
|
||||
import dyaml.escapes;
|
||||
import dyaml.event;
|
||||
|
@ -68,7 +67,7 @@ private alias isFlowIndicator = among!(',', '?', '[', ']', '{', '}');
|
|||
private alias isSpace = among!('\0', '\n', '\r', '\u0085', '\u2028', '\u2029', ' ', '\t');
|
||||
|
||||
//Emits YAML events into a file/stream.
|
||||
struct Emitter
|
||||
struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||
{
|
||||
private:
|
||||
///Default tag handle shortcuts and replacements.
|
||||
|
@ -76,9 +75,7 @@ struct Emitter
|
|||
[TagDirective("!", "!"), TagDirective("!!", "tag:yaml.org,2002:")];
|
||||
|
||||
///Stream to write to.
|
||||
YStream stream_;
|
||||
///Encoding can be overriden by STREAM-START.
|
||||
Encoding encoding_ = Encoding.UTF_8;
|
||||
Range stream_;
|
||||
|
||||
///Stack of states.
|
||||
Appender!(void function() @safe[]) states_;
|
||||
|
@ -159,15 +156,13 @@ struct Emitter
|
|||
/**
|
||||
* Construct an emitter.
|
||||
*
|
||||
* Params: stream = YStream to write to. Must be writable.
|
||||
* Params: stream = Output range to write to.
|
||||
* canonical = Write scalars in canonical form?
|
||||
* indent = Indentation width.
|
||||
* lineBreak = Line break character/s.
|
||||
*/
|
||||
this(YStream stream, const bool canonical, const int indent, const int width,
|
||||
this(Range stream, const bool canonical, const int indent, const int width,
|
||||
const LineBreak lineBreak) @trusted
|
||||
in{assert(stream.writeable, "Can't emit YAML to a non-writable stream");}
|
||||
body
|
||||
{
|
||||
states_.reserve(32);
|
||||
indents_.reserve(32);
|
||||
|
@ -224,19 +219,22 @@ struct Emitter
|
|||
///Write a string to the file/stream.
|
||||
void writeString(const char[] str) @safe
|
||||
{
|
||||
try final switch(encoding_)
|
||||
try
|
||||
{
|
||||
static if(is(CharType == char))
|
||||
{
|
||||
copy(str, stream_);
|
||||
}
|
||||
static if(is(CharType == wchar))
|
||||
{
|
||||
case Encoding.UTF_8:
|
||||
stream_.writeExact(str);
|
||||
break;
|
||||
case Encoding.UTF_16:
|
||||
const buffer = to!wstring(str);
|
||||
stream_.writeExact(buffer);
|
||||
break;
|
||||
case Encoding.UTF_32:
|
||||
copy(buffer, stream_);
|
||||
}
|
||||
static if(is(CharType == dchar))
|
||||
{
|
||||
const buffer = to!dstring(str);
|
||||
stream_.writeExact(buffer);
|
||||
break;
|
||||
copy(buffer, stream_);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -319,7 +317,6 @@ struct Emitter
|
|||
enforce(eventTypeIs(EventID.StreamStart),
|
||||
new EmitterException("Expected YStreamStart, but got " ~ event_.idString));
|
||||
|
||||
encoding_ = event_.encoding;
|
||||
writeStreamStart();
|
||||
nextExpected(&expectDocumentStart!(Yes.first));
|
||||
}
|
||||
|
@ -411,7 +408,6 @@ struct Emitter
|
|||
writeIndicator("...", Yes.needWhitespace);
|
||||
writeIndent();
|
||||
}
|
||||
stream_.flush();
|
||||
nextExpected(&expectDocumentStart!(No.first));
|
||||
}
|
||||
|
||||
|
@ -749,7 +745,7 @@ struct Emitter
|
|||
//{
|
||||
// writeIndent();
|
||||
//}
|
||||
auto writer = ScalarWriter(this, analysis_.scalar,
|
||||
auto writer = ScalarWriter!(Range, CharType)(this, analysis_.scalar,
|
||||
context_ != Context.MappingSimpleKey);
|
||||
with(writer) final switch(style_)
|
||||
{
|
||||
|
@ -1153,29 +1149,15 @@ struct Emitter
|
|||
///Start the YAML stream (write the unicode byte order mark).
|
||||
void writeStreamStart() @safe
|
||||
{
|
||||
immutable(ubyte)[] bom;
|
||||
//Write BOM (except for UTF-8)
|
||||
final switch(encoding_)
|
||||
static if(is(CharType == wchar) || is(CharType == dchar))
|
||||
{
|
||||
case Encoding.UTF_8:
|
||||
break;
|
||||
case Encoding.UTF_16:
|
||||
bom = std.system.endian == Endian.littleEndian
|
||||
? bomTable[BOM.utf16le].sequence
|
||||
: bomTable[BOM.utf16be].sequence;
|
||||
break;
|
||||
case Encoding.UTF_32:
|
||||
bom = std.system.endian == Endian.littleEndian
|
||||
? bomTable[BOM.utf32le].sequence
|
||||
: bomTable[BOM.utf32be].sequence;
|
||||
break;
|
||||
stream_.put(cast(CharType)'\uFEFF');
|
||||
}
|
||||
|
||||
enforce(stream_.write(bom) == bom.length, new EmitterException("Unable to write to stream"));
|
||||
}
|
||||
|
||||
///End the YAML stream.
|
||||
void writeStreamEnd() @safe {stream_.flush();}
|
||||
void writeStreamEnd() @safe {}
|
||||
|
||||
///Write an indicator (e.g. ":", "[", ">", etc.).
|
||||
void writeIndicator(const char[] indicator,
|
||||
|
@ -1270,7 +1252,7 @@ struct Emitter
|
|||
private:
|
||||
|
||||
///RAII struct used to write out scalar values.
|
||||
struct ScalarWriter
|
||||
struct ScalarWriter(Range, CharType)
|
||||
{
|
||||
invariant()
|
||||
{
|
||||
|
@ -1279,14 +1261,14 @@ struct ScalarWriter
|
|||
}
|
||||
|
||||
private:
|
||||
@disable int opCmp(ref Emitter);
|
||||
@disable bool opEquals(ref Emitter);
|
||||
@disable int opCmp(ref Emitter!(Range, CharType));
|
||||
@disable bool opEquals(ref Emitter!(Range, CharType));
|
||||
|
||||
///Used as "null" UTF-32 character.
|
||||
static immutable dcharNone = dchar.max;
|
||||
|
||||
///Emitter used to emit the scalar.
|
||||
Emitter* emitter_;
|
||||
Emitter!(Range, CharType)* emitter_;
|
||||
|
||||
///UTF-8 encoded text of the scalar to write.
|
||||
string text_;
|
||||
|
@ -1307,7 +1289,7 @@ struct ScalarWriter
|
|||
|
||||
public:
|
||||
///Construct a ScalarWriter using emitter to output text.
|
||||
this(ref Emitter emitter, string text, const bool split = true) @trusted nothrow
|
||||
this(ref Emitter!(Range, CharType) emitter, string text, const bool split = true) @trusted nothrow
|
||||
{
|
||||
emitter_ = &emitter;
|
||||
text_ = text;
|
||||
|
@ -1502,7 +1484,7 @@ struct ScalarWriter
|
|||
///Write text as plain scalar.
|
||||
void writePlain() @safe
|
||||
{
|
||||
if(emitter_.context_ == Emitter.Context.Root){emitter_.openEnded_ = true;}
|
||||
if(emitter_.context_ == Emitter!(Range, CharType).Context.Root){emitter_.openEnded_ = true;}
|
||||
if(text_ == ""){return;}
|
||||
if(!emitter_.whitespace_)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,6 @@ module dyaml.event;
|
|||
import std.array;
|
||||
import std.conv;
|
||||
|
||||
import dyaml.encoding;
|
||||
import dyaml.exception;
|
||||
import dyaml.reader;
|
||||
import dyaml.tagdirective;
|
||||
|
@ -80,8 +79,6 @@ struct Event
|
|||
*/
|
||||
bool explicitDocument;
|
||||
}
|
||||
///Encoding of the stream, if this is a StreamStart.
|
||||
Encoding encoding;
|
||||
///Collection style, if this is a SequenceStart or MappingStart.
|
||||
CollectionStyle collectionStyle = CollectionStyle.Invalid;
|
||||
|
||||
|
@ -159,16 +156,14 @@ Event collectionStartEvent(EventID id)
|
|||
*
|
||||
* Params: start = Start position of the event in the file/stream.
|
||||
* end = End position of the event in the file/stream.
|
||||
* encoding = Encoding of the stream.
|
||||
*/
|
||||
Event streamStartEvent(const Mark start, const Mark end, const Encoding encoding)
|
||||
Event streamStartEvent(const Mark start, const Mark end)
|
||||
pure @safe nothrow
|
||||
{
|
||||
Event result;
|
||||
result.startMark = start;
|
||||
result.endMark = end;
|
||||
result.id = EventID.StreamStart;
|
||||
result.encoding = encoding;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ struct Loader
|
|||
catch(YAMLException e)
|
||||
{
|
||||
throw new YAMLException("Unable to open %s for YAML loading: %s"
|
||||
.format(name_, e.msg));
|
||||
.format(name_, e.msg), e.file, e.line);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2011,24 +2011,22 @@ struct Node
|
|||
@safe unittest
|
||||
{
|
||||
import dyaml.dumper;
|
||||
import dyaml.stream;
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node([1, 2, 3, 4, 5]);
|
||||
node.setStyle(CollectionStyle.Block);
|
||||
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.dump(node);
|
||||
}
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
import dyaml.dumper;
|
||||
import dyaml.stream;
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node(4);
|
||||
node.setStyle(ScalarStyle.Literal);
|
||||
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.dump(node);
|
||||
}
|
||||
@safe unittest
|
||||
|
@ -2039,12 +2037,11 @@ struct Node
|
|||
@safe unittest
|
||||
{
|
||||
import dyaml.dumper;
|
||||
import dyaml.stream;
|
||||
{
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node([1, 2, 3, 4, 5]);
|
||||
node.setStyle(CollectionStyle.Block);
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.explicitEnd = false;
|
||||
dumper.explicitStart = false;
|
||||
dumper.YAMLVersion = null;
|
||||
|
@ -2054,10 +2051,10 @@ struct Node
|
|||
assert(stream.data[0] == '-');
|
||||
}
|
||||
{
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node([1, 2, 3, 4, 5]);
|
||||
node.setStyle(CollectionStyle.Flow);
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.explicitEnd = false;
|
||||
dumper.explicitStart = false;
|
||||
dumper.YAMLVersion = null;
|
||||
|
@ -2067,10 +2064,10 @@ struct Node
|
|||
assert(stream.data[0] == '[');
|
||||
}
|
||||
{
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node(1);
|
||||
node.setStyle(ScalarStyle.SingleQuoted);
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.explicitEnd = false;
|
||||
dumper.explicitStart = false;
|
||||
dumper.YAMLVersion = null;
|
||||
|
@ -2079,10 +2076,10 @@ struct Node
|
|||
assert(stream.data == "!!int '1'\n");
|
||||
}
|
||||
{
|
||||
auto stream = new YMemoryStream();
|
||||
auto stream = new Appender!string();
|
||||
auto node = Node(1);
|
||||
node.setStyle(ScalarStyle.DoubleQuoted);
|
||||
auto dumper = Dumper(stream);
|
||||
auto dumper = dumper(stream);
|
||||
dumper.explicitEnd = false;
|
||||
dumper.explicitStart = false;
|
||||
dumper.YAMLVersion = null;
|
||||
|
|
|
@ -256,7 +256,7 @@ final class Parser
|
|||
{
|
||||
const token = scanner_.getToken();
|
||||
state_ = &parseImplicitDocumentStart;
|
||||
return streamStartEvent(token.startMark, token.endMark, token.encoding);
|
||||
return streamStartEvent(token.startMark, token.endMark);
|
||||
}
|
||||
|
||||
/// Parse implicit document start, unless explicit detected: if so, parse explicit.
|
||||
|
|
|
@ -154,7 +154,7 @@ final class Representer
|
|||
return representer.representScalar("!mystruct.tag", scalar);
|
||||
}
|
||||
|
||||
auto dumper = Dumper("example.yaml");
|
||||
auto dumper = dumper(new Appender!string);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!MyStruct(&representMyStruct);
|
||||
dumper.representer = representer;
|
||||
|
@ -207,7 +207,7 @@ final class Representer
|
|||
return representer.representScalar("!myclass.tag", scalar);
|
||||
}
|
||||
|
||||
auto dumper = Dumper("example.yaml");
|
||||
auto dumper = dumper(new Appender!string);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!MyClass(&representMyClass);
|
||||
dumper.representer = representer;
|
||||
|
@ -263,7 +263,7 @@ final class Representer
|
|||
return representer.representScalar("!mystruct.tag", scalar);
|
||||
}
|
||||
|
||||
auto dumper = Dumper("example.yaml");
|
||||
auto dumper = dumper(new Appender!string);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!MyStruct(&representMyStruct);
|
||||
dumper.representer = representer;
|
||||
|
@ -339,7 +339,7 @@ final class Representer
|
|||
CollectionStyle.Flow);
|
||||
}
|
||||
|
||||
auto dumper = Dumper("example.yaml");
|
||||
auto dumper = dumper(new Appender!string);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!MyStruct(&representMyStruct);
|
||||
dumper.representer = representer;
|
||||
|
@ -422,7 +422,7 @@ final class Representer
|
|||
return representer.representMapping("!mystruct.tag", pairs);
|
||||
}
|
||||
|
||||
auto dumper = Dumper("example.yaml");
|
||||
auto dumper = dumper(new Appender!string);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!MyStruct(&representMyStruct);
|
||||
dumper.representer = representer;
|
||||
|
@ -457,7 +457,7 @@ final class Representer
|
|||
}
|
||||
|
||||
//Represent a node, serializing with specified Serializer.
|
||||
void represent(ref Serializer serializer, ref Node node) @safe
|
||||
void represent(Range, CharType)(ref Serializer!(Range, CharType) serializer, ref Node node) @safe
|
||||
{
|
||||
auto data = representData(node);
|
||||
serializer.serialize(data);
|
||||
|
@ -677,15 +677,13 @@ Node representMyClass(ref Node node, Representer representer) @safe
|
|||
return representer.representScalar("!myclass.tag", scalar);
|
||||
}
|
||||
|
||||
import dyaml.stream;
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
foreach(r; [&representMyStruct,
|
||||
&representMyStructSeq,
|
||||
&representMyStructMap])
|
||||
{
|
||||
auto dumper = Dumper(new YMemoryStream());
|
||||
auto dumper = dumper(new Appender!string);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!MyStruct(r);
|
||||
dumper.representer = representer;
|
||||
|
@ -695,7 +693,7 @@ import dyaml.stream;
|
|||
|
||||
@safe unittest
|
||||
{
|
||||
auto dumper = Dumper(new YMemoryStream());
|
||||
auto dumper = dumper(new Appender!string);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!MyClass(&representMyClass);
|
||||
dumper.representer = representer;
|
||||
|
|
|
@ -16,7 +16,6 @@ import std.format;
|
|||
import std.typecons;
|
||||
|
||||
import dyaml.emitter;
|
||||
import dyaml.encoding;
|
||||
import dyaml.event;
|
||||
import dyaml.exception;
|
||||
import dyaml.node;
|
||||
|
@ -28,11 +27,11 @@ import dyaml.token;
|
|||
package:
|
||||
|
||||
///Serializes represented YAML nodes, generating events which are then emitted by Emitter.
|
||||
struct Serializer
|
||||
struct Serializer(Range, CharType)
|
||||
{
|
||||
private:
|
||||
///Emitter to emit events produced.
|
||||
Emitter* emitter_;
|
||||
Emitter!(Range, CharType)* emitter_;
|
||||
///Resolver used to determine which tags are automaticaly resolvable.
|
||||
Resolver resolver_;
|
||||
|
||||
|
@ -60,13 +59,12 @@ struct Serializer
|
|||
*
|
||||
* Params: emitter = Emitter to emit events produced.
|
||||
* resolver = Resolver used to determine which tags are automaticaly resolvable.
|
||||
* encoding = Character encoding to use.
|
||||
* explicitStart = Do all document starts have to be specified explicitly?
|
||||
* explicitEnd = Do all document ends have to be specified explicitly?
|
||||
* YAMLVersion = YAML version string.
|
||||
* tagDirectives = Tag directives to emit.
|
||||
*/
|
||||
this(Emitter* emitter, Resolver resolver, Encoding encoding,
|
||||
this(Emitter!(Range, CharType)* emitter, Resolver resolver,
|
||||
const Flag!"explicitStart" explicitStart,
|
||||
const Flag!"explicitEnd" explicitEnd, string YAMLVersion,
|
||||
TagDirective[] tagDirectives) @safe
|
||||
|
@ -78,7 +76,7 @@ struct Serializer
|
|||
YAMLVersion_ = YAMLVersion;
|
||||
tagDirectives_ = tagDirectives;
|
||||
|
||||
emitter_.emit(streamStartEvent(Mark(), Mark(), encoding));
|
||||
emitter_.emit(streamStartEvent(Mark(), Mark()));
|
||||
}
|
||||
|
||||
///Destroy the Serializer.
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
module dyaml.stream;
|
||||
|
||||
interface YStream
|
||||
{
|
||||
void writeExact(const void* buffer, size_t size);
|
||||
void writeExact(const void[] buffer) @safe;
|
||||
size_t write(const(ubyte)[] buffer) @safe;
|
||||
size_t write(const(char)[] str) @safe;
|
||||
void flush() @safe;
|
||||
@property bool writeable() @safe;
|
||||
}
|
||||
|
||||
class YMemoryStream : YStream
|
||||
{
|
||||
ubyte[] data;
|
||||
|
||||
void writeExact(const void* buffer, size_t size)
|
||||
{
|
||||
data ~= cast(ubyte[])buffer[0 .. size];
|
||||
}
|
||||
|
||||
void writeExact(const void[] buffer) @trusted
|
||||
{
|
||||
data ~= cast(ubyte[])buffer;
|
||||
}
|
||||
|
||||
size_t write(const(ubyte)[] buffer) @safe
|
||||
{
|
||||
data ~= buffer;
|
||||
return buffer.length;
|
||||
}
|
||||
|
||||
size_t write(const(char)[] str) @safe
|
||||
{
|
||||
return write(cast(const(ubyte)[])str);
|
||||
}
|
||||
|
||||
void flush() @safe {}
|
||||
|
||||
@property bool writeable() @safe { return true; }
|
||||
}
|
||||
|
||||
class YFile : YStream
|
||||
{
|
||||
static import std.stdio;
|
||||
std.stdio.File file;
|
||||
|
||||
this(string fn) @safe
|
||||
{
|
||||
this.file = std.stdio.File(fn, "w");
|
||||
}
|
||||
|
||||
this(std.stdio.File file) @safe
|
||||
{
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
import std.stdio : File;
|
||||
auto stream = new YFile(File.tmpfile);
|
||||
stream.write("Test writing to tmpFile through YFile stream\n");
|
||||
}
|
||||
|
||||
void writeExact(const void* buffer, size_t size)
|
||||
{
|
||||
this.file.rawWrite(cast(const) buffer[0 .. size]);
|
||||
}
|
||||
|
||||
void writeExact(const void[] buffer) @trusted
|
||||
{
|
||||
this.file.rawWrite(buffer);
|
||||
}
|
||||
|
||||
size_t write(const(ubyte)[] buffer) @trusted
|
||||
{
|
||||
this.file.rawWrite(buffer);
|
||||
return buffer.length;
|
||||
}
|
||||
|
||||
size_t write(const(char)[] str) @trusted
|
||||
{
|
||||
return write(cast(ubyte[])str);
|
||||
}
|
||||
|
||||
void flush() @safe
|
||||
{
|
||||
this.file.flush();
|
||||
}
|
||||
|
||||
@property bool writeable() @safe { return true; }
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
import dyaml.dumper, dyaml.loader, dyaml.node;
|
||||
import std.file : readText, remove;
|
||||
|
||||
string test = "Hello World : [Hello, World]\n" ~
|
||||
"Answer: 42";
|
||||
//Read the input.
|
||||
Node expected = Loader.fromString(test).load();
|
||||
assert(expected["Hello World"][0] == "Hello");
|
||||
assert(expected["Hello World"][1] == "World");
|
||||
assert(expected["Answer"].as!int == 42);
|
||||
|
||||
//Dump the loaded document to output.yaml.
|
||||
Dumper("output.yaml").dump(expected);
|
||||
|
||||
// Load the file and verify that it was saved correctly.
|
||||
Node actual = Loader.fromFile("output.yaml").load();
|
||||
assert(actual["Hello World"][0] == "Hello");
|
||||
assert(actual["Hello World"][1] == "World");
|
||||
assert(actual["Answer"].as!int == 42);
|
||||
assert(actual == expected);
|
||||
|
||||
// Clean up.
|
||||
remove("output.yaml");
|
||||
}
|
||||
|
||||
@safe unittest // #88, #89
|
||||
{
|
||||
import dyaml.dumper, dyaml.loader;
|
||||
import std.file : remove, read;
|
||||
|
||||
enum fn = "output.yaml";
|
||||
scope (exit) fn.remove;
|
||||
|
||||
auto dumper = Dumper(fn);
|
||||
dumper.YAMLVersion = null; // supress directive
|
||||
dumper.dump(Loader.fromString("Hello world").load);
|
||||
|
||||
assert (fn.read()[0..3] == "Hel");
|
||||
}
|
|
@ -15,7 +15,6 @@ import std.file;
|
|||
import std.range;
|
||||
import std.typecons;
|
||||
|
||||
import dyaml.stream;
|
||||
import dyaml.dumper;
|
||||
import dyaml.event;
|
||||
import dyaml.test.common;
|
||||
|
@ -83,17 +82,17 @@ void testEmitterOnData(string dataFilename, string canonicalFilename) @safe
|
|||
//Must exist due to Anchor, Tags reference counts.
|
||||
auto loader = Loader.fromFile(dataFilename);
|
||||
auto events = loader.parse();
|
||||
auto emitStream = new YMemoryStream;
|
||||
Dumper(emitStream).emit(events);
|
||||
auto emitStream = new Appender!string;
|
||||
dumper(emitStream).emit(events);
|
||||
|
||||
static if(verbose)
|
||||
{
|
||||
writeln(dataFilename);
|
||||
writeln("ORIGINAL:\n", readText(dataFilename));
|
||||
writeln("OUTPUT:\n", cast(char[])emitStream.data);
|
||||
writeln("OUTPUT:\n", emitStream.toString);
|
||||
}
|
||||
|
||||
auto loader2 = Loader.fromBuffer(emitStream.data);
|
||||
auto loader2 = Loader.fromString(emitStream.data);
|
||||
loader2.name = "TEST";
|
||||
loader2.constructor = new Constructor;
|
||||
loader2.resolver = new Resolver;
|
||||
|
@ -113,16 +112,16 @@ void testEmitterOnCanonical(string canonicalFilename) @safe
|
|||
auto events = loader.parse();
|
||||
foreach(canonical; [false, true])
|
||||
{
|
||||
auto emitStream = new YMemoryStream;
|
||||
auto dumper = Dumper(emitStream);
|
||||
auto emitStream = new Appender!string;
|
||||
auto dumper = dumper(emitStream);
|
||||
dumper.canonical = canonical;
|
||||
dumper.emit(events);
|
||||
static if(verbose)
|
||||
{
|
||||
writeln("OUTPUT (canonical=", canonical, "):\n",
|
||||
cast(char[])emitStream.data);
|
||||
emitStream.toString);
|
||||
}
|
||||
auto loader2 = Loader.fromBuffer(emitStream.data);
|
||||
auto loader2 = Loader.fromString(emitStream.data);
|
||||
loader2.name = "TEST";
|
||||
loader2.constructor = new Constructor;
|
||||
loader2.resolver = new Resolver;
|
||||
|
@ -172,15 +171,15 @@ void testEmitterStyles(string dataFilename, string canonicalFilename) @safe
|
|||
}
|
||||
styledEvents ~= event;
|
||||
}
|
||||
auto emitStream = new YMemoryStream;
|
||||
Dumper(emitStream).emit(styledEvents);
|
||||
auto emitStream = new Appender!string;
|
||||
dumper(emitStream).emit(styledEvents);
|
||||
static if(verbose)
|
||||
{
|
||||
writeln("OUTPUT (", filename, ", ", to!string(flowStyle), ", ",
|
||||
to!string(style), ")");
|
||||
writeln(cast(char[])emitStream.data);
|
||||
writeln(emitStream.toString);
|
||||
}
|
||||
auto loader2 = Loader.fromBuffer(emitStream.data);
|
||||
auto loader2 = Loader.fromString(emitStream.data);
|
||||
loader2.name = "TEST";
|
||||
loader2.constructor = new Constructor;
|
||||
loader2.resolver = new Resolver;
|
||||
|
|
|
@ -15,7 +15,6 @@ import std.file;
|
|||
import std.system;
|
||||
|
||||
import dyaml.test.common;
|
||||
import dyaml.stream;
|
||||
|
||||
/// Get an UTF-16 byte order mark.
|
||||
///
|
||||
|
|
|
@ -10,9 +10,12 @@ module dyaml.test.representer;
|
|||
version(unittest)
|
||||
{
|
||||
|
||||
import std.path;
|
||||
import std.array;
|
||||
import std.exception;
|
||||
import std.meta;
|
||||
import std.path;
|
||||
import std.typecons;
|
||||
import std.utf;
|
||||
|
||||
import dyaml.test.common;
|
||||
import dyaml.test.constructor;
|
||||
|
@ -30,9 +33,9 @@ void testRepresenterTypes(string codeFilename) @safe
|
|||
new Exception("Unimplemented representer test: " ~ baseName));
|
||||
|
||||
Node[] expectedNodes = expected[baseName];
|
||||
foreach(encoding; [Encoding.UTF_8, Encoding.UTF_16, Encoding.UTF_32])
|
||||
foreach(encoding; AliasSeq!(char, wchar, dchar))
|
||||
{
|
||||
ubyte[] output;
|
||||
immutable(encoding)[] output;
|
||||
Node[] readNodes;
|
||||
|
||||
scope(failure)
|
||||
|
@ -49,23 +52,20 @@ void testRepresenterTypes(string codeFilename) @safe
|
|||
}
|
||||
}
|
||||
|
||||
import dyaml.stream;
|
||||
|
||||
auto emitStream = new YMemoryStream;
|
||||
auto emitStream = new Appender!(immutable(encoding)[]);
|
||||
auto representer = new Representer;
|
||||
representer.addRepresenter!TestClass(&representClass);
|
||||
representer.addRepresenter!TestStruct(&representStruct);
|
||||
auto dumper = Dumper(emitStream);
|
||||
auto dumper = dumper(emitStream);
|
||||
dumper.representer = representer;
|
||||
dumper.encoding = encoding;
|
||||
dumper.dump(expectedNodes);
|
||||
dumper.dump!encoding(expectedNodes);
|
||||
|
||||
output = emitStream.data;
|
||||
auto constructor = new Constructor;
|
||||
constructor.addConstructorMapping("!tag1", &constructClass);
|
||||
constructor.addConstructorScalar("!tag2", &constructStruct);
|
||||
|
||||
auto loader = Loader.fromBuffer(emitStream.data);
|
||||
auto loader = Loader.fromString(emitStream.data.toUTF8);
|
||||
loader.name = "TEST";
|
||||
loader.constructor = constructor;
|
||||
readNodes = loader.loadAll();
|
||||
|
|
Loading…
Reference in a new issue