Fixed a bug which prevented dumping to file. Updated tutorials

and example with new information.
This commit is contained in:
Ferdinand Majerech 2011-10-15 16:31:23 +02:00
parent 23290239a7
commit 210091a75f
20 changed files with 493 additions and 68 deletions

Binary file not shown.

View file

@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later.
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 are supplied by the user using the
*addConstructor()* method. *Constructor* is then passed to *Loader*, which
parses YAML input.
D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ 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 are supplied by
the user using the *addConstructor()* method. *Constructor* is then passed to
*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
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);
}
Next, we need some YAML data using our new tag. Create a file called input.yaml
with the following contents:
Next, we need some YAML data using our new tag. Create a file called
``input.yaml`` with the following contents:
.. 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``
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
*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
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).
int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ 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
expression the value must match to resolve to this tag, and a string of possible
starting characters of the value. Then we pass the *Resolver* to *Loader*.
We use the *addImplicitResolver()* method of *Resolver*, passing the tag,
regular expression the scalar must match to resolve to this tag, and a string of
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
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...
auto resolver = new Resolver;
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}",
"0123456789abcdefABCDEF"));
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
"0123456789abcdefABCDEF");
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...
Now, change contents of input.yaml to this:
Now, change contents of ``input.yaml`` to this:
.. 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
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.

View file

@ -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.
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:
.. code-block:: d
@ -82,12 +82,18 @@ into the file:
void main()
{
//Read the input.
Node root = Loader("input.yaml").load();
//Display the data read.
foreach(string word; root["Hello World"])
{
writeln(word);
}
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
to use D:YAML - it automatically imports all needed modules.
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
Next we load the file using the *Loader.load()* method. *Loader* is a struct
used for parsing YAML documents. The *load()* method loads the file as
**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
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
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

View file

@ -39,7 +39,8 @@
<div id="content">
<h1>dyaml.representer</h1>
<!-- 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>Code based on <a href="http://www.pyyaml.org">PyYAML</a>.</p>

View file

@ -138,7 +138,7 @@ struct appears in Phobos.</p>
</div>
<div class="footer">
&copy; 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.
</div>
</body>

View file

@ -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-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#representer">Representer</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="tutorials/yaml_syntax.html">YAML syntax</a><ul>
@ -103,7 +104,7 @@
</div>
<div class="footer">
&copy; 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.
</div>
</body>

View file

@ -87,7 +87,7 @@
</div>
<div class="footer">
&copy; 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.
</div>
</body>

File diff suppressed because one or more lines are too long

View file

@ -57,11 +57,15 @@ during parsing, so you don&#8217;t need to specify tag for each float, integer,
It is also possible to implicitly resolve custom tags, as we will show later.</p>
<div class="section" id="constructor">
<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
corresponding to its tag. <em>Constructor</em> stores a function for each supported
tag to process it. These functions are supplied by the user using the
<em>addConstructor()</em> method. <em>Constructor</em> is then passed to <em>Loader</em>, which
parses YAML input.</p>
<p>D:YAML uses the <a class="reference external" href="../api/dyaml.constructor.html">Constructor</a> class to process
each node to hold data type corresponding to its tag. <em>Constructor</em> stores a
function for each supported tag to process it. These functions are supplied by
the user using the <em>addConstructor()</em> method. <em>Constructor</em> is then passed to
<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
following struct:</p>
<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>
</pre></div>
</div>
<p>Next, we need some YAML data using our new tag. Create a file called input.yaml
with the following contents:</p>
<p>Next, we need some YAML data using our new tag. Create a file called
<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>
<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>
@ -197,7 +201,7 @@ with the following contents:</p>
</pre></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>
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
<em>get()</em> method to test if they were loaded as expected.</p>
<p>You can find the source code for what we&#8217;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>
<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
int are resolved. We will use the <em>Resolver</em> class 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
expression the value must match to resolve to this tag, and a string of possible
starting characters of the value. Then we pass the <em>Resolver</em> to <em>Loader</em>.</p>
int are resolved. We will use the <a class="reference external" href="../api/dyaml.resolver.html">Resolver</a> class
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 expression the scalar must match to resolve to this tag, and a string of
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
matches a scalar, YAML string tag is used. Therefore our custom values must not
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>
<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">&quot;!color&quot;</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">&quot;[0-9a-fA-F]{6}&quot;</span><span class="p">,</span>
<span class="s">&quot;0123456789abcdefABCDEF&quot;</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">&quot;!color&quot;</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">&quot;[0-9a-fA-F]{6}&quot;</span><span class="p">),</span>
<span class="s">&quot;0123456789abcdefABCDEF&quot;</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">&quot;input.yaml&quot;</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>
</pre></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>
<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>
@ -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
D:YAML package.</p>
</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">&quot;0123456789ABCDEF&quot;</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">&quot;!color&quot;</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&#8217;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&#8217;t dump <em>Color</em> both
in the scalar and mapping formats we&#8217;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">(&amp;</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">&quot;!color&quot;</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">&quot;[0-9a-fA-F]{6}&quot;</span><span class="p">),</span>
<span class="s">&quot;0123456789abcdefABCDEF&quot;</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">&quot;output.yaml&quot;</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&#8217;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>
@ -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="#constructor">Constructor</a></li>
<li><a class="reference internal" href="#resolver">Resolver</a></li>
<li><a class="reference internal" href="#representer">Representer</a></li>
</ul>
</li>
</ul>
@ -284,7 +380,7 @@ D:YAML package.</p>
</div>
<div class="footer">
&copy; 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.
</div>
</body>

View file

@ -101,19 +101,25 @@ To do this on Unix/Linux, use the following command:</p>
</pre></div>
</div>
<p>This will serve as input for our example.</p>
<p>Now we need to parse it. Create a file called &#8220;main.d&#8221;. 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>
<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="kt">void</span> <span class="n">main</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">&quot;input.yaml&quot;</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">&quot;Hello World&quot;</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="p">}</span>
<span class="n">writeln</span><span class="p">(</span><span class="s">&quot;The answer is &quot;</span><span class="p">,</span> <span class="n">root</span><span class="p">[</span><span class="s">&quot;Answer&quot;</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">&quot;output.yaml&quot;</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>
</pre></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>
<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>
<p>Next we load the file using the <em>Loader.load()</em> method. <em>Loader</em> is the struct
used for parsing YAML documents, and <em>load()</em> is a method that loads the file as
<p>Next we load the file using the <em>Loader.load()</em> method. <em>Loader</em> is a struct
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
file could not be parsed or does not contain exactly one document. Note that we
don&#8217;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
specify type. D:YAML will try to return the scalar as this type, converting if
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&#8217;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 class="section" id="compiling">
<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 class="footer">
&copy; 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.
</div>
</body>

View file

@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).</p>
</div>
<div class="footer">
&copy; 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.
</div>
</body>

View file

@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later.
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 are supplied by the user using the
*addConstructor()* method. *Constructor* is then passed to *Loader*, which
parses YAML input.
D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ 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 are supplied by
the user using the *addConstructor()* method. *Constructor* is then passed to
*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
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);
}
Next, we need some YAML data using our new tag. Create a file called input.yaml
with the following contents:
Next, we need some YAML data using our new tag. Create a file called
``input.yaml`` with the following contents:
.. 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``
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
*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
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).
int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ 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
expression the value must match to resolve to this tag, and a string of possible
starting characters of the value. Then we pass the *Resolver* to *Loader*.
We use the *addImplicitResolver()* method of *Resolver*, passing the tag,
regular expression the scalar must match to resolve to this tag, and a string of
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
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...
auto resolver = new Resolver;
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}",
"0123456789abcdefABCDEF"));
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
"0123456789abcdefABCDEF");
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...
Now, change contents of input.yaml to this:
Now, change contents of ``input.yaml`` to this:
.. 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
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.

View file

@ -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.
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:
.. code-block:: d
@ -82,12 +82,18 @@ into the file:
void main()
{
//Read the input.
Node root = Loader("input.yaml").load();
//Display the data read.
foreach(string word; root["Hello World"])
{
writeln(word);
}
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
to use D:YAML - it automatically imports all needed modules.
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
Next we load the file using the *Loader.load()* method. *Loader* is a struct
used for parsing YAML documents. The *load()* method loads the file as
**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
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
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

View file

@ -152,7 +152,7 @@ struct Dumper
*/
this(string filename)
{
try{this(new File(filename));}
try{this(new File(filename, FileMode.OutNew));}
catch(StreamException e)
{
throw new YAMLException("Unable to use file for YAML dumping " ~ filename ~ " : " ~ e.msg);

View file

@ -5,7 +5,8 @@
// 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).
*/

View file

@ -3,10 +3,16 @@ import yaml;
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"])
{
writeln(word);
}
writeln("The answer is ", root["Answer"].get!int);
//Dump the loaded document to output.yaml.
Dumper("output.yaml").dump(root);
}

View file

@ -0,0 +1,2 @@
main:
dmd -w -I../../ -L-L../../ -L-ldyaml main.d

View 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);
}
}