Implement range interface for Loader, remove old opApply interface (#196)
* Implement range interface for Loader, remove old opApply interface * remove dead Composer.getSingleNode * add Returns: lines to range primitives * a ddoc fixup
This commit is contained in:
parent
9c2ae02792
commit
1f5eb76996
|
@ -45,6 +45,7 @@ void extract(ref Node document) @safe
|
|||
|
||||
void main(string[] args) //@safe
|
||||
{
|
||||
import std.array : array;
|
||||
bool get = false;
|
||||
bool dump = false;
|
||||
bool reload = false;
|
||||
|
@ -113,7 +114,7 @@ void main(string[] args) //@safe
|
|||
|
||||
loader.resolver = resolver;
|
||||
loader.constructor = constructor;
|
||||
nodes = loader.loadAll();
|
||||
nodes = loader.array;
|
||||
}
|
||||
void runDumpBenchmark() @safe
|
||||
{
|
||||
|
|
|
@ -114,27 +114,6 @@ final class Composer
|
|||
return composeDocument();
|
||||
}
|
||||
|
||||
///Get single YAML document, throwing if there is more than one document.
|
||||
Node getSingleNode() @safe
|
||||
{
|
||||
assert(parser_.front.id != EventID.streamEnd,
|
||||
"Trying to get a node from Composer when there is no node to " ~
|
||||
"get. use checkNode() to determine if there is a node.");
|
||||
|
||||
Node document = composeDocument();
|
||||
|
||||
//Ensure that the stream contains no more documents.
|
||||
enforce(parser_.front.id == EventID.streamEnd,
|
||||
new ComposerException("Expected single document in the stream, " ~
|
||||
"but found another document.",
|
||||
parser_.front.startMark));
|
||||
|
||||
skipExpected(EventID.streamEnd);
|
||||
assert(parser_.empty, "Found event after stream end");
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void skipExpected(const EventID id) @safe
|
||||
|
|
|
@ -47,6 +47,10 @@ struct Loader
|
|||
string name_ = "<unknown>";
|
||||
// Are we done loading?
|
||||
bool done_;
|
||||
// Last node read from stream
|
||||
Node currentNode;
|
||||
// Has the range interface been initialized yet?
|
||||
bool rangeInitialized;
|
||||
|
||||
public:
|
||||
@disable this();
|
||||
|
@ -191,25 +195,12 @@ struct Loader
|
|||
* or on a YAML parsing error.
|
||||
*/
|
||||
Node load() @safe
|
||||
in
|
||||
{
|
||||
assert(!done_, "Loader: Trying to load YAML twice");
|
||||
}
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
lazyInitConstructorResolver();
|
||||
scope(exit) { done_ = true; }
|
||||
auto composer = new Composer(parser_, resolver_, constructor_);
|
||||
enforce(composer.checkNode(), new YAMLException("No YAML document to load"));
|
||||
return composer.getSingleNode();
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
throw new YAMLException("Unable to load YAML from %s : %s"
|
||||
.format(name_, e.msg), e.file, e.line);
|
||||
}
|
||||
enforce!YAMLException(!empty, "Zero documents in stream");
|
||||
auto output = front;
|
||||
popFront();
|
||||
enforce!YAMLException(empty, "More than one document in stream");
|
||||
return output;
|
||||
}
|
||||
|
||||
/** Load all YAML documents.
|
||||
|
@ -224,64 +215,64 @@ struct Loader
|
|||
*
|
||||
* Throws: YAMLException on a parsing error.
|
||||
*/
|
||||
Node[] loadAll() @safe
|
||||
deprecated("Redundant, loader is now an InputRange") Node[] loadAll() @safe
|
||||
{
|
||||
Node[] nodes;
|
||||
foreach(ref node; this)
|
||||
{
|
||||
nodes ~= node;
|
||||
import std.array: array;
|
||||
return this.array;
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/** Foreach over YAML documents.
|
||||
/** Implements the empty range primitive.
|
||||
*
|
||||
* Parses documents lazily, when they are needed.
|
||||
* If there's no more documents left in the stream, this will be true.
|
||||
*
|
||||
* Foreach over a Loader can only be used once; this is enforced by contract.
|
||||
*
|
||||
* Throws: YAMLException on a parsing error.
|
||||
* Returns: `true` if no more documents left, `false` otherwise.
|
||||
*/
|
||||
int opApply(int delegate(ref Node) @safe dg) @safe
|
||||
bool empty() @safe
|
||||
{
|
||||
return opApplyImpl(dg);
|
||||
// currentNode and done_ are both invalid until popFront is called once
|
||||
if (!rangeInitialized)
|
||||
{
|
||||
popFront();
|
||||
}
|
||||
/// Ditto
|
||||
int opApply(int delegate(ref Node) @system dg) @system
|
||||
{
|
||||
return opApplyImpl(dg);
|
||||
return done_;
|
||||
}
|
||||
|
||||
package:
|
||||
int opApplyImpl(T)(T dg)
|
||||
in
|
||||
/** Implements the popFront range primitive.
|
||||
*
|
||||
* Reads the next document from the stream, if possible.
|
||||
*/
|
||||
void popFront() @safe
|
||||
{
|
||||
assert(!done_, "Loader: Trying to load YAML twice");
|
||||
}
|
||||
do
|
||||
{
|
||||
scope(exit) { done_ = true; }
|
||||
try
|
||||
// Composer initialization is done here in case the constructor is
|
||||
// modified, which is a pretty common case.
|
||||
static Composer composer;
|
||||
if (!rangeInitialized)
|
||||
{
|
||||
lazyInitConstructorResolver();
|
||||
auto composer = new Composer(parser_, resolver_, constructor_);
|
||||
|
||||
int result;
|
||||
while(composer.checkNode())
|
||||
composer = new Composer(parser_, resolver_, constructor_);
|
||||
rangeInitialized = true;
|
||||
}
|
||||
assert(!done_, "Loader.popFront called on empty range");
|
||||
if (composer.checkNode())
|
||||
{
|
||||
auto node = composer.getNode();
|
||||
result = dg(node);
|
||||
if(result) { break; }
|
||||
currentNode = composer.getNode();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch(YAMLException e)
|
||||
else
|
||||
{
|
||||
throw new YAMLException("Unable to load YAML from %s : %s "
|
||||
.format(name_, e.msg), e.file, e.line);
|
||||
done_ = true;
|
||||
}
|
||||
}
|
||||
/** Implements the front range primitive.
|
||||
*
|
||||
* Returns: the current document as a Node.
|
||||
*/
|
||||
Node front() @safe
|
||||
{
|
||||
// currentNode and done_ are both invalid until popFront is called once
|
||||
if (!rangeInitialized)
|
||||
{
|
||||
popFront();
|
||||
}
|
||||
return currentNode;
|
||||
}
|
||||
// Scan and return all tokens. Used for debugging.
|
||||
Token[] scan() @safe
|
||||
{
|
||||
|
@ -353,6 +344,7 @@ struct Loader
|
|||
/// Load all YAML documents from a file:
|
||||
@safe unittest
|
||||
{
|
||||
import std.array : array;
|
||||
import std.file : write;
|
||||
write("example.yaml",
|
||||
"---\n"~
|
||||
|
@ -362,7 +354,7 @@ struct Loader
|
|||
"Hello world 2!\n"~
|
||||
"...\n"
|
||||
);
|
||||
auto nodes = Loader.fromFile("example.yaml").loadAll();
|
||||
auto nodes = Loader.fromFile("example.yaml").array;
|
||||
assert(nodes.length == 2);
|
||||
}
|
||||
/// Iterate over YAML documents in a file, lazily loading them:
|
||||
|
|
|
@ -34,8 +34,9 @@ void testParser(string dataFilename, string canonicalFilename) @safe
|
|||
/// canonicalFilename = Another file to load, in canonical YAML format.
|
||||
void testLoader(string dataFilename, string canonicalFilename) @safe
|
||||
{
|
||||
auto data = Loader.fromFile(dataFilename).loadAll();
|
||||
auto canonical = Loader.fromFile(canonicalFilename).loadAll();
|
||||
import std.array : array;
|
||||
auto data = Loader.fromFile(dataFilename).array;
|
||||
auto canonical = Loader.fromFile(canonicalFilename).array;
|
||||
|
||||
assert(data.length == canonical.length, "Unequal node count");
|
||||
foreach(n; 0 .. data.length)
|
||||
|
|
|
@ -20,8 +20,9 @@ import dyaml.test.common;
|
|||
/// Params: errorFilename = File name to read from.
|
||||
void testLoaderError(string errorFilename) @safe
|
||||
{
|
||||
import std.array : array;
|
||||
Node[] nodes;
|
||||
try { nodes = Loader.fromFile(errorFilename).loadAll(); }
|
||||
try { nodes = Loader.fromFile(errorFilename).array; }
|
||||
catch(YAMLException e)
|
||||
{
|
||||
printException(e);
|
||||
|
@ -35,9 +36,10 @@ void testLoaderError(string errorFilename) @safe
|
|||
/// Params: errorFilename = File name to read from.
|
||||
void testLoaderErrorString(string errorFilename) @safe
|
||||
{
|
||||
import std.array : array;
|
||||
try
|
||||
{
|
||||
auto nodes = Loader.fromFile(errorFilename).loadAll();
|
||||
auto nodes = Loader.fromFile(errorFilename).array;
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
|
@ -52,7 +54,8 @@ void testLoaderErrorString(string errorFilename) @safe
|
|||
/// Params: errorFilename = File name to read from.
|
||||
void testLoaderErrorFilename(string errorFilename) @safe
|
||||
{
|
||||
try { auto nodes = Loader.fromFile(errorFilename).loadAll(); }
|
||||
import std.array : array;
|
||||
try { auto nodes = Loader.fromFile(errorFilename).array; }
|
||||
catch(YAMLException e)
|
||||
{
|
||||
printException(e);
|
||||
|
|
|
@ -68,7 +68,7 @@ void testRepresenterTypes(string codeFilename) @safe
|
|||
auto loader = Loader.fromString(emitStream.data.toUTF8);
|
||||
loader.name = "TEST";
|
||||
loader.constructor = constructor;
|
||||
readNodes = loader.loadAll();
|
||||
readNodes = loader.array;
|
||||
|
||||
assert(expectedNodes.length == readNodes.length);
|
||||
foreach(n; 0 .. expectedNodes.length)
|
||||
|
|
Loading…
Reference in a new issue