Fixed a bug which prevented dumping to file. Updated tutorials
and example with new information.
This commit is contained in:
parent
23290239a7
commit
210091a75f
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later.
|
||||||
Constructor
|
Constructor
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
D:YAML uses the *Constructor* class to process each node to hold data type
|
D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process
|
||||||
corresponding to its tag. *Constructor* stores a function for each supported
|
each node to hold data type corresponding to its tag. *Constructor* stores a
|
||||||
tag to process it. These functions are supplied by the user using the
|
function for each supported tag to process it. These functions are supplied by
|
||||||
*addConstructor()* method. *Constructor* is then passed to *Loader*, which
|
the user using the *addConstructor()* method. *Constructor* is then passed to
|
||||||
parses YAML input.
|
*Loader*, which parses YAML input.
|
||||||
|
|
||||||
|
Struct types have no specific requirements for YAML support. Class types should
|
||||||
|
define the *opEquals()* operator, as this is used in equality comparisons of
|
||||||
|
nodes. Default class *opEquals()* compares references, which means two identical
|
||||||
|
objects might be considered unequal.
|
||||||
|
|
||||||
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,8 +116,8 @@ 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 data using our new tag. Create a file called input.yaml
|
Next, we need some YAML data using our new tag. Create a file called
|
||||||
with the following contents:
|
``input.yaml`` with the following contents:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
@ -167,7 +172,7 @@ 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*m and pass the *Constructor*
|
and ``!color-mapping`` tag. We construct a *Loader* and pass the *Constructor*
|
||||||
to it. We then load the YAML document, and finally, read the colors using
|
to it. We then load the YAML document, and finally, read the colors using
|
||||||
*get()* method to test if they were loaded as expected.
|
*get()* method to test if they were loaded as expected.
|
||||||
|
|
||||||
|
@ -181,12 +186,13 @@ 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 scalar tags using regular expressions. This is how default types such as
|
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
|
int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ class
|
||||||
resolution for the Color data type (in its scalar form).
|
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
|
We use the *addImplicitResolver()* method of *Resolver*, passing the tag,
|
||||||
expression the value must match to resolve to this tag, and a string of possible
|
regular expression the scalar must match to resolve to this tag, and a string of
|
||||||
starting characters of the value. Then we pass the *Resolver* to *Loader*.
|
possible starting characters of the scalar. Then we pass the *Resolver* to
|
||||||
|
*Loader*.
|
||||||
|
|
||||||
Note that resolvers added first override ones added later. If no resolver
|
Note that resolvers added first override ones added later. If no resolver
|
||||||
matches a scalar, YAML string tag is used. Therefore our custom values must not
|
matches a scalar, YAML string tag is used. Therefore our custom values must not
|
||||||
|
@ -199,8 +205,8 @@ Add this to your code to add implicit resolution of ``!color``.
|
||||||
//code from the previous example...
|
//code from the previous example...
|
||||||
|
|
||||||
auto resolver = new Resolver;
|
auto resolver = new Resolver;
|
||||||
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 = Loader("input.yaml");
|
auto loader = Loader("input.yaml");
|
||||||
|
|
||||||
|
@ -209,7 +215,7 @@ Add this to your code to add implicit resolution of ``!color``.
|
||||||
|
|
||||||
//code from the previous example...
|
//code from the previous example...
|
||||||
|
|
||||||
Now, change contents of input.yaml to this:
|
Now, change contents of ``input.yaml`` to this:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
@ -227,3 +233,107 @@ the example. If everything went as expected, it should report success.
|
||||||
|
|
||||||
You can find the complete code in the ``examples/resolver`` directory in the
|
You can find the complete code in the ``examples/resolver`` directory in the
|
||||||
D:YAML package.
|
D:YAML package.
|
||||||
|
|
||||||
|
|
||||||
|
-----------
|
||||||
|
Representer
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Now that you know how to load custom data types, it might also be useful to know
|
||||||
|
how to dump them. D:YAML uses the `Representer <../api/dyaml.representer.html>`_
|
||||||
|
class for this purpose.
|
||||||
|
|
||||||
|
*Representer* processes YAML nodes into plain mapping, sequence or scalar nodes
|
||||||
|
ready for output. Just like with *Constructor*, this is done by user specified
|
||||||
|
functions. These functions take references to a node to process and to the
|
||||||
|
*Representer*, and return the processed node.
|
||||||
|
|
||||||
|
Representer functions can be added with the *addRepresenter()* method. The
|
||||||
|
*Representer* is then passed to *Dumper*, which dumps YAML documents. Only one
|
||||||
|
representer can be added for a type. This is asserted in *addRepresenter()*
|
||||||
|
preconditions. By default, the default YAML types already have representer
|
||||||
|
functions, but you can disable them by constructing *Representer* with the
|
||||||
|
*useDefaultRepresenters* parameter set to false.
|
||||||
|
|
||||||
|
By default, tags are explicitly specified for all non-default types. If you
|
||||||
|
want the tags to be implicit, you can pass a *Resolver* that will resolve them
|
||||||
|
implicitly. Of course, you will then need to use an identical *Resolver* when
|
||||||
|
loading the output.
|
||||||
|
|
||||||
|
With the following code, we will add support for dumping the our Color type.
|
||||||
|
|
||||||
|
.. code-block:: d
|
||||||
|
|
||||||
|
Node representColor(ref Node node, Representer representer)
|
||||||
|
{
|
||||||
|
//The node is guaranteed to be Color as we add representer for Color.
|
||||||
|
Color color = node.get!Color;
|
||||||
|
|
||||||
|
static immutable hex = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
//Using the color format from the Constructor example.
|
||||||
|
string scalar;
|
||||||
|
foreach(channel; [color.red, color.green, color.blue])
|
||||||
|
{
|
||||||
|
scalar ~= hex[channel / 16];
|
||||||
|
scalar ~= hex[channel % 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Representing as a scalar, with custom tag to specify this data type.
|
||||||
|
return representer.representScalar("!color", scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
First we get the *Color* from the node. Then we convert it to a string with the
|
||||||
|
HTML-like format we've used before. Finally, we use the *representScalar()*
|
||||||
|
method of *Representer* to get a scalar node ready for output.
|
||||||
|
There are corresponding *representMapping()* and *representSequence()* methods
|
||||||
|
as well, with examples in the
|
||||||
|
`Resolver API documentation <../api/dyaml.resolver.html>`_.
|
||||||
|
|
||||||
|
Since a type can only have one representer function, we don't dump *Color* both
|
||||||
|
in the scalar and mapping formats we've used before. However, you can decide to
|
||||||
|
dump the node with different formats/tags in the representer function itself.
|
||||||
|
E.g. you could dump the Color as a mapping based on some arbitrary condition,
|
||||||
|
such as the color being white.
|
||||||
|
|
||||||
|
.. code-block:: d
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto representer = new Representer;
|
||||||
|
representer.addRepresenter!Color(&representColor);
|
||||||
|
|
||||||
|
auto resolver = new Resolver;
|
||||||
|
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
|
||||||
|
"0123456789abcdefABCDEF");
|
||||||
|
|
||||||
|
auto dumper = Dumper("output.yaml");
|
||||||
|
dumper.representer = representer;
|
||||||
|
dumper.resolver = resolver;
|
||||||
|
|
||||||
|
auto document = Node([Color(255, 0, 0),
|
||||||
|
Color(0, 255, 0),
|
||||||
|
Color(0, 0, 255)]);
|
||||||
|
|
||||||
|
dumper.dump(document);
|
||||||
|
}
|
||||||
|
catch(YAMLException e)
|
||||||
|
{
|
||||||
|
writeln(e.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
We construct a new *Representer*, and specify a representer function for the
|
||||||
|
*Color* (the template argument) type. We also construct a *Resolver*, same as in
|
||||||
|
the previous section, so the ``!color`` tag will be implicit. Of course,
|
||||||
|
identical *Resolver* would then have to be used when loading the file.
|
||||||
|
You don't need to do this if you want the tag to be explicit.
|
||||||
|
|
||||||
|
We construct a *Dumper* to file ``output.yaml`` and pass the *Representer* and
|
||||||
|
*Resolver* to it. Then, we create a simple node containing a sequence of colors
|
||||||
|
and finally, we dump it.
|
||||||
|
|
||||||
|
Source code for this section can be found in the ``examples/representer``
|
||||||
|
directory of the D:YAML package.
|
||||||
|
|
|
@ -72,7 +72,7 @@ Create a directory for your project and in that directory, create a file called
|
||||||
|
|
||||||
This will serve as input for our example.
|
This will serve as input for our example.
|
||||||
|
|
||||||
Now we need to parse it. Create a file called "main.d". Paste following code
|
Now we need to parse it. Create a file called ``main.d``. Paste following code
|
||||||
into the file:
|
into the file:
|
||||||
|
|
||||||
.. code-block:: d
|
.. code-block:: d
|
||||||
|
@ -82,12 +82,18 @@ into the file:
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
//Read the input.
|
||||||
Node root = Loader("input.yaml").load();
|
Node root = Loader("input.yaml").load();
|
||||||
|
|
||||||
|
//Display the data read.
|
||||||
foreach(string word; root["Hello World"])
|
foreach(string word; root["Hello World"])
|
||||||
{
|
{
|
||||||
writeln(word);
|
writeln(word);
|
||||||
}
|
}
|
||||||
writeln("The answer is ", root["Answer"].get!int);
|
writeln("The answer is ", root["Answer"].get!int);
|
||||||
|
|
||||||
|
//Dump the loaded document to output.yaml.
|
||||||
|
Dumper("output.yaml").dump(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,8 +104,8 @@ 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 *Loader.load()* method. *Loader* is the struct
|
Next we load the file using the *Loader.load()* method. *Loader* is a struct
|
||||||
used for parsing YAML documents, and *load()* is a method that loads the file as
|
used for parsing YAML documents. The *load()* method loads the file as
|
||||||
**one** YAML document, or throws *YAMLException*, D:YAML exception type, if the
|
**one** YAML document, or 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
|
||||||
|
@ -126,6 +132,15 @@ 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
|
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.
|
||||||
|
|
||||||
|
Finally we dump the document we just read to ``output.yaml`` with the
|
||||||
|
*Dumper.dump()* method. *Dumper* is a struct used to dump YAML documents.
|
||||||
|
The *dump()* method writes one or more documents to a file, throwing
|
||||||
|
*YAMLException* if the file could not be written to.
|
||||||
|
|
||||||
|
D:YAML doesn't preserve style information in documents, so even though
|
||||||
|
``output.yaml`` will contain the same data as ``input.yaml``, it might be
|
||||||
|
formatted differently. Comments are not preserved, either.
|
||||||
|
|
||||||
|
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
Compiling
|
Compiling
|
||||||
|
|
|
@ -39,7 +39,8 @@
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<h1>dyaml.representer</h1>
|
<h1>dyaml.representer</h1>
|
||||||
<!-- Generated by Ddoc from dyaml/representer.d -->
|
<!-- Generated by Ddoc from dyaml/representer.d -->
|
||||||
<p>YAML node representer.
|
<p>YAML node representer. Prepares YAML nodes for output. A tutorial can be
|
||||||
|
found <a href="../tutorials/custom_types.html">here</a>.
|
||||||
</p>
|
</p>
|
||||||
<p>Code based on <a href="http://www.pyyaml.org">PyYAML</a>.</p>
|
<p>Code based on <a href="http://www.pyyaml.org">PyYAML</a>.</p>
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ struct appears in Phobos.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||||
Last updated on Oct 14, 2011.
|
Last updated on Oct 15, 2011.
|
||||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
<li class="toctree-l1"><a class="reference internal" href="tutorials/custom_types.html">Custom YAML data types</a><ul>
|
<li class="toctree-l1"><a class="reference internal" href="tutorials/custom_types.html">Custom YAML data types</a><ul>
|
||||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/custom_types.html#constructor">Constructor</a></li>
|
<li class="toctree-l2"><a class="reference internal" href="tutorials/custom_types.html#constructor">Constructor</a></li>
|
||||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/custom_types.html#resolver">Resolver</a></li>
|
<li class="toctree-l2"><a class="reference internal" href="tutorials/custom_types.html#resolver">Resolver</a></li>
|
||||||
|
<li class="toctree-l2"><a class="reference internal" href="tutorials/custom_types.html#representer">Representer</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="toctree-l1"><a class="reference internal" href="tutorials/yaml_syntax.html">YAML syntax</a><ul>
|
<li class="toctree-l1"><a class="reference internal" href="tutorials/yaml_syntax.html">YAML syntax</a><ul>
|
||||||
|
@ -103,7 +104,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||||
Last updated on Oct 14, 2011.
|
Last updated on Oct 15, 2011.
|
||||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||||
Last updated on Oct 14, 2011.
|
Last updated on Oct 15, 2011.
|
||||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -57,11 +57,15 @@ during parsing, so you don’t need to specify tag for each float, integer,
|
||||||
It is also possible to implicitly resolve custom tags, as we will show later.</p>
|
It is also possible to implicitly resolve custom tags, as we will show later.</p>
|
||||||
<div class="section" id="constructor">
|
<div class="section" id="constructor">
|
||||||
<h2>Constructor<a class="headerlink" href="#constructor" title="Permalink to this headline">¶</a></h2>
|
<h2>Constructor<a class="headerlink" href="#constructor" title="Permalink to this headline">¶</a></h2>
|
||||||
<p>D:YAML uses the <em>Constructor</em> class to process each node to hold data type
|
<p>D:YAML uses the <a class="reference external" href="../api/dyaml.constructor.html">Constructor</a> class to process
|
||||||
corresponding to its tag. <em>Constructor</em> stores a function for each supported
|
each node to hold data type corresponding to its tag. <em>Constructor</em> stores a
|
||||||
tag to process it. These functions are supplied by the user using the
|
function for each supported tag to process it. These functions are supplied by
|
||||||
<em>addConstructor()</em> method. <em>Constructor</em> is then passed to <em>Loader</em>, which
|
the user using the <em>addConstructor()</em> method. <em>Constructor</em> is then passed to
|
||||||
parses YAML input.</p>
|
<em>Loader</em>, which parses YAML input.</p>
|
||||||
|
<p>Struct types have no specific requirements for YAML support. Class types should
|
||||||
|
define the <em>opEquals()</em> operator, as this is used in equality comparisons of
|
||||||
|
nodes. Default class <em>opEquals()</em> compares references, which means two identical
|
||||||
|
objects might be considered unequal.</p>
|
||||||
<p>We will implement support for an RGB color type. It is implemented as the
|
<p>We will implement support for an RGB color type. It is implemented as the
|
||||||
following struct:</p>
|
following struct:</p>
|
||||||
<div class="highlight-d"><div class="highlight"><pre><span class="k">struct</span> <span class="n">Color</span>
|
<div class="highlight-d"><div class="highlight"><pre><span class="k">struct</span> <span class="n">Color</span>
|
||||||
|
@ -146,8 +150,8 @@ RRGGBB, or from a mapping, where we use the following format:
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
</div>
|
</div>
|
||||||
<p>Next, we need some YAML data using our new tag. Create a file called input.yaml
|
<p>Next, we need some YAML data using our new tag. Create a file called
|
||||||
with the following contents:</p>
|
<tt class="docutils literal"><span class="pre">input.yaml</span></tt> with the following contents:</p>
|
||||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar-red</span><span class="p-Indicator">:</span> <span class="kt">!color</span> <span class="l-Scalar-Plain">FF0000</span>
|
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar-red</span><span class="p-Indicator">:</span> <span class="kt">!color</span> <span class="l-Scalar-Plain">FF0000</span>
|
||||||
<span class="l-Scalar-Plain">scalar-orange</span><span class="p-Indicator">:</span> <span class="kt">!color</span> <span class="l-Scalar-Plain">FFFF00</span>
|
<span class="l-Scalar-Plain">scalar-orange</span><span class="p-Indicator">:</span> <span class="kt">!color</span> <span class="l-Scalar-Plain">FFFF00</span>
|
||||||
<span class="l-Scalar-Plain">mapping-red</span><span class="p-Indicator">:</span> <span class="kt">!color-mapping</span> <span class="p-Indicator">{</span><span class="nv">r</span><span class="p-Indicator">:</span> <span class="nv">255</span><span class="p-Indicator">,</span> <span class="nv">g</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">,</span> <span class="nv">b</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">}</span>
|
<span class="l-Scalar-Plain">mapping-red</span><span class="p-Indicator">:</span> <span class="kt">!color-mapping</span> <span class="p-Indicator">{</span><span class="nv">r</span><span class="p-Indicator">:</span> <span class="nv">255</span><span class="p-Indicator">,</span> <span class="nv">g</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">,</span> <span class="nv">b</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">}</span>
|
||||||
|
@ -197,7 +201,7 @@ with the following contents:</p>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
</div>
|
</div>
|
||||||
<p>First, we create a <em>Constructor</em> and pass functions to handle the <tt class="docutils literal"><span class="pre">!color</span></tt>
|
<p>First, we create a <em>Constructor</em> and pass functions to handle the <tt class="docutils literal"><span class="pre">!color</span></tt>
|
||||||
and <tt class="docutils literal"><span class="pre">!color-mapping</span></tt> tag. We construct a <em>Loader*m and pass the *Constructor</em>
|
and <tt class="docutils literal"><span class="pre">!color-mapping</span></tt> tag. We construct a <em>Loader</em> and pass the <em>Constructor</em>
|
||||||
to it. We then load the YAML document, and finally, read the colors using
|
to it. We then load the YAML document, and finally, read the colors using
|
||||||
<em>get()</em> method to test if they were loaded as expected.</p>
|
<em>get()</em> method to test if they were loaded as expected.</p>
|
||||||
<p>You can find the source code for what we’ve done so far in the
|
<p>You can find the source code for what we’ve done so far in the
|
||||||
|
@ -207,11 +211,12 @@ to it. We then load the YAML document, and finally, read the colors using
|
||||||
<h2>Resolver<a class="headerlink" href="#resolver" title="Permalink to this headline">¶</a></h2>
|
<h2>Resolver<a class="headerlink" href="#resolver" title="Permalink to this headline">¶</a></h2>
|
||||||
<p>Specifying tag for every color value can be tedious. D:YAML can implicitly
|
<p>Specifying tag for every color value can be tedious. D:YAML can implicitly
|
||||||
resolve scalar tags using regular expressions. This is how default types such as
|
resolve scalar tags using regular expressions. This is how default types such as
|
||||||
int are resolved. We will use the <em>Resolver</em> class to add implicit tag
|
int are resolved. We will use the <a class="reference external" href="../api/dyaml.resolver.html">Resolver</a> class
|
||||||
resolution for the Color data type (in its scalar form).</p>
|
to add implicit tag resolution for the Color data type (in its scalar form).</p>
|
||||||
<p>We use the <em>addImplicitResolver</em> method of <em>Resolver</em>, passing the tag, regular
|
<p>We use the <em>addImplicitResolver()</em> method of <em>Resolver</em>, passing the tag,
|
||||||
expression the value must match to resolve to this tag, and a string of possible
|
regular expression the scalar must match to resolve to this tag, and a string of
|
||||||
starting characters of the value. Then we pass the <em>Resolver</em> to <em>Loader</em>.</p>
|
possible starting characters of the scalar. Then we pass the <em>Resolver</em> to
|
||||||
|
<em>Loader</em>.</p>
|
||||||
<p>Note that resolvers added first override ones added later. If no resolver
|
<p>Note that resolvers added first override ones added later. If no resolver
|
||||||
matches a scalar, YAML string tag is used. Therefore our custom values must not
|
matches a scalar, YAML string tag is used. Therefore our custom values must not
|
||||||
be resolvable as any non-string YAML data type.</p>
|
be resolvable as any non-string YAML data type.</p>
|
||||||
|
@ -219,8 +224,8 @@ be resolvable as any non-string YAML data type.</p>
|
||||||
<div class="highlight-d"><div class="highlight"><pre><span class="c1">//code from the previous example...</span>
|
<div class="highlight-d"><div class="highlight"><pre><span class="c1">//code from the previous example...</span>
|
||||||
|
|
||||||
<span class="k">auto</span> <span class="n">resolver</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Resolver</span><span class="p">;</span>
|
<span class="k">auto</span> <span class="n">resolver</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Resolver</span><span class="p">;</span>
|
||||||
<span class="n">resolver</span><span class="p">.</span><span class="n">addImplicitResolver</span><span class="p">(</span><span class="s">"!color"</span><span class="p">,</span> <span class="n">std</span><span class="p">.</span><span class="n">regex</span><span class="p">.</span><span class="n">regex</span><span class="p">(</span><span class="s">"[0-9a-fA-F]{6}"</span><span class="p">,</span>
|
<span class="n">resolver</span><span class="p">.</span><span class="n">addImplicitResolver</span><span class="p">(</span><span class="s">"!color"</span><span class="p">,</span> <span class="n">std</span><span class="p">.</span><span class="n">regex</span><span class="p">.</span><span class="n">regex</span><span class="p">(</span><span class="s">"[0-9a-fA-F]{6}"</span><span class="p">),</span>
|
||||||
<span class="s">"0123456789abcdefABCDEF"</span><span class="p">));</span>
|
<span class="s">"0123456789abcdefABCDEF"</span><span class="p">);</span>
|
||||||
|
|
||||||
<span class="k">auto</span> <span class="n">loader</span> <span class="p">=</span> <span class="n">Loader</span><span class="p">(</span><span class="s">"input.yaml"</span><span class="p">);</span>
|
<span class="k">auto</span> <span class="n">loader</span> <span class="p">=</span> <span class="n">Loader</span><span class="p">(</span><span class="s">"input.yaml"</span><span class="p">);</span>
|
||||||
|
|
||||||
|
@ -230,7 +235,7 @@ be resolvable as any non-string YAML data type.</p>
|
||||||
<span class="c1">//code from the previous example...</span>
|
<span class="c1">//code from the previous example...</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
</div>
|
</div>
|
||||||
<p>Now, change contents of input.yaml to this:</p>
|
<p>Now, change contents of <tt class="docutils literal"><span class="pre">input.yaml</span></tt> to this:</p>
|
||||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar-red</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">FF0000</span>
|
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar-red</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">FF0000</span>
|
||||||
<span class="l-Scalar-Plain">scalar-orange</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">FFFF00</span>
|
<span class="l-Scalar-Plain">scalar-orange</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">FFFF00</span>
|
||||||
<span class="l-Scalar-Plain">mapping-red</span><span class="p-Indicator">:</span> <span class="kt">!color-mapping</span> <span class="p-Indicator">{</span><span class="nv">r</span><span class="p-Indicator">:</span> <span class="nv">255</span><span class="p-Indicator">,</span> <span class="nv">g</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">,</span> <span class="nv">b</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">}</span>
|
<span class="l-Scalar-Plain">mapping-red</span><span class="p-Indicator">:</span> <span class="kt">!color-mapping</span> <span class="p-Indicator">{</span><span class="nv">r</span><span class="p-Indicator">:</span> <span class="nv">255</span><span class="p-Indicator">,</span> <span class="nv">g</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">,</span> <span class="nv">b</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">}</span>
|
||||||
|
@ -246,6 +251,96 @@ the example. If everything went as expected, it should report success.</p>
|
||||||
<p>You can find the complete code in the <tt class="docutils literal"><span class="pre">examples/resolver</span></tt> directory in the
|
<p>You can find the complete code in the <tt class="docutils literal"><span class="pre">examples/resolver</span></tt> directory in the
|
||||||
D:YAML package.</p>
|
D:YAML package.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="section" id="representer">
|
||||||
|
<h2>Representer<a class="headerlink" href="#representer" title="Permalink to this headline">¶</a></h2>
|
||||||
|
<p>Now that you know how to load custom data types, it might also be useful to know
|
||||||
|
how to dump them. D:YAML uses the <a class="reference external" href="../api/dyaml.representer.html">Representer</a>
|
||||||
|
class for this purpose.</p>
|
||||||
|
<p><em>Representer</em> processes YAML nodes into plain mapping, sequence or scalar nodes
|
||||||
|
ready for output. Just like with <em>Constructor</em>, this is done by user specified
|
||||||
|
functions. These functions take references to a node to process and to the
|
||||||
|
<em>Representer</em>, and return the processed node.</p>
|
||||||
|
<p>Representer functions can be added with the <em>addRepresenter()</em> method. The
|
||||||
|
<em>Representer</em> is then passed to <em>Dumper</em>, which dumps YAML documents. Only one
|
||||||
|
representer can be added for a type. This is asserted in <em>addRepresenter()</em>
|
||||||
|
preconditions. By default, the default YAML types already have representer
|
||||||
|
functions, but you can disable them by constructing <em>Representer</em> with the
|
||||||
|
<em>useDefaultRepresenters</em> parameter set to false.</p>
|
||||||
|
<p>By default, tags are explicitly specified for all non-default types. If you
|
||||||
|
want the tags to be implicit, you can pass a <em>Resolver</em> that will resolve them
|
||||||
|
implicitly. Of course, you will then need to use an identical <em>Resolver</em> when
|
||||||
|
loading the output.</p>
|
||||||
|
<p>With the following code, we will add support for dumping the our Color type.</p>
|
||||||
|
<div class="highlight-d"><div class="highlight"><pre><span class="n">Node</span> <span class="n">representColor</span><span class="p">(</span><span class="k">ref</span> <span class="n">Node</span> <span class="n">node</span><span class="p">,</span> <span class="n">Representer</span> <span class="n">representer</span><span class="p">)</span>
|
||||||
|
<span class="p">{</span>
|
||||||
|
<span class="c1">//The node is guaranteed to be Color as we add representer for Color.</span>
|
||||||
|
<span class="n">Color</span> <span class="n">color</span> <span class="p">=</span> <span class="n">node</span><span class="p">.</span><span class="n">get</span><span class="p">!</span><span class="n">Color</span><span class="p">;</span>
|
||||||
|
|
||||||
|
<span class="k">static</span> <span class="n">immutable</span> <span class="n">hex</span> <span class="p">=</span> <span class="s">"0123456789ABCDEF"</span><span class="p">;</span>
|
||||||
|
|
||||||
|
<span class="c1">//Using the color format from the Constructor example.</span>
|
||||||
|
<span class="nb">string</span> <span class="n">scalar</span><span class="p">;</span>
|
||||||
|
<span class="k">foreach</span><span class="p">(</span><span class="n">channel</span><span class="p">;</span> <span class="p">[</span><span class="n">color</span><span class="p">.</span><span class="n">red</span><span class="p">,</span> <span class="n">color</span><span class="p">.</span><span class="n">green</span><span class="p">,</span> <span class="n">color</span><span class="p">.</span><span class="n">blue</span><span class="p">])</span>
|
||||||
|
<span class="p">{</span>
|
||||||
|
<span class="n">scalar</span> <span class="p">~=</span> <span class="n">hex</span><span class="p">[</span><span class="n">channel</span> <span class="p">/</span> <span class="mi">16</span><span class="p">];</span>
|
||||||
|
<span class="n">scalar</span> <span class="p">~=</span> <span class="n">hex</span><span class="p">[</span><span class="n">channel</span> <span class="p">%</span> <span class="mi">16</span><span class="p">];</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
|
||||||
|
<span class="c1">//Representing as a scalar, with custom tag to specify this data type.</span>
|
||||||
|
<span class="k">return</span> <span class="n">representer</span><span class="p">.</span><span class="n">representScalar</span><span class="p">(</span><span class="s">"!color"</span><span class="p">,</span> <span class="n">scalar</span><span class="p">);</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
</pre></div>
|
||||||
|
</div>
|
||||||
|
<p>First we get the <em>Color</em> from the node. Then we convert it to a string with the
|
||||||
|
HTML-like format we’ve used before. Finally, we use the <em>representScalar()</em>
|
||||||
|
method of <em>Representer</em> to get a scalar node ready for output.
|
||||||
|
There are corresponding <em>representMapping()</em> and <em>representSequence()</em> methods
|
||||||
|
as well, with examples in the
|
||||||
|
<a class="reference external" href="../api/dyaml.resolver.html">Resolver API documentation</a>.</p>
|
||||||
|
<p>Since a type can only have one representer function, we don’t dump <em>Color</em> both
|
||||||
|
in the scalar and mapping formats we’ve used before. However, you can decide to
|
||||||
|
dump the node with different formats/tags in the representer function itself.
|
||||||
|
E.g. you could dump the Color as a mapping based on some arbitrary condition,
|
||||||
|
such as the color being white.</p>
|
||||||
|
<div class="highlight-d"><div class="highlight"><pre><span class="kt">void</span> <span class="n">main</span><span class="p">()</span>
|
||||||
|
<span class="p">{</span>
|
||||||
|
<span class="k">try</span>
|
||||||
|
<span class="p">{</span>
|
||||||
|
<span class="k">auto</span> <span class="n">representer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Representer</span><span class="p">;</span>
|
||||||
|
<span class="n">representer</span><span class="p">.</span><span class="n">addRepresenter</span><span class="p">!</span><span class="n">Color</span><span class="p">(&</span><span class="n">representColor</span><span class="p">);</span>
|
||||||
|
|
||||||
|
<span class="k">auto</span> <span class="n">resolver</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Resolver</span><span class="p">;</span>
|
||||||
|
<span class="n">resolver</span><span class="p">.</span><span class="n">addImplicitResolver</span><span class="p">(</span><span class="s">"!color"</span><span class="p">,</span> <span class="n">std</span><span class="p">.</span><span class="n">regex</span><span class="p">.</span><span class="n">regex</span><span class="p">(</span><span class="s">"[0-9a-fA-F]{6}"</span><span class="p">),</span>
|
||||||
|
<span class="s">"0123456789abcdefABCDEF"</span><span class="p">);</span>
|
||||||
|
|
||||||
|
<span class="k">auto</span> <span class="n">dumper</span> <span class="p">=</span> <span class="n">Dumper</span><span class="p">(</span><span class="s">"output.yaml"</span><span class="p">);</span>
|
||||||
|
<span class="n">dumper</span><span class="p">.</span><span class="n">representer</span> <span class="p">=</span> <span class="n">representer</span><span class="p">;</span>
|
||||||
|
<span class="n">dumper</span><span class="p">.</span><span class="n">resolver</span> <span class="p">=</span> <span class="n">resolver</span><span class="p">;</span>
|
||||||
|
|
||||||
|
<span class="k">auto</span> <span class="n">document</span> <span class="p">=</span> <span class="n">Node</span><span class="p">([</span><span class="n">Color</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
|
||||||
|
<span class="n">Color</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
|
||||||
|
<span class="n">Color</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">)]);</span>
|
||||||
|
|
||||||
|
<span class="n">dumper</span><span class="p">.</span><span class="n">dump</span><span class="p">(</span><span class="n">document</span><span class="p">);</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
<span class="k">catch</span><span class="p">(</span><span class="n">YAMLException</span> <span class="n">e</span><span class="p">)</span>
|
||||||
|
<span class="p">{</span>
|
||||||
|
<span class="n">writeln</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">msg</span><span class="p">);</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
</pre></div>
|
||||||
|
</div>
|
||||||
|
<p>We construct a new <em>Representer</em>, and specify a representer function for the
|
||||||
|
<em>Color</em> (the template argument) type. We also construct a <em>Resolver</em>, same as in
|
||||||
|
the previous section, so the <tt class="docutils literal"><span class="pre">!color</span></tt> tag will be implicit. Of course,
|
||||||
|
identical <em>Resolver</em> would then have to be used when loading the file.
|
||||||
|
You don’t need to do this if you want the tag to be explicit.</p>
|
||||||
|
<p>We construct a <em>Dumper</em> to file <tt class="docutils literal"><span class="pre">output.yaml</span></tt> and pass the <em>Representer</em> and
|
||||||
|
<em>Resolver</em> to it. Then, we create a simple node containing a sequence of colors
|
||||||
|
and finally, we dump it.</p>
|
||||||
|
<p>Source code for this section can be found in the <tt class="docutils literal"><span class="pre">examples/representer</span></tt>
|
||||||
|
directory of the D:YAML package.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,6 +357,7 @@ D:YAML package.</p>
|
||||||
<li><a class="reference internal" href="#">Custom YAML data types</a><ul>
|
<li><a class="reference internal" href="#">Custom YAML data types</a><ul>
|
||||||
<li><a class="reference internal" href="#constructor">Constructor</a></li>
|
<li><a class="reference internal" href="#constructor">Constructor</a></li>
|
||||||
<li><a class="reference internal" href="#resolver">Resolver</a></li>
|
<li><a class="reference internal" href="#resolver">Resolver</a></li>
|
||||||
|
<li><a class="reference internal" href="#representer">Representer</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -284,7 +380,7 @@ D:YAML package.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||||
Last updated on Oct 14, 2011.
|
Last updated on Oct 15, 2011.
|
||||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -101,19 +101,25 @@ To do this on Unix/Linux, use the following command:</p>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
</div>
|
</div>
|
||||||
<p>This will serve as input for our example.</p>
|
<p>This will serve as input for our example.</p>
|
||||||
<p>Now we need to parse it. Create a file called “main.d”. Paste following code
|
<p>Now we need to parse it. Create a file called <tt class="docutils literal"><span class="pre">main.d</span></tt>. Paste following code
|
||||||
into the file:</p>
|
into the file:</p>
|
||||||
<div class="highlight-d"><div class="highlight"><pre><span class="k">import</span> <span class="n">std</span><span class="p">.</span><span class="n">stdio</span><span class="p">;</span>
|
<div class="highlight-d"><div class="highlight"><pre><span class="k">import</span> <span class="n">std</span><span class="p">.</span><span class="n">stdio</span><span class="p">;</span>
|
||||||
<span class="k">import</span> <span class="n">yaml</span><span class="p">;</span>
|
<span class="k">import</span> <span class="n">yaml</span><span class="p">;</span>
|
||||||
|
|
||||||
<span class="kt">void</span> <span class="n">main</span><span class="p">()</span>
|
<span class="kt">void</span> <span class="n">main</span><span class="p">()</span>
|
||||||
<span class="p">{</span>
|
<span class="p">{</span>
|
||||||
|
<span class="c1">//Read the input.</span>
|
||||||
<span class="n">Node</span> <span class="n">root</span> <span class="p">=</span> <span class="n">Loader</span><span class="p">(</span><span class="s">"input.yaml"</span><span class="p">).</span><span class="n">load</span><span class="p">();</span>
|
<span class="n">Node</span> <span class="n">root</span> <span class="p">=</span> <span class="n">Loader</span><span class="p">(</span><span class="s">"input.yaml"</span><span class="p">).</span><span class="n">load</span><span class="p">();</span>
|
||||||
|
|
||||||
|
<span class="c1">//Display the data read.</span>
|
||||||
<span class="k">foreach</span><span class="p">(</span><span class="nb">string</span> <span class="n">word</span><span class="p">;</span> <span class="n">root</span><span class="p">[</span><span class="s">"Hello World"</span><span class="p">])</span>
|
<span class="k">foreach</span><span class="p">(</span><span class="nb">string</span> <span class="n">word</span><span class="p">;</span> <span class="n">root</span><span class="p">[</span><span class="s">"Hello World"</span><span class="p">])</span>
|
||||||
<span class="p">{</span>
|
<span class="p">{</span>
|
||||||
<span class="n">writeln</span><span class="p">(</span><span class="n">word</span><span class="p">);</span>
|
<span class="n">writeln</span><span class="p">(</span><span class="n">word</span><span class="p">);</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
<span class="n">writeln</span><span class="p">(</span><span class="s">"The answer is "</span><span class="p">,</span> <span class="n">root</span><span class="p">[</span><span class="s">"Answer"</span><span class="p">].</span><span class="n">get</span><span class="p">!</span><span class="kt">int</span><span class="p">);</span>
|
<span class="n">writeln</span><span class="p">(</span><span class="s">"The answer is "</span><span class="p">,</span> <span class="n">root</span><span class="p">[</span><span class="s">"Answer"</span><span class="p">].</span><span class="n">get</span><span class="p">!</span><span class="kt">int</span><span class="p">);</span>
|
||||||
|
|
||||||
|
<span class="c1">//Dump the loaded document to output.yaml.</span>
|
||||||
|
<span class="n">Dumper</span><span class="p">(</span><span class="s">"output.yaml"</span><span class="p">).</span><span class="n">dump</span><span class="p">(</span><span class="n">root</span><span class="p">);</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -121,8 +127,8 @@ into the file:</p>
|
||||||
<h3>Explanation of the code<a class="headerlink" href="#explanation-of-the-code" title="Permalink to this headline">¶</a></h3>
|
<h3>Explanation of the code<a class="headerlink" href="#explanation-of-the-code" title="Permalink to this headline">¶</a></h3>
|
||||||
<p>First, we import the <em>yaml</em> module. This is the only module you need to import
|
<p>First, we import the <em>yaml</em> module. This is the only module you need to import
|
||||||
to use D:YAML - it automatically imports all needed modules.</p>
|
to use D:YAML - it automatically imports all needed modules.</p>
|
||||||
<p>Next we load the file using the <em>Loader.load()</em> method. <em>Loader</em> is the struct
|
<p>Next we load the file using the <em>Loader.load()</em> method. <em>Loader</em> is a struct
|
||||||
used for parsing YAML documents, and <em>load()</em> is a method that loads the file as
|
used for parsing YAML documents. The <em>load()</em> method loads the file as
|
||||||
<strong>one</strong> YAML document, or throws <em>YAMLException</em>, D:YAML exception type, if the
|
<strong>one</strong> YAML document, or throws <em>YAMLException</em>, 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
|
||||||
|
@ -144,6 +150,13 @@ cannot be converted to an integer.</p>
|
||||||
<p>The <em>Node.get()</em> method is used to get value of a scalar node, allowing to
|
<p>The <em>Node.get()</em> 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
|
specify type. D:YAML will try to return the scalar as this type, converting if
|
||||||
needed, throwing <em>YAMLException</em> if not possible.</p>
|
needed, throwing <em>YAMLException</em> if not possible.</p>
|
||||||
|
<p>Finally we dump the document we just read to <tt class="docutils literal"><span class="pre">output.yaml</span></tt> with the
|
||||||
|
<em>Dumper.dump()</em> method. <em>Dumper</em> is a struct used to dump YAML documents.
|
||||||
|
The <em>dump()</em> method writes one or more documents to a file, throwing
|
||||||
|
<em>YAMLException</em> if the file could not be written to.</p>
|
||||||
|
<p>D:YAML doesn’t preserve style information in documents, so even though
|
||||||
|
<tt class="docutils literal"><span class="pre">output.yaml</span></tt> will contain the same data as <tt class="docutils literal"><span class="pre">input.yaml</span></tt>, it might be
|
||||||
|
formatted differently. Comments are not preserved, either.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="compiling">
|
<div class="section" id="compiling">
|
||||||
<h3>Compiling<a class="headerlink" href="#compiling" title="Permalink to this headline">¶</a></h3>
|
<h3>Compiling<a class="headerlink" href="#compiling" title="Permalink to this headline">¶</a></h3>
|
||||||
|
@ -224,7 +237,7 @@ example in the <tt class="docutils literal"><span class="pre">example/getting_st
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||||
Last updated on Oct 14, 2011.
|
Last updated on Oct 15, 2011.
|
||||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||||
Last updated on Oct 14, 2011.
|
Last updated on Oct 15, 2011.
|
||||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later.
|
||||||
Constructor
|
Constructor
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
D:YAML uses the *Constructor* class to process each node to hold data type
|
D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process
|
||||||
corresponding to its tag. *Constructor* stores a function for each supported
|
each node to hold data type corresponding to its tag. *Constructor* stores a
|
||||||
tag to process it. These functions are supplied by the user using the
|
function for each supported tag to process it. These functions are supplied by
|
||||||
*addConstructor()* method. *Constructor* is then passed to *Loader*, which
|
the user using the *addConstructor()* method. *Constructor* is then passed to
|
||||||
parses YAML input.
|
*Loader*, which parses YAML input.
|
||||||
|
|
||||||
|
Struct types have no specific requirements for YAML support. Class types should
|
||||||
|
define the *opEquals()* operator, as this is used in equality comparisons of
|
||||||
|
nodes. Default class *opEquals()* compares references, which means two identical
|
||||||
|
objects might be considered unequal.
|
||||||
|
|
||||||
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,8 +116,8 @@ 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 data using our new tag. Create a file called input.yaml
|
Next, we need some YAML data using our new tag. Create a file called
|
||||||
with the following contents:
|
``input.yaml`` with the following contents:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
@ -167,7 +172,7 @@ 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*m and pass the *Constructor*
|
and ``!color-mapping`` tag. We construct a *Loader* and pass the *Constructor*
|
||||||
to it. We then load the YAML document, and finally, read the colors using
|
to it. We then load the YAML document, and finally, read the colors using
|
||||||
*get()* method to test if they were loaded as expected.
|
*get()* method to test if they were loaded as expected.
|
||||||
|
|
||||||
|
@ -181,12 +186,13 @@ 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 scalar tags using regular expressions. This is how default types such as
|
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
|
int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ class
|
||||||
resolution for the Color data type (in its scalar form).
|
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
|
We use the *addImplicitResolver()* method of *Resolver*, passing the tag,
|
||||||
expression the value must match to resolve to this tag, and a string of possible
|
regular expression the scalar must match to resolve to this tag, and a string of
|
||||||
starting characters of the value. Then we pass the *Resolver* to *Loader*.
|
possible starting characters of the scalar. Then we pass the *Resolver* to
|
||||||
|
*Loader*.
|
||||||
|
|
||||||
Note that resolvers added first override ones added later. If no resolver
|
Note that resolvers added first override ones added later. If no resolver
|
||||||
matches a scalar, YAML string tag is used. Therefore our custom values must not
|
matches a scalar, YAML string tag is used. Therefore our custom values must not
|
||||||
|
@ -199,8 +205,8 @@ Add this to your code to add implicit resolution of ``!color``.
|
||||||
//code from the previous example...
|
//code from the previous example...
|
||||||
|
|
||||||
auto resolver = new Resolver;
|
auto resolver = new Resolver;
|
||||||
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 = Loader("input.yaml");
|
auto loader = Loader("input.yaml");
|
||||||
|
|
||||||
|
@ -209,7 +215,7 @@ Add this to your code to add implicit resolution of ``!color``.
|
||||||
|
|
||||||
//code from the previous example...
|
//code from the previous example...
|
||||||
|
|
||||||
Now, change contents of input.yaml to this:
|
Now, change contents of ``input.yaml`` to this:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
@ -227,3 +233,107 @@ the example. If everything went as expected, it should report success.
|
||||||
|
|
||||||
You can find the complete code in the ``examples/resolver`` directory in the
|
You can find the complete code in the ``examples/resolver`` directory in the
|
||||||
D:YAML package.
|
D:YAML package.
|
||||||
|
|
||||||
|
|
||||||
|
-----------
|
||||||
|
Representer
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Now that you know how to load custom data types, it might also be useful to know
|
||||||
|
how to dump them. D:YAML uses the `Representer <../api/dyaml.representer.html>`_
|
||||||
|
class for this purpose.
|
||||||
|
|
||||||
|
*Representer* processes YAML nodes into plain mapping, sequence or scalar nodes
|
||||||
|
ready for output. Just like with *Constructor*, this is done by user specified
|
||||||
|
functions. These functions take references to a node to process and to the
|
||||||
|
*Representer*, and return the processed node.
|
||||||
|
|
||||||
|
Representer functions can be added with the *addRepresenter()* method. The
|
||||||
|
*Representer* is then passed to *Dumper*, which dumps YAML documents. Only one
|
||||||
|
representer can be added for a type. This is asserted in *addRepresenter()*
|
||||||
|
preconditions. By default, the default YAML types already have representer
|
||||||
|
functions, but you can disable them by constructing *Representer* with the
|
||||||
|
*useDefaultRepresenters* parameter set to false.
|
||||||
|
|
||||||
|
By default, tags are explicitly specified for all non-default types. If you
|
||||||
|
want the tags to be implicit, you can pass a *Resolver* that will resolve them
|
||||||
|
implicitly. Of course, you will then need to use an identical *Resolver* when
|
||||||
|
loading the output.
|
||||||
|
|
||||||
|
With the following code, we will add support for dumping the our Color type.
|
||||||
|
|
||||||
|
.. code-block:: d
|
||||||
|
|
||||||
|
Node representColor(ref Node node, Representer representer)
|
||||||
|
{
|
||||||
|
//The node is guaranteed to be Color as we add representer for Color.
|
||||||
|
Color color = node.get!Color;
|
||||||
|
|
||||||
|
static immutable hex = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
//Using the color format from the Constructor example.
|
||||||
|
string scalar;
|
||||||
|
foreach(channel; [color.red, color.green, color.blue])
|
||||||
|
{
|
||||||
|
scalar ~= hex[channel / 16];
|
||||||
|
scalar ~= hex[channel % 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Representing as a scalar, with custom tag to specify this data type.
|
||||||
|
return representer.representScalar("!color", scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
First we get the *Color* from the node. Then we convert it to a string with the
|
||||||
|
HTML-like format we've used before. Finally, we use the *representScalar()*
|
||||||
|
method of *Representer* to get a scalar node ready for output.
|
||||||
|
There are corresponding *representMapping()* and *representSequence()* methods
|
||||||
|
as well, with examples in the
|
||||||
|
`Resolver API documentation <../api/dyaml.resolver.html>`_.
|
||||||
|
|
||||||
|
Since a type can only have one representer function, we don't dump *Color* both
|
||||||
|
in the scalar and mapping formats we've used before. However, you can decide to
|
||||||
|
dump the node with different formats/tags in the representer function itself.
|
||||||
|
E.g. you could dump the Color as a mapping based on some arbitrary condition,
|
||||||
|
such as the color being white.
|
||||||
|
|
||||||
|
.. code-block:: d
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto representer = new Representer;
|
||||||
|
representer.addRepresenter!Color(&representColor);
|
||||||
|
|
||||||
|
auto resolver = new Resolver;
|
||||||
|
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
|
||||||
|
"0123456789abcdefABCDEF");
|
||||||
|
|
||||||
|
auto dumper = Dumper("output.yaml");
|
||||||
|
dumper.representer = representer;
|
||||||
|
dumper.resolver = resolver;
|
||||||
|
|
||||||
|
auto document = Node([Color(255, 0, 0),
|
||||||
|
Color(0, 255, 0),
|
||||||
|
Color(0, 0, 255)]);
|
||||||
|
|
||||||
|
dumper.dump(document);
|
||||||
|
}
|
||||||
|
catch(YAMLException e)
|
||||||
|
{
|
||||||
|
writeln(e.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
We construct a new *Representer*, and specify a representer function for the
|
||||||
|
*Color* (the template argument) type. We also construct a *Resolver*, same as in
|
||||||
|
the previous section, so the ``!color`` tag will be implicit. Of course,
|
||||||
|
identical *Resolver* would then have to be used when loading the file.
|
||||||
|
You don't need to do this if you want the tag to be explicit.
|
||||||
|
|
||||||
|
We construct a *Dumper* to file ``output.yaml`` and pass the *Representer* and
|
||||||
|
*Resolver* to it. Then, we create a simple node containing a sequence of colors
|
||||||
|
and finally, we dump it.
|
||||||
|
|
||||||
|
Source code for this section can be found in the ``examples/representer``
|
||||||
|
directory of the D:YAML package.
|
||||||
|
|
|
@ -72,7 +72,7 @@ Create a directory for your project and in that directory, create a file called
|
||||||
|
|
||||||
This will serve as input for our example.
|
This will serve as input for our example.
|
||||||
|
|
||||||
Now we need to parse it. Create a file called "main.d". Paste following code
|
Now we need to parse it. Create a file called ``main.d``. Paste following code
|
||||||
into the file:
|
into the file:
|
||||||
|
|
||||||
.. code-block:: d
|
.. code-block:: d
|
||||||
|
@ -82,12 +82,18 @@ into the file:
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
//Read the input.
|
||||||
Node root = Loader("input.yaml").load();
|
Node root = Loader("input.yaml").load();
|
||||||
|
|
||||||
|
//Display the data read.
|
||||||
foreach(string word; root["Hello World"])
|
foreach(string word; root["Hello World"])
|
||||||
{
|
{
|
||||||
writeln(word);
|
writeln(word);
|
||||||
}
|
}
|
||||||
writeln("The answer is ", root["Answer"].get!int);
|
writeln("The answer is ", root["Answer"].get!int);
|
||||||
|
|
||||||
|
//Dump the loaded document to output.yaml.
|
||||||
|
Dumper("output.yaml").dump(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,8 +104,8 @@ 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 *Loader.load()* method. *Loader* is the struct
|
Next we load the file using the *Loader.load()* method. *Loader* is a struct
|
||||||
used for parsing YAML documents, and *load()* is a method that loads the file as
|
used for parsing YAML documents. The *load()* method loads the file as
|
||||||
**one** YAML document, or throws *YAMLException*, D:YAML exception type, if the
|
**one** YAML document, or 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
|
||||||
|
@ -126,6 +132,15 @@ 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
|
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.
|
||||||
|
|
||||||
|
Finally we dump the document we just read to ``output.yaml`` with the
|
||||||
|
*Dumper.dump()* method. *Dumper* is a struct used to dump YAML documents.
|
||||||
|
The *dump()* method writes one or more documents to a file, throwing
|
||||||
|
*YAMLException* if the file could not be written to.
|
||||||
|
|
||||||
|
D:YAML doesn't preserve style information in documents, so even though
|
||||||
|
``output.yaml`` will contain the same data as ``input.yaml``, it might be
|
||||||
|
formatted differently. Comments are not preserved, either.
|
||||||
|
|
||||||
|
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
Compiling
|
Compiling
|
||||||
|
|
|
@ -152,7 +152,7 @@ struct Dumper
|
||||||
*/
|
*/
|
||||||
this(string filename)
|
this(string filename)
|
||||||
{
|
{
|
||||||
try{this(new File(filename));}
|
try{this(new File(filename, FileMode.OutNew));}
|
||||||
catch(StreamException e)
|
catch(StreamException e)
|
||||||
{
|
{
|
||||||
throw new YAMLException("Unable to use file for YAML dumping " ~ filename ~ " : " ~ e.msg);
|
throw new YAMLException("Unable to use file for YAML dumping " ~ filename ~ " : " ~ e.msg);
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* YAML node _representer.
|
* YAML node _representer. Prepares YAML nodes for output. A tutorial can be
|
||||||
|
* found $(LINK2 ../tutorials/custom_types.html, here).
|
||||||
*
|
*
|
||||||
* Code based on $(LINK2 http://www.pyyaml.org, PyYAML).
|
* Code based on $(LINK2 http://www.pyyaml.org, PyYAML).
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,10 +3,16 @@ import yaml;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
yaml.Node root = Loader("input.yaml").load();
|
//Read the input.
|
||||||
|
Node root = Loader("input.yaml").load();
|
||||||
|
|
||||||
|
//Display the data read.
|
||||||
foreach(string word; root["Hello World"])
|
foreach(string word; root["Hello World"])
|
||||||
{
|
{
|
||||||
writeln(word);
|
writeln(word);
|
||||||
}
|
}
|
||||||
writeln("The answer is ", root["Answer"].get!int);
|
writeln("The answer is ", root["Answer"].get!int);
|
||||||
|
|
||||||
|
//Dump the loaded document to output.yaml.
|
||||||
|
Dumper("output.yaml").dump(root);
|
||||||
}
|
}
|
||||||
|
|
2
examples/representer/Makefile
Normal file
2
examples/representer/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
main:
|
||||||
|
dmd -w -I../../ -L-L../../ -L-ldyaml main.d
|
55
examples/representer/main.d
Normal file
55
examples/representer/main.d
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import std.stdio;
|
||||||
|
import yaml;
|
||||||
|
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
ubyte red;
|
||||||
|
ubyte green;
|
||||||
|
ubyte blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node representColor(ref Node node, Representer representer)
|
||||||
|
{
|
||||||
|
//The node is guaranteed to be Color as we add representer for Color.
|
||||||
|
Color color = node.get!Color;
|
||||||
|
|
||||||
|
static immutable hex = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
//Using the color format from the Constructor example.
|
||||||
|
string scalar;
|
||||||
|
foreach(channel; [color.red, color.green, color.blue])
|
||||||
|
{
|
||||||
|
scalar ~= hex[channel / 16];
|
||||||
|
scalar ~= hex[channel % 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Representing as a scalar, with custom tag to specify this data type.
|
||||||
|
return representer.representScalar("!color", scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto representer = new Representer;
|
||||||
|
representer.addRepresenter!Color(&representColor);
|
||||||
|
|
||||||
|
auto resolver = new Resolver;
|
||||||
|
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
|
||||||
|
"0123456789abcdefABCDEF");
|
||||||
|
|
||||||
|
auto dumper = Dumper("output.yaml");
|
||||||
|
dumper.representer = representer;
|
||||||
|
dumper.resolver = resolver;
|
||||||
|
|
||||||
|
auto document = Node([Color(255, 0, 0),
|
||||||
|
Color(0, 255, 0),
|
||||||
|
Color(0, 0, 255)]);
|
||||||
|
|
||||||
|
dumper.dump(document);
|
||||||
|
}
|
||||||
|
catch(YAMLException e)
|
||||||
|
{
|
||||||
|
writeln(e.msg);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue