Implemented the resolver unittest.

Changed Loader API to be in line with Dumper,
and updated examples, tutorials and docs.
This commit is contained in:
Ferdinand Majerech 2011-10-12 23:49:42 +02:00
parent 934df763ad
commit 34b11405d4
16 changed files with 262 additions and 279 deletions

View file

@ -2,10 +2,10 @@
Custom YAML data types
======================
Often you will want to serialize complex data types such as classes. You can use
functions to process nodes; e.g. a mapping containing class data members indexed
by name. Alternatively, YAML supports custom data types using identifiers called
*tags*. That is the topic of this tutorial.
Often you might want to serialize complex data types such as classes. You can
use functions to process nodes such as a mapping containing class data members
indexed by name. Alternatively, YAML supports custom data types using
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
``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
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
*addConstructor()* method. *Constructor* is then passed to *Loader*, which will
parse YAML input.
tag to process it. These functions are supplied by the user using the
*addConstructor()* method. *Constructor* is then passed to *Loader*, which
parses YAML input.
We will implement support for an RGB color type. It is implemented as the
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);
}
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:
.. code-block:: yaml
@ -144,9 +144,10 @@ Finally, the code to put it all together:
constructor.addConstructor("!color", &constructColorScalar);
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 &&
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``
and ``!color-mapping`` tag. We construct a *Loader* using the *Constructor*.
We also need a *Resolver*, but for now we just default-construct it. We then
load the YAML document, and finally, read the colors using *get()* method to
test if they were loaded as expected.
and ``!color-mapping`` tag. We construct a *Loader*m and pass the *Constructor*
to it. We then load the YAML document, and finally, read the colors using
*get()* method to test if they were loaded as expected.
You can find the source code for what we've done so far in the
``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
resolve tag of a scalar using a regular expression. This is how default types,
e.g. int, are resolved. We will use the *Resolver* class to add implicit tag
resolve scalar tags using regular expressions. This is how default types such as
int are resolved. We will use the *Resolver* class to add implicit tag
resolution for the Color data type (in its scalar form).
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}",
"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...
Now, change contents of input.dyaml to this:
Now, change contents of input.yaml to this:
.. code-block:: yaml

View file

@ -26,10 +26,8 @@ Download the version of DMD for your operating system and install it.
.. note::
Other D compilers exist, such as
`GDC <http://bitbucket.org/goshawk/gdc/wiki/Home>`_ and
`LDC <http://www.dsource.org/projects/ldc/>`_.
Setting up with either one of them should be similar to DMD,
however, at the moment they are not as up to date as DMD.
`LDC <http://www.dsource.org/projects/ldc/>`_. Setting up with either one of
them should be similar to DMD, but they are not yet as stable as DMD.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Download and compile D:YAML
@ -84,7 +82,7 @@ into the file:
void main()
{
yaml.Node root = yaml.load("input.yaml");
Node root = Loader("input.yaml").load();
foreach(string word; root["Hello World"])
{
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
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
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
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, 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
*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
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
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
@ -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"
cannot be converted to an integer.
The *yaml.Node.get()* method is used to get value of a scalar node as specified
type. D:YAML will try to return the scalar as specified type, converting if
The *Node.get()* method is used to get value of a scalar node, allowing to
specify type. D:YAML will try to return the scalar as this type, converting if
needed, throwing *YAMLException* if not possible.
@ -135,16 +134,15 @@ Compiling
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
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
compiled D:YAML library. On Unix/Linux you can specify it using the ``-L-L``
option, and link with D:YAML using the ``-L-l`` option. On Windows, the import
directory is used as the library directory. To link with the library on Windows,
just add the path to it relative to the current directory.
``-I`` option of DMD. The library directory should be where you put the compiled
D:YAML library. On Unix/Linux you can specify it using the ``-L-L`` option, and
link with D:YAML using the ``-L-l`` option. On Windows, the import directory is
used as the library directory. To link with the library on Windows, just add the
path to it relative to the current directory.
For example, if you extracted D:YAML to ``/home/xxx/dyaml`` and compiled it in
that directory, your project is in ``/home/xxx/dyaml-project``, and you are
currently in that directory, you can compile the project with the following
command on Unix/Linux::
For example, if you extracted and compiled D:YAML in ``/home/xxx/dyaml``, your
project is in ``/home/xxx/dyaml-project``, and you are currently in that
directory, you can compile the project with the following command on Unix/Linux::
dmd -I../dyaml -L-L../dyaml -L-ldyaml main.d

View file

@ -8,14 +8,14 @@ which this article is based on,
`Chapter 2 of the YAML specification <http://yaml.org/spec/1.1/#id857168>`_
or the `Wikipedia page <http://en.wikipedia.org/wiki/YAML>`_.
YAML is a data serialization format designed to be as human readable as
possible. YAML is a recursive acronym for "YAML Ain't Markup Language".
YAML is a data serialization format designed for human readability. YAML is a
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
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
(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).
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
optionally ending with ``...`` . If there is only one document, ``---`` can be
left out.
optionally ending with ``...`` . ``---`` can be left out for the first document.
Single document with no explicit start or end: