Implemented the resolver unittest.
Changed Loader API to be in line with Dumper, and updated examples, tutorials and docs.
This commit is contained in:
parent
934df763ad
commit
34b11405d4
|
@ -9,7 +9,7 @@ are caused by difficulty of implementation of some features, such as multiple
|
||||||
Unicode encodings within single stream, and some by unnecessary restrictions or
|
Unicode encodings within single stream, and some by unnecessary restrictions or
|
||||||
ambiguities in the specification.
|
ambiguities in the specification.
|
||||||
|
|
||||||
Still, D:YAML tries to be as close to the specification as possible. D:YAML should
|
Still, D:YAML tries to be as close to the specification as possible. It should
|
||||||
never load documents with different meaning than according to the specification,
|
never load documents with different meaning than according to the specification,
|
||||||
and documents that fail to load should be very rare (for instance, very few
|
and documents that fail to load should be very rare (for instance, very few
|
||||||
files use multiple Unicode encodings).
|
files use multiple Unicode encodings).
|
||||||
|
@ -21,10 +21,6 @@ List of known differences:
|
||||||
|
|
||||||
Differences that can cause valid YAML documents not to load:
|
Differences that can cause valid YAML documents not to load:
|
||||||
|
|
||||||
* At the moment, all mappings in the internal representation are ordered,
|
|
||||||
and a comparison for equality between equal mappings with differing order
|
|
||||||
will return false. This will be fixed once Phobos has a usable map type or
|
|
||||||
D associative arrays work with variants.
|
|
||||||
* No support for byte order marks and multiple Unicode encodings in a stream.
|
* No support for byte order marks and multiple Unicode encodings in a stream.
|
||||||
* Plain scalars in flow context cannot contain ``,``, ``:`` and ``?``.
|
* Plain scalars in flow context cannot contain ``,``, ``:`` and ``?``.
|
||||||
This might change with ``:`` in the future.
|
This might change with ``:`` in the future.
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
Custom YAML data types
|
Custom YAML data types
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Often you will want to serialize complex data types such as classes. You can use
|
Often you might want to serialize complex data types such as classes. You can
|
||||||
functions to process nodes; e.g. a mapping containing class data members indexed
|
use functions to process nodes such as a mapping containing class data members
|
||||||
by name. Alternatively, YAML supports custom data types using identifiers called
|
indexed by name. Alternatively, YAML supports custom data types using
|
||||||
*tags*. That is the topic of this tutorial.
|
identifiers called *tags*. That is the topic of this tutorial.
|
||||||
|
|
||||||
Each YAML node has a tag specifying its type. For instance: strings use the tag
|
Each YAML node has a tag specifying its type. For instance: strings use the tag
|
||||||
``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved*
|
``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved*
|
||||||
|
@ -19,9 +19,9 @@ Constructor
|
||||||
|
|
||||||
D:YAML uses the *Constructor* class to process each node to hold data type
|
D:YAML uses the *Constructor* class to process each node to hold data type
|
||||||
corresponding to its tag. *Constructor* stores a function for each supported
|
corresponding to its tag. *Constructor* stores a function for each supported
|
||||||
tag to process it. These functions can be supplied by the user using the
|
tag to process it. These functions are supplied by the user using the
|
||||||
*addConstructor()* method. *Constructor* is then passed to *Loader*, which will
|
*addConstructor()* method. *Constructor* is then passed to *Loader*, which
|
||||||
parse YAML input.
|
parses YAML input.
|
||||||
|
|
||||||
We will implement support for an RGB color type. It is implemented as the
|
We will implement support for an RGB color type. It is implemented as the
|
||||||
following struct:
|
following struct:
|
||||||
|
@ -111,7 +111,7 @@ RRGGBB, or from a mapping, where we use the following format:
|
||||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||||
}
|
}
|
||||||
|
|
||||||
Next, we need some YAML code using our new tag. Create a file called input.yaml
|
Next, we need some YAML data using our new tag. Create a file called input.yaml
|
||||||
with the following contents:
|
with the following contents:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
@ -144,9 +144,10 @@ Finally, the code to put it all together:
|
||||||
constructor.addConstructor("!color", &constructColorScalar);
|
constructor.addConstructor("!color", &constructColorScalar);
|
||||||
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
||||||
|
|
||||||
auto loader = new Loader("input.yaml", constructor, new Resolver);
|
auto loader = Loader("input.yaml");
|
||||||
|
loader.constructor = constructor;
|
||||||
|
|
||||||
auto root = loader.loadSingleDocument();
|
auto root = loader.load();
|
||||||
|
|
||||||
if(root["scalar-red"].get!Color == red &&
|
if(root["scalar-red"].get!Color == red &&
|
||||||
root["mapping-red"].get!Color == red &&
|
root["mapping-red"].get!Color == red &&
|
||||||
|
@ -166,10 +167,9 @@ Finally, the code to put it all together:
|
||||||
}
|
}
|
||||||
|
|
||||||
First, we create a *Constructor* and pass functions to handle the ``!color``
|
First, we create a *Constructor* and pass functions to handle the ``!color``
|
||||||
and ``!color-mapping`` tag. We construct a *Loader* using the *Constructor*.
|
and ``!color-mapping`` tag. We construct a *Loader*m and pass the *Constructor*
|
||||||
We also need a *Resolver*, but for now we just default-construct it. We then
|
to it. We then load the YAML document, and finally, read the colors using
|
||||||
load the YAML document, and finally, read the colors using *get()* method to
|
*get()* method to test if they were loaded as expected.
|
||||||
test if they were loaded as expected.
|
|
||||||
|
|
||||||
You can find the source code for what we've done so far in the
|
You can find the source code for what we've done so far in the
|
||||||
``examples/constructor`` directory in the D:YAML package.
|
``examples/constructor`` directory in the D:YAML package.
|
||||||
|
@ -180,8 +180,8 @@ Resolver
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Specifying tag for every color value can be tedious. D:YAML can implicitly
|
Specifying tag for every color value can be tedious. D:YAML can implicitly
|
||||||
resolve tag of a scalar using a regular expression. This is how default types,
|
resolve scalar tags using regular expressions. This is how default types such as
|
||||||
e.g. int, are resolved. We will use the *Resolver* class to add implicit tag
|
int are resolved. We will use the *Resolver* class to add implicit tag
|
||||||
resolution for the Color data type (in its scalar form).
|
resolution for the Color data type (in its scalar form).
|
||||||
|
|
||||||
We use the *addImplicitResolver* method of *Resolver*, passing the tag, regular
|
We use the *addImplicitResolver* method of *Resolver*, passing the tag, regular
|
||||||
|
@ -203,11 +203,14 @@ Add this to your code to add implicit resolution of ``!color``.
|
||||||
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}",
|
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}",
|
||||||
"0123456789abcdefABCDEF"));
|
"0123456789abcdefABCDEF"));
|
||||||
|
|
||||||
auto loader = new Loader("input.yaml", constructor, resolver);
|
auto loader = Loader("input.yaml");
|
||||||
|
|
||||||
|
loader.constructor = constructor;
|
||||||
|
loader.resolver = resolver;
|
||||||
|
|
||||||
//code from the previous example...
|
//code from the previous example...
|
||||||
|
|
||||||
Now, change contents of input.dyaml to this:
|
Now, change contents of input.yaml to this:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,8 @@ Download the version of DMD for your operating system and install it.
|
||||||
.. note::
|
.. note::
|
||||||
Other D compilers exist, such as
|
Other D compilers exist, such as
|
||||||
`GDC <http://bitbucket.org/goshawk/gdc/wiki/Home>`_ and
|
`GDC <http://bitbucket.org/goshawk/gdc/wiki/Home>`_ and
|
||||||
`LDC <http://www.dsource.org/projects/ldc/>`_.
|
`LDC <http://www.dsource.org/projects/ldc/>`_. Setting up with either one of
|
||||||
Setting up with either one of them should be similar to DMD,
|
them should be similar to DMD, but they are not yet as stable as DMD.
|
||||||
however, at the moment they are not as up to date as DMD.
|
|
||||||
|
|
||||||
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Download and compile D:YAML
|
Download and compile D:YAML
|
||||||
|
@ -84,7 +82,7 @@ into the file:
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
yaml.Node root = yaml.load("input.yaml");
|
Node root = Loader("input.yaml").load();
|
||||||
foreach(string word; root["Hello World"])
|
foreach(string word; root["Hello World"])
|
||||||
{
|
{
|
||||||
writeln(word);
|
writeln(word);
|
||||||
|
@ -100,22 +98,23 @@ Explanation of the code
|
||||||
First, we import the *yaml* module. This is the only module you need to import
|
First, we import the *yaml* module. This is the only module you need to import
|
||||||
to use D:YAML - it automatically imports all needed modules.
|
to use D:YAML - it automatically imports all needed modules.
|
||||||
|
|
||||||
Next we load the file using the *yaml.load()* function - this loads the file as
|
Next we load the file using the *Loader.load()* method. *Loader* is the struct
|
||||||
|
used for parsing YAML documents, and *load()* is a method that loads the file as
|
||||||
**one** YAML document and throws *YAMLException*, D:YAML exception type, if the
|
**one** YAML document and throws *YAMLException*, D:YAML exception type, if the
|
||||||
file could not be parsed or does not contain exactly one document. Note that we
|
file could not be parsed or does not contain exactly one document. Note that we
|
||||||
don't do any error checking here in order to keep the example as simple as
|
don't do any error checking here in order to keep the example as simple as
|
||||||
possible.
|
possible.
|
||||||
|
|
||||||
*yaml.Node* represents a node in a YAML document. It can be a sequence (array),
|
*Node* represents a node in a YAML document. It can be a sequence (array),
|
||||||
mapping (associative array) or a scalar (value). Here the root node is a
|
mapping (associative array) or a scalar (value). Here the root node is a
|
||||||
mapping, and we use the index operator to get subnodes with keys "Hello World"
|
mapping, and we use the index operator to get subnodes with keys "Hello World"
|
||||||
and "Answer". We iterate over the first, as it is a sequence, and use the
|
and "Answer". We iterate over the first, as it is a sequence, and use the
|
||||||
*yaml.Node.get()* method on the second to get its value as an integer.
|
*Node.get()* method on the second to get its value as an integer.
|
||||||
|
|
||||||
You can iterate over a mapping or sequence as if it was an associative or normal
|
You can iterate over a mapping or sequence as if it was an associative or normal
|
||||||
array. If you try to iterate over a scalar, it will throw a *YAMLException*.
|
array. If you try to iterate over a scalar, it will throw a *YAMLException*.
|
||||||
|
|
||||||
You can iterate over subnodes using yaml.Node as the iterated type, or specify
|
You can iterate over subnodes using *Node* as the iterated type, or specify
|
||||||
the type subnodes are expected to have. D:YAML will automatically convert
|
the type subnodes are expected to have. D:YAML will automatically convert
|
||||||
iterated subnodes to that type if possible. Here we specify the *string* type,
|
iterated subnodes to that type if possible. Here we specify the *string* type,
|
||||||
so we iterate over the "Hello World" sequence as an array of strings. If it is
|
so we iterate over the "Hello World" sequence as an array of strings. If it is
|
||||||
|
@ -123,8 +122,8 @@ not possible to convert to iterated type, a *YAMLException* is thrown. For
|
||||||
instance, if we specified *int* here, we would get an error, as "Hello"
|
instance, if we specified *int* here, we would get an error, as "Hello"
|
||||||
cannot be converted to an integer.
|
cannot be converted to an integer.
|
||||||
|
|
||||||
The *yaml.Node.get()* method is used to get value of a scalar node as specified
|
The *Node.get()* method is used to get value of a scalar node, allowing to
|
||||||
type. D:YAML will try to return the scalar as specified type, converting if
|
specify type. D:YAML will try to return the scalar as this type, converting if
|
||||||
needed, throwing *YAMLException* if not possible.
|
needed, throwing *YAMLException* if not possible.
|
||||||
|
|
||||||
|
|
||||||
|
@ -135,16 +134,15 @@ Compiling
|
||||||
To compile your project, you must give DMD the directories containing import
|
To compile your project, you must give DMD the directories containing import
|
||||||
modules and the library. You also need to tell it to link with D:YAML. The import
|
modules and the library. You also need to tell it to link with D:YAML. The import
|
||||||
directory should be the D:YAML package directory. You can specify it using the
|
directory should be the D:YAML package directory. You can specify it using the
|
||||||
``-I`` option of DMD. The library directory should point to where you put the
|
``-I`` option of DMD. The library directory should be where you put the compiled
|
||||||
compiled D:YAML library. On Unix/Linux you can specify it using the ``-L-L``
|
D:YAML library. On Unix/Linux you can specify it using the ``-L-L`` option, and
|
||||||
option, and link with D:YAML using the ``-L-l`` option. On Windows, the import
|
link with D:YAML using the ``-L-l`` option. On Windows, the import directory is
|
||||||
directory is used as the library directory. To link with the library on Windows,
|
used as the library directory. To link with the library on Windows, just add the
|
||||||
just add the path to it relative to the current directory.
|
path to it relative to the current directory.
|
||||||
|
|
||||||
For example, if you extracted D:YAML to ``/home/xxx/dyaml`` and compiled it in
|
For example, if you extracted and compiled D:YAML in ``/home/xxx/dyaml``, your
|
||||||
that directory, your project is in ``/home/xxx/dyaml-project``, and you are
|
project is in ``/home/xxx/dyaml-project``, and you are currently in that
|
||||||
currently in that directory, you can compile the project with the following
|
directory, you can compile the project with the following command on Unix/Linux::
|
||||||
command on Unix/Linux::
|
|
||||||
|
|
||||||
dmd -I../dyaml -L-L../dyaml -L-ldyaml main.d
|
dmd -I../dyaml -L-L../dyaml -L-ldyaml main.d
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,14 @@ which this article is based on,
|
||||||
`Chapter 2 of the YAML specification <http://yaml.org/spec/1.1/#id857168>`_
|
`Chapter 2 of the YAML specification <http://yaml.org/spec/1.1/#id857168>`_
|
||||||
or the `Wikipedia page <http://en.wikipedia.org/wiki/YAML>`_.
|
or the `Wikipedia page <http://en.wikipedia.org/wiki/YAML>`_.
|
||||||
|
|
||||||
YAML is a data serialization format designed to be as human readable as
|
YAML is a data serialization format designed for human readability. YAML is a
|
||||||
possible. YAML is a recursive acronym for "YAML Ain't Markup Language".
|
recursive acronym for "YAML Ain't Markup Language".
|
||||||
|
|
||||||
YAML is similar to JSON, and in fact, JSON is a subset of YAML 1.2; but YAML has
|
YAML is similar to JSON, and in fact, JSON is a subset of YAML 1.2; but YAML has
|
||||||
some more advanced features and is easier to read. However, YAML is also more
|
some more advanced features and is easier to read. However, it is also more
|
||||||
difficult to parse (and probably somewhat slower). Data is stored in mappings
|
difficult to parse (and probably somewhat slower). Data is stored in mappings
|
||||||
(associative arrays), sequences (lists) and scalars (single values). Data
|
(associative arrays), sequences (lists) and scalars (single values). Data
|
||||||
structure hierarchy either depends on indentation (block context, similar to
|
structure hierarchy depends either on indentation (block context, similar to
|
||||||
Python code), or nesting of brackets and braces (flow context, similar to JSON).
|
Python code), or nesting of brackets and braces (flow context, similar to JSON).
|
||||||
YAML comments begin with ``#`` and continue until the end of line.
|
YAML comments begin with ``#`` and continue until the end of line.
|
||||||
|
|
||||||
|
@ -25,8 +25,7 @@ Documents
|
||||||
---------
|
---------
|
||||||
|
|
||||||
A YAML stream consists of one or more documents starting with ``---`` and
|
A YAML stream consists of one or more documents starting with ``---`` and
|
||||||
optionally ending with ``...`` . If there is only one document, ``---`` can be
|
optionally ending with ``...`` . ``---`` can be left out for the first document.
|
||||||
left out.
|
|
||||||
|
|
||||||
Single document with no explicit start or end:
|
Single document with no explicit start or end:
|
||||||
|
|
||||||
|
|
|
@ -40,14 +40,14 @@ import dyaml.tagdirectives;
|
||||||
* Write to a file:
|
* Write to a file:
|
||||||
* --------------------
|
* --------------------
|
||||||
* auto node = Node([1, 2, 3, 4, 5]);
|
* auto node = Node([1, 2, 3, 4, 5]);
|
||||||
* Dumper("file.txt").dump(node);
|
* Dumper("file.yaml").dump(node);
|
||||||
* --------------------
|
* --------------------
|
||||||
*
|
*
|
||||||
* Write multiple YAML documents to a file:
|
* Write multiple YAML documents to a file:
|
||||||
* --------------------
|
* --------------------
|
||||||
* auto node1 = Node([1, 2, 3, 4, 5]);
|
* auto node1 = Node([1, 2, 3, 4, 5]);
|
||||||
* auto node2 = Node("This document contains only one string");
|
* auto node2 = Node("This document contains only one string");
|
||||||
* Dumper("file.txt").dump(node1, node2);
|
* Dumper("file.yaml").dump(node1, node2);
|
||||||
* --------------------
|
* --------------------
|
||||||
*
|
*
|
||||||
* Write to memory:
|
* Write to memory:
|
||||||
|
@ -65,8 +65,8 @@ import dyaml.tagdirectives;
|
||||||
* auto resolver = new Resolver();
|
* auto resolver = new Resolver();
|
||||||
*
|
*
|
||||||
* //Add representer functions / resolver expressions here...
|
* //Add representer functions / resolver expressions here...
|
||||||
* --------------------
|
*
|
||||||
* auto dumper = Dumper("file.txt");
|
* auto dumper = Dumper("file.yaml");
|
||||||
* dumper.representer = representer;
|
* dumper.representer = representer;
|
||||||
* dumper.resolver = resolver;
|
* dumper.resolver = resolver;
|
||||||
* dumper.dump(node);
|
* dumper.dump(node);
|
||||||
|
@ -259,7 +259,7 @@ struct Dumper
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* --------------------
|
* --------------------
|
||||||
* Dumper dumper = Dumper("file.txt");
|
* Dumper dumper = Dumper("file.yaml");
|
||||||
* //This will emit tags starting with "tag:long.org,2011"
|
* //This will emit tags starting with "tag:long.org,2011"
|
||||||
* //with a "!short!" prefix instead.
|
* //with a "!short!" prefix instead.
|
||||||
* dumper.tags("short", "tag:long.org,2011:");
|
* dumper.tags("short", "tag:long.org,2011:");
|
||||||
|
|
352
dyaml/loader.d
352
dyaml/loader.d
|
@ -28,43 +28,36 @@ import dyaml.token;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load single YAML document from a file.
|
* Loads YAML documents from files or streams.
|
||||||
*
|
*
|
||||||
* If there is no or more than one YAML document in the file, this will throw.
|
* User specified Constructor and/or Resolver can be used to support new
|
||||||
* Use $(LREF loadAll) for such files.
|
* tags / data types.
|
||||||
*
|
|
||||||
* Params: filename = Name of the file to _load from.
|
|
||||||
*
|
|
||||||
* Returns: Root node of the document.
|
|
||||||
*
|
|
||||||
* Throws: YAMLException if there wasn't exactly one document in the file,
|
|
||||||
* the file could not be opened or on a YAML parsing error.
|
|
||||||
*/
|
|
||||||
Node load(in string filename)
|
|
||||||
{
|
|
||||||
auto loader = Loader(filename);
|
|
||||||
return loader.loadSingleDocument();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load single YAML document from a stream.
|
|
||||||
*
|
|
||||||
* You can use this to e.g _load YAML from memory.
|
|
||||||
*
|
|
||||||
* If there is no or more than one YAML document in the stream, this will throw.
|
|
||||||
* Use $(LREF loadAll) for such files.
|
|
||||||
*
|
|
||||||
* Params: input = Stream to read from. Must be readable.
|
|
||||||
* name = Name of the stream, used in error messages.
|
|
||||||
*
|
|
||||||
* Returns: Root node of the document.
|
|
||||||
*
|
|
||||||
* Throws: YAMLException if there wasn't exactly one document in the stream,
|
|
||||||
* the stream could not be read from or on a YAML parsing error.
|
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
* Loading YAML from memory:
|
* Load single YAML document from a file:
|
||||||
|
* --------------------
|
||||||
|
* auto rootNode = Loader("file.yaml").load();
|
||||||
|
* ...
|
||||||
|
* --------------------
|
||||||
|
*
|
||||||
|
* Load all YAML documents from a file:
|
||||||
|
* --------------------
|
||||||
|
* auto nodes = Loader("file.yaml").loadAll();
|
||||||
|
* ...
|
||||||
|
* --------------------
|
||||||
|
*
|
||||||
|
* Iterate over YAML documents in a file, lazily loading them:
|
||||||
|
* --------------------
|
||||||
|
* auto loader = Loader("file.yaml");
|
||||||
|
*
|
||||||
|
* foreach(ref node; loader)
|
||||||
|
* {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* --------------------
|
||||||
|
*
|
||||||
|
* Load YAML from memory:
|
||||||
* --------------------
|
* --------------------
|
||||||
* import std.stream;
|
* import std.stream;
|
||||||
* import std.stdio;
|
* import std.stdio;
|
||||||
|
@ -73,74 +66,27 @@ Node load(in string filename)
|
||||||
* "green: '#00ff00'\n"
|
* "green: '#00ff00'\n"
|
||||||
* "blue: '#0000ff'";
|
* "blue: '#0000ff'";
|
||||||
*
|
*
|
||||||
* auto colors = yaml.load(new MemoryStream(cast(char[])yaml_input));
|
* auto colors = Loader(new MemoryStream(cast(char[])yaml_input)).load();
|
||||||
*
|
*
|
||||||
* foreach(string color, string value; colors)
|
* foreach(string color, string value; colors)
|
||||||
* {
|
* {
|
||||||
* writeln(color, " is ", value, " in HTML/CSS");
|
* writeln(color, " is ", value, " in HTML/CSS");
|
||||||
* }
|
* }
|
||||||
* --------------------
|
* --------------------
|
||||||
|
*
|
||||||
|
* Use a custom constructor/resolver to support custom data types and/or implicit tags:
|
||||||
|
* --------------------
|
||||||
|
* auto constructor = new Constructor();
|
||||||
|
* auto resolver = new Resolver();
|
||||||
|
*
|
||||||
|
* //Add constructor functions / resolver expressions here...
|
||||||
|
*
|
||||||
|
* auto loader = Loader("file.yaml");
|
||||||
|
* loader.constructor = constructor;
|
||||||
|
* loader.resolver = resolver;
|
||||||
|
* auto rootNode = loader.load(node);
|
||||||
|
* --------------------
|
||||||
*/
|
*/
|
||||||
Node load(Stream input, in string name = "<unknown>")
|
|
||||||
{
|
|
||||||
auto loader = Loader(input, name, new Constructor, new Resolver);
|
|
||||||
return loader.loadSingleDocument();
|
|
||||||
}
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
import std.stream;
|
|
||||||
import std.stdio;
|
|
||||||
|
|
||||||
string yaml_input = "red: '#ff0000'\n"
|
|
||||||
"green: '#00ff00'\n"
|
|
||||||
"blue: '#0000ff'";
|
|
||||||
|
|
||||||
auto colors = load(new MemoryStream(cast(char[])yaml_input));
|
|
||||||
|
|
||||||
foreach(string color, string value; colors)
|
|
||||||
{
|
|
||||||
writeln(color, " is ", value, " in HTML/CSS");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load all YAML documents from a file.
|
|
||||||
*
|
|
||||||
* Params: filename = Name of the file to load from.
|
|
||||||
*
|
|
||||||
* Returns: Array of root nodes of documents in the stream.
|
|
||||||
* If the stream is empty, empty array will be returned.
|
|
||||||
*
|
|
||||||
* Throws: YAMLException if the file could not be opened or on a YAML parsing error.
|
|
||||||
*/
|
|
||||||
Node[] loadAll(in string filename)
|
|
||||||
{
|
|
||||||
auto loader = Loader(filename);
|
|
||||||
Node[] result;
|
|
||||||
foreach(ref node; loader){result ~= node;}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load all YAML documents from a stream.
|
|
||||||
*
|
|
||||||
* Params: input = Stream to read from. Must be readable.
|
|
||||||
* name = Name of the stream, used in error messages.
|
|
||||||
*
|
|
||||||
* Returns: Array of root nodes of documents in the file.
|
|
||||||
* If the file is empty, empty array will be returned.
|
|
||||||
*
|
|
||||||
* Throws: YAMLException if the stream could not be read from or on a YAML parsing error.
|
|
||||||
*/
|
|
||||||
Node[] loadAll(Stream input, in string name = "<unknown>")
|
|
||||||
{
|
|
||||||
auto loader = Loader(input, name, new Constructor, new Resolver);
|
|
||||||
Node[] result;
|
|
||||||
foreach(ref node; loader){result ~= node;}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
///Loads YAML documents from files or streams.
|
|
||||||
struct Loader
|
struct Loader
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -154,12 +100,8 @@ struct Loader
|
||||||
Resolver resolver_;
|
Resolver resolver_;
|
||||||
///Constructs YAML data types.
|
///Constructs YAML data types.
|
||||||
Constructor constructor_;
|
Constructor constructor_;
|
||||||
///Composes YAML nodes.
|
|
||||||
Composer composer_;
|
|
||||||
///Name of the input file or stream, used in error messages.
|
///Name of the input file or stream, used in error messages.
|
||||||
string name_;
|
string name_ = "<unknown>";
|
||||||
///Input file stream, if the stream is created by Loader itself.
|
|
||||||
File file_ = null;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -171,60 +113,33 @@ struct Loader
|
||||||
*/
|
*/
|
||||||
this(in string filename)
|
this(in string filename)
|
||||||
{
|
{
|
||||||
try{file_ = new File(filename);}
|
try
|
||||||
|
{
|
||||||
|
name = filename;
|
||||||
|
this(new File(filename));
|
||||||
|
}
|
||||||
catch(StreamException e)
|
catch(StreamException e)
|
||||||
{
|
{
|
||||||
throw new YAMLException("Unable to load YAML file " ~ filename ~ " : " ~ e.msg);
|
throw new YAMLException("Unable to load YAML file " ~ filename ~ " : " ~ e.msg);
|
||||||
}
|
}
|
||||||
this(file_, filename, new Constructor, new Resolver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a Loader to load YAML from a file, with provided _constructor and _resolver.
|
* Construct a Loader to load YAML from a stream.
|
||||||
*
|
*
|
||||||
* Constructor and _resolver can be used to implement custom data types in YAML.
|
* Params: stream = Stream to read from. Must be readable.
|
||||||
*
|
|
||||||
* Params: filename = Name of the file to load from.
|
|
||||||
* constructor = Constructor to use.
|
|
||||||
* resolver = Resolver to use.
|
|
||||||
*
|
|
||||||
* Throws: YAMLException if the file could not be opened or read from.
|
|
||||||
*/
|
|
||||||
this(in string filename, Constructor constructor, Resolver resolver)
|
|
||||||
{
|
|
||||||
try{file_ = new File(filename);}
|
|
||||||
catch(StreamException e)
|
|
||||||
{
|
|
||||||
throw new YAMLException("Unable to load YAML file " ~ filename ~ " : " ~ e.msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
this(file_, filename, constructor, resolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a Loader to load YAML from a stream with provided _constructor and _resolver.
|
|
||||||
*
|
|
||||||
* Stream can be used to load YAML from memory and other sources.
|
|
||||||
* Constructor and _resolver can be used to implement custom data types in YAML.
|
|
||||||
*
|
|
||||||
* Params: input = Stream to read from. Must be readable.
|
|
||||||
* name = Name of the stream. Used in error messages.
|
|
||||||
* constructor = Constructor to use.
|
|
||||||
* resolver = Resolver to use.
|
|
||||||
*
|
*
|
||||||
* Throws: YAMLException if the stream could not be read from.
|
* Throws: YAMLException if the stream could not be read from.
|
||||||
*/
|
*/
|
||||||
this(Stream input, in string name, Constructor constructor, Resolver resolver)
|
this(Stream stream)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
reader_ = new Reader(input);
|
reader_ = new Reader(stream);
|
||||||
scanner_ = new Scanner(reader_);
|
scanner_ = new Scanner(reader_);
|
||||||
parser_ = new Parser(scanner_);
|
parser_ = new Parser(scanner_);
|
||||||
resolver_ = resolver;
|
resolver_ = new Resolver;
|
||||||
constructor_ = constructor;
|
constructor_ = new Constructor;
|
||||||
composer_ = new Composer(parser_, resolver_, constructor_);
|
|
||||||
name_ = name;
|
|
||||||
Anchor.addReference();
|
Anchor.addReference();
|
||||||
TagDirectives.addReference();
|
TagDirectives.addReference();
|
||||||
}
|
}
|
||||||
|
@ -235,58 +150,6 @@ struct Loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load single YAML document.
|
|
||||||
*
|
|
||||||
* If no or more than one YAML document is found, this will throw a YAMLException.
|
|
||||||
*
|
|
||||||
* Returns: Root node of the document.
|
|
||||||
*
|
|
||||||
* Throws: YAMLException if there wasn't exactly one document
|
|
||||||
* or on a YAML parsing error.
|
|
||||||
*/
|
|
||||||
Node loadSingleDocument()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
enforce(composer_.checkNode(), new YAMLException("No YAML document to load"));
|
|
||||||
return composer_.getSingleNode();
|
|
||||||
}
|
|
||||||
catch(YAMLException e)
|
|
||||||
{
|
|
||||||
e.name = name_;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Foreach over YAML documents.
|
|
||||||
*
|
|
||||||
* Parses documents lazily, as they are needed.
|
|
||||||
*
|
|
||||||
* Throws: YAMLException on a parsing error.
|
|
||||||
*/
|
|
||||||
int opApply(int delegate(ref Node) dg)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
while(composer_.checkNode())
|
|
||||||
{
|
|
||||||
auto node = composer_.getNode();
|
|
||||||
result = dg(node);
|
|
||||||
if(result){break;}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch(YAMLException e)
|
|
||||||
{
|
|
||||||
e.name = name_;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///Destroy the Loader.
|
///Destroy the Loader.
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
|
@ -295,9 +158,97 @@ struct Loader
|
||||||
clear(reader_);
|
clear(reader_);
|
||||||
clear(scanner_);
|
clear(scanner_);
|
||||||
clear(parser_);
|
clear(parser_);
|
||||||
clear(composer_);
|
}
|
||||||
//Can't clear constructor, resolver: they might be supplied by the user.
|
|
||||||
if(file_ !is null){file_.close();}
|
///Set stream name. Used in debugging messages.
|
||||||
|
@property void name(string name)
|
||||||
|
{
|
||||||
|
name_ = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Set Resolver to use.
|
||||||
|
@property void resolver(Resolver resolver)
|
||||||
|
{
|
||||||
|
resolver_ = resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Set Constructor to use.
|
||||||
|
@property void constructor(Constructor constructor)
|
||||||
|
{
|
||||||
|
constructor_ = constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load single YAML document.
|
||||||
|
*
|
||||||
|
* If no or more than one YAML document is found, this will throw a YAMLException.
|
||||||
|
*
|
||||||
|
* Returns: Root node of the document.
|
||||||
|
*
|
||||||
|
* Throws: YAMLException if there wasn't exactly one document
|
||||||
|
* or on a YAML parsing error.
|
||||||
|
*/
|
||||||
|
Node load()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto composer = new Composer(parser_, resolver_, constructor_);
|
||||||
|
enforce(composer.checkNode(), new YAMLException("No YAML document to load"));
|
||||||
|
return composer.getSingleNode();
|
||||||
|
}
|
||||||
|
catch(YAMLException e)
|
||||||
|
{
|
||||||
|
e.name = name_;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all YAML documents.
|
||||||
|
*
|
||||||
|
* Returns: Array of root nodes of all documents in the file/stream.
|
||||||
|
*
|
||||||
|
* Throws: YAMLException if there wasn't exactly one document
|
||||||
|
* or on a YAML parsing error.
|
||||||
|
*/
|
||||||
|
Node[] loadAll()
|
||||||
|
{
|
||||||
|
Node[] nodes;
|
||||||
|
foreach(ref node; this)
|
||||||
|
{
|
||||||
|
nodes ~= node;
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Foreach over YAML documents.
|
||||||
|
*
|
||||||
|
* Parses documents lazily, as they are needed.
|
||||||
|
*
|
||||||
|
* Throws: YAMLException on a parsing error.
|
||||||
|
*/
|
||||||
|
int opApply(int delegate(ref Node) dg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto composer = new Composer(parser_, resolver_, constructor_);
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
while(composer.checkNode())
|
||||||
|
{
|
||||||
|
auto node = composer.getNode();
|
||||||
|
result = dg(node);
|
||||||
|
if(result){break;}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch(YAMLException e)
|
||||||
|
{
|
||||||
|
e.name = name_;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
package:
|
package:
|
||||||
|
@ -333,3 +284,20 @@ struct Loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
import std.stream;
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
string yaml_input = "red: '#ff0000'\n"
|
||||||
|
"green: '#00ff00'\n"
|
||||||
|
"blue: '#0000ff'";
|
||||||
|
|
||||||
|
auto colors = Loader(new MemoryStream(cast(char[])yaml_input)).load();
|
||||||
|
|
||||||
|
foreach(string color, string value; colors)
|
||||||
|
{
|
||||||
|
writeln(color, " is ", value, " in HTML/CSS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -88,9 +88,10 @@ void main()
|
||||||
constructor.addConstructor("!color", &constructColorScalar);
|
constructor.addConstructor("!color", &constructColorScalar);
|
||||||
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
||||||
|
|
||||||
auto loader = new Loader("input.yaml", constructor, new Resolver);
|
auto loader = Loader("input.yaml");
|
||||||
|
loader.constructor = constructor;
|
||||||
|
|
||||||
auto root = loader.loadSingleDocument();
|
auto root = loader.load();
|
||||||
|
|
||||||
if(root["scalar-red"].get!Color == red &&
|
if(root["scalar-red"].get!Color == red &&
|
||||||
root["mapping-red"].get!Color == red &&
|
root["mapping-red"].get!Color == red &&
|
||||||
|
|
|
@ -3,7 +3,7 @@ import yaml;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
yaml.Node root = yaml.load("input.yaml");
|
yaml.Node root = Loader("input.yaml").load();
|
||||||
foreach(string word; root["Hello World"])
|
foreach(string word; root["Hello World"])
|
||||||
{
|
{
|
||||||
writeln(word);
|
writeln(word);
|
||||||
|
|
|
@ -92,9 +92,11 @@ void main()
|
||||||
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
|
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
|
||||||
"0123456789abcdefABCDEF");
|
"0123456789abcdefABCDEF");
|
||||||
|
|
||||||
auto loader = new Loader("input.yaml", constructor, resolver);
|
auto loader = Loader("input.yaml");
|
||||||
|
loader.constructor = constructor;
|
||||||
|
loader.resolver = resolver;
|
||||||
|
|
||||||
auto root = loader.loadSingleDocument();
|
auto root = loader.load();
|
||||||
|
|
||||||
if(root["scalar-red"].get!Color == red &&
|
if(root["scalar-red"].get!Color == red &&
|
||||||
root["mapping-red"].get!Color == red &&
|
root["mapping-red"].get!Color == red &&
|
||||||
|
|
|
@ -42,8 +42,8 @@ void testParser(bool verbose, string dataFilename, string canonicalFilename)
|
||||||
*/
|
*/
|
||||||
void testLoader(bool verbose, string dataFilename, string canonicalFilename)
|
void testLoader(bool verbose, string dataFilename, string canonicalFilename)
|
||||||
{
|
{
|
||||||
auto data = loadAll(dataFilename);
|
auto data = Loader(dataFilename).loadAll;
|
||||||
auto canonical = loadAll(canonicalFilename);
|
auto canonical = Loader(canonicalFilename).loadAll;
|
||||||
|
|
||||||
assert(data.length == canonical.length, "Unequal node count");
|
assert(data.length == canonical.length, "Unequal node count");
|
||||||
foreach(n; 0 .. data.length)
|
foreach(n; 0 .. data.length)
|
||||||
|
|
|
@ -398,8 +398,9 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy)
|
||||||
constructor.addConstructor("!tag1", &constructClass);
|
constructor.addConstructor("!tag1", &constructClass);
|
||||||
constructor.addConstructor("!tag2", &constructStruct);
|
constructor.addConstructor("!tag2", &constructStruct);
|
||||||
|
|
||||||
auto resolver = new Resolver;
|
auto loader = Loader(dataFilename);
|
||||||
auto loader = Loader(dataFilename, constructor, resolver);
|
loader.constructor = constructor;
|
||||||
|
loader.resolver = new Resolver;
|
||||||
|
|
||||||
Node[] exp = expected[base];
|
Node[] exp = expected[base];
|
||||||
|
|
||||||
|
|
|
@ -92,8 +92,12 @@ void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilena
|
||||||
writeln("ORIGINAL:\n", readText(dataFilename));
|
writeln("ORIGINAL:\n", readText(dataFilename));
|
||||||
writeln("OUTPUT:\n", cast(string)emitStream.data);
|
writeln("OUTPUT:\n", cast(string)emitStream.data);
|
||||||
}
|
}
|
||||||
auto loadStream = new MemoryStream(emitStream.data);
|
|
||||||
auto newEvents = Loader(loadStream, "DUMMY", new Constructor, new Resolver).parse();
|
auto loader2 = Loader(new MemoryStream(emitStream.data));
|
||||||
|
loader2.name = "TEST";
|
||||||
|
loader2.constructor = new Constructor;
|
||||||
|
loader2.resolver = new Resolver;
|
||||||
|
auto newEvents = loader2.parse();
|
||||||
assert(compareEvents(events, newEvents));
|
assert(compareEvents(events, newEvents));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +125,11 @@ void testEmitterOnCanonical(bool verbose, string canonicalFilename)
|
||||||
writeln("OUTPUT (canonical=", canonical, "):\n",
|
writeln("OUTPUT (canonical=", canonical, "):\n",
|
||||||
cast(string)emitStream.data);
|
cast(string)emitStream.data);
|
||||||
}
|
}
|
||||||
auto loadStream = new MemoryStream(emitStream.data);
|
auto loader2 = Loader(new MemoryStream(emitStream.data));
|
||||||
auto newEvents = Loader(loadStream, "DUMMY", new Constructor, new Resolver).parse();
|
loader2.name = "TEST";
|
||||||
|
loader2.constructor = new Constructor;
|
||||||
|
loader2.resolver = new Resolver;
|
||||||
|
auto newEvents = loader2.parse();
|
||||||
assert(compareEvents(events, newEvents));
|
assert(compareEvents(events, newEvents));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,8 +186,11 @@ void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilena
|
||||||
to!string(style), ")");
|
to!string(style), ")");
|
||||||
writeln(emitStream.data);
|
writeln(emitStream.data);
|
||||||
}
|
}
|
||||||
auto loadStream = new MemoryStream(emitStream.data);
|
auto loader2 = Loader(new MemoryStream(emitStream.data));
|
||||||
auto newEvents = Loader(loadStream, "DUMMY", new Constructor, new Resolver).parse();
|
loader2.name = "TEST";
|
||||||
|
loader2.constructor = new Constructor;
|
||||||
|
loader2.resolver = new Resolver;
|
||||||
|
auto newEvents = loader2.parse();
|
||||||
assert(compareEvents(events, newEvents));
|
assert(compareEvents(events, newEvents));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ void testLoaderError(bool verbose, string errorFilename)
|
||||||
scope(exit){file.close();}
|
scope(exit){file.close();}
|
||||||
|
|
||||||
Node[] nodes;
|
Node[] nodes;
|
||||||
try{nodes = loadAll(file, errorFilename);}
|
try{nodes = Loader(file).loadAll();}
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
||||||
|
@ -48,7 +48,7 @@ void testLoaderErrorString(bool verbose, string errorFilename)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto nodes = loadAll(new MemoryStream(buffer), errorFilename);
|
auto nodes = Loader(new MemoryStream(buffer)).loadAll();
|
||||||
}
|
}
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,7 @@ void testLoaderErrorString(bool verbose, string errorFilename)
|
||||||
*/
|
*/
|
||||||
void testLoaderErrorFilename(bool verbose, string errorFilename)
|
void testLoaderErrorFilename(bool verbose, string errorFilename)
|
||||||
{
|
{
|
||||||
try{auto nodes = loadAll(errorFilename);}
|
try{auto nodes = Loader(errorFilename).loadAll();}
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
||||||
|
@ -83,7 +83,7 @@ void testLoaderErrorFilename(bool verbose, string errorFilename)
|
||||||
*/
|
*/
|
||||||
void testLoaderErrorSingle(bool verbose, string errorFilename)
|
void testLoaderErrorSingle(bool verbose, string errorFilename)
|
||||||
{
|
{
|
||||||
try{auto nodes = load(errorFilename);}
|
try{auto nodes = Loader(errorFilename).load();}
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
||||||
|
|
|
@ -57,13 +57,13 @@ void testUnicodeInput(bool verbose, string unicodeFilename)
|
||||||
string data = readText(unicodeFilename);
|
string data = readText(unicodeFilename);
|
||||||
string expected = data.split().join(" ");
|
string expected = data.split().join(" ");
|
||||||
|
|
||||||
Node output = load(new MemoryStream(to!(char[])(data)), unicodeFilename);
|
Node output = Loader(new MemoryStream(to!(char[])(data))).load();
|
||||||
assert(output.get!string == expected);
|
assert(output.get!string == expected);
|
||||||
|
|
||||||
foreach(stream; [new MemoryStream(cast(byte[])(bom16() ~ to!(wchar[])(data))),
|
foreach(stream; [new MemoryStream(cast(byte[])(bom16() ~ to!(wchar[])(data))),
|
||||||
new MemoryStream(cast(byte[])(bom32() ~ to!(dchar[])(data)))])
|
new MemoryStream(cast(byte[])(bom32() ~ to!(dchar[])(data)))])
|
||||||
{
|
{
|
||||||
output = load(stream, unicodeFilename);
|
output = Loader(stream).load();
|
||||||
assert(output.get!string == expected);
|
assert(output.get!string == expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ void testUnicodeInputErrors(bool verbose, string unicodeFilename)
|
||||||
new MemoryStream(cast(byte[])(bom16(true) ~ to!(wchar[])(data))),
|
new MemoryStream(cast(byte[])(bom16(true) ~ to!(wchar[])(data))),
|
||||||
new MemoryStream(cast(byte[])(bom32(true) ~ to!(dchar[])(data)))])
|
new MemoryStream(cast(byte[])(bom32(true) ~ to!(dchar[])(data)))])
|
||||||
{
|
{
|
||||||
try{load(stream, unicodeFilename);}
|
try{Loader(stream).load();}
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
if(verbose){writeln(typeid(e).toString(), "\n", e);}
|
||||||
|
|
|
@ -61,9 +61,10 @@ void testRepresenterTypes(bool verbose, string codeFilename)
|
||||||
constructor.addConstructor("!tag1", &constructClass);
|
constructor.addConstructor("!tag1", &constructClass);
|
||||||
constructor.addConstructor("!tag2", &constructStruct);
|
constructor.addConstructor("!tag2", &constructStruct);
|
||||||
|
|
||||||
auto resolver = new Resolver;
|
auto loader = Loader(loadStream);
|
||||||
auto loader = Loader(loadStream, "DUMMY", constructor, resolver);
|
loader.name = "TEST";
|
||||||
foreach(node; loader){readNodes ~= node;}
|
loader.constructor = constructor;
|
||||||
|
readNodes = loader.loadAll();
|
||||||
|
|
||||||
assert(expectedNodes.length == readNodes.length);
|
assert(expectedNodes.length == readNodes.length);
|
||||||
foreach(n; 0 .. expectedNodes.length)
|
foreach(n; 0 .. expectedNodes.length)
|
||||||
|
|
|
@ -17,27 +17,31 @@ import dyaml.testcommon;
|
||||||
* Implicit tag resolution unittest.
|
* Implicit tag resolution unittest.
|
||||||
*
|
*
|
||||||
* Params: verbose = Print verbose output?
|
* Params: verbose = Print verbose output?
|
||||||
* dataFilename = TODO
|
* dataFilename = File with unittest data.
|
||||||
* detectFilename = TODO
|
* detectFilename = Dummy filename used to specify which data filenames to use.
|
||||||
*/
|
*/
|
||||||
void testImplicitResolver(bool verbose, string dataFilename, string detectFilename)
|
void testImplicitResolver(bool verbose, string dataFilename, string detectFilename)
|
||||||
{
|
{
|
||||||
string correctTag;
|
string correctTag;
|
||||||
Node node;
|
Node node;
|
||||||
|
|
||||||
scope(exit)
|
scope(failure)
|
||||||
{
|
{
|
||||||
if(verbose)
|
if(true)
|
||||||
{
|
{
|
||||||
writeln("Correct tag: ", correctTag);
|
writeln("Correct tag: ", correctTag);
|
||||||
writeln("Node: ", node.debugString);
|
writeln("Node: ", node.debugString);
|
||||||
assert(node.isSequence);
|
|
||||||
assert(node.tag.get == correctTag);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
correctTag = readText(dataFilename).strip();
|
correctTag = readText(detectFilename).strip();
|
||||||
node = yaml.load(dataFilename);
|
node = Loader(dataFilename).load();
|
||||||
|
assert(node.isSequence);
|
||||||
|
foreach(ref Node scalar; node)
|
||||||
|
{
|
||||||
|
assert(scalar.isScalar);
|
||||||
|
assert(scalar.tag.get == correctTag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue