dyaml/doc/html/tutorials/custom_types.html
2011-10-29 20:43:30 +02:00

375 lines
34 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Custom YAML data types &mdash; D:YAML v0.3 documentation</title>
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '0.3',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<link rel="top" title="D:YAML v0.3 documentation" href="../index.html" />
<link rel="next" title="YAML syntax" href="yaml_syntax.html" />
<link rel="prev" title="Getting started" href="getting_started.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="yaml_syntax.html" title="YAML syntax"
accesskey="N">next</a></li>
<li class="right" >
<a href="getting_started.html" title="Getting started"
accesskey="P">previous</a> |</li>
<li><a href="../index.html">D:YAML v0.3 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="custom-yaml-data-types">
<h1>Custom YAML data types<a class="headerlink" href="#custom-yaml-data-types" title="Permalink to this headline"></a></h1>
<p>Sometimes you need to serialize complex data types such as classes. To do this
you could use plain nodes such as mappings with class data members. However,
YAML supports custom types with identifiers called <em>tags</em>. That is the topic of
this tutorial.</p>
<p>Each YAML node has a tag specifying its type. For instance: strings use the tag
<tt class="docutils literal"><span class="pre">tag:yaml.org,2002:str</span></tt>. Tags of most default types are <em>implicitly resolved</em>
during parsing, so you don&#8217;t need to specify tag for each float, integer, etc.
D:YAML can also 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 <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
functions to process each supported tag. These are supplied by the user using
the <em>addConstructorXXX()</em> methods, where <em>XXX</em> is <em>Scalar</em>, <em>Sequence</em> or
<em>Mapping</em>. <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. (Default struct <em>opEquals()</em> compares
byte-by-byte, sometimes you might want to override that as well.)</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>
<span class="p">{</span>
<span class="kt">ubyte</span> <span class="n">red</span><span class="p">;</span>
<span class="kt">ubyte</span> <span class="n">green</span><span class="p">;</span>
<span class="kt">ubyte</span> <span class="n">blue</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>First, we need a function to construct our data type. It must take two <em>Mark</em>
structs, which store position of the node in the file, and a reference to <em>Node</em>
to construct from. The node is guaranteed to contain either a <em>string</em>, an array
of <em>Node</em> or of <em>Node.Pair</em>, depending on whether we&#8217;re constructing our value
from a scalar, sequence, or mapping, respectively. In this tutorial, we have
functions to construct a color from a scalar, using CSS-like format, RRGGBB, or
from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code
of these functions:</p>
<div class="highlight-d"><div class="highlight"><pre><span class="n">Color</span> <span class="n">constructColorScalar</span><span class="p">(</span><span class="n">Mark</span> <span class="n">start</span><span class="p">,</span> <span class="n">Mark</span> <span class="n">end</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="p">{</span>
<span class="nb">string</span> <span class="n">value</span> <span class="p">=</span> <span class="n">node</span><span class="p">.</span><span class="n">as</span><span class="p">!</span><span class="nb">string</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">length</span> <span class="p">!=</span> <span class="mi">6</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">&quot;Invalid color: &quot;</span> <span class="p">~</span> <span class="n">value</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">//We don&#39;t need to check for uppercase chars this way.</span>
<span class="n">value</span> <span class="p">=</span> <span class="n">value</span><span class="p">.</span><span class="n">toLower</span><span class="p">();</span>
<span class="c1">//Get value of a hex digit.</span>
<span class="kt">uint</span> <span class="n">hex</span><span class="p">(</span><span class="kt">char</span> <span class="n">c</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span><span class="p">(!</span><span class="n">std</span><span class="p">.</span><span class="n">ascii</span><span class="p">.</span><span class="n">isHexDigit</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">&quot;Invalid color: &quot;</span> <span class="p">~</span> <span class="n">value</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="n">std</span><span class="p">.</span><span class="n">ascii</span><span class="p">.</span><span class="n">isDigit</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">c</span> <span class="p">-</span> <span class="sc">&#39;0&#39;</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">c</span> <span class="p">-</span> <span class="sc">&#39;a&#39;</span> <span class="p">+</span> <span class="mi">10</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">Color</span> <span class="n">result</span><span class="p">;</span>
<span class="n">result</span><span class="p">.</span><span class="n">red</span> <span class="p">=</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)(</span><span class="mi">16</span> <span class="p">*</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">+</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span>
<span class="n">result</span><span class="p">.</span><span class="n">green</span> <span class="p">=</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)(</span><span class="mi">16</span> <span class="p">*</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="p">+</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">3</span><span class="p">]));</span>
<span class="n">result</span><span class="p">.</span><span class="n">blue</span> <span class="p">=</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)(</span><span class="mi">16</span> <span class="p">*</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span> <span class="p">+</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">5</span><span class="p">]));</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">Color</span> <span class="n">constructColorMapping</span><span class="p">(</span><span class="n">Mark</span> <span class="n">start</span><span class="p">,</span> <span class="n">Mark</span> <span class="n">end</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="p">{</span>
<span class="kt">ubyte</span> <span class="n">r</span><span class="p">,</span><span class="n">g</span><span class="p">,</span><span class="n">b</span><span class="p">;</span>
<span class="c1">//Might throw if a value is missing is not an integer, or is out of range.</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="n">r</span> <span class="p">=</span> <span class="n">node</span><span class="p">[</span><span class="s">&quot;r&quot;</span><span class="p">].</span><span class="n">as</span><span class="p">!</span><span class="kt">ubyte</span><span class="p">;</span>
<span class="n">g</span> <span class="p">=</span> <span class="n">node</span><span class="p">[</span><span class="s">&quot;g&quot;</span><span class="p">].</span><span class="n">as</span><span class="p">!</span><span class="kt">ubyte</span><span class="p">;</span>
<span class="n">b</span> <span class="p">=</span> <span class="n">node</span><span class="p">[</span><span class="s">&quot;b&quot;</span><span class="p">].</span><span class="n">as</span><span class="p">!</span><span class="kt">ubyte</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">catch</span><span class="p">(</span><span class="n">NodeException</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">&quot;Invalid color: &quot;</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="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">Color</span><span class="p">(</span><span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)</span><span class="n">r</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)</span><span class="n">g</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)</span><span class="n">b</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<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>
<span class="l-Scalar-Plain">mapping-orange</span><span class="p-Indicator">:</span>
<span class="kt">!color-mapping</span>
<span class="l-Scalar-Plain">r</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
<span class="l-Scalar-Plain">g</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
<span class="l-Scalar-Plain">b</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">0</span>
</pre></div>
</div>
<p>You can see that we&#8217;re using tag <tt class="docutils literal"><span class="pre">!color</span></tt> for scalar colors, and
<tt class="docutils literal"><span class="pre">!color-mapping</span></tt> for colors expressed as mappings.</p>
<p>Finally, the code to put it all together:</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">auto</span> <span class="n">red</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="k">auto</span> <span class="n">orange</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">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="k">auto</span> <span class="n">constructor</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Constructor</span><span class="p">;</span>
<span class="c1">//both functions handle the same tag, but one handles scalar, one mapping.</span>
<span class="n">constructor</span><span class="p">.</span><span class="n">addConstructorScalar</span><span class="p">(</span><span class="s">&quot;!color&quot;</span><span class="p">,</span> <span class="p">&amp;</span><span class="n">constructColorScalar</span><span class="p">);</span>
<span class="n">constructor</span><span class="p">.</span><span class="n">addConstructorMapping</span><span class="p">(</span><span class="s">&quot;!color-mapping&quot;</span><span class="p">,</span> <span class="p">&amp;</span><span class="n">constructColorMapping</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>
<span class="n">loader</span><span class="p">.</span><span class="n">constructor</span> <span class="p">=</span> <span class="n">constructor</span><span class="p">;</span>
<span class="k">auto</span> <span class="n">root</span> <span class="p">=</span> <span class="n">loader</span><span class="p">.</span><span class="n">load</span><span class="p">();</span>
<span class="k">if</span><span class="p">(</span><span class="n">root</span><span class="p">[</span><span class="s">&quot;scalar-red&quot;</span><span class="p">].</span><span class="n">as</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">red</span> <span class="p">&amp;&amp;</span>
<span class="n">root</span><span class="p">[</span><span class="s">&quot;mapping-red&quot;</span><span class="p">].</span><span class="n">as</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">red</span> <span class="p">&amp;&amp;</span>
<span class="n">root</span><span class="p">[</span><span class="s">&quot;scalar-orange&quot;</span><span class="p">].</span><span class="n">as</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">orange</span> <span class="p">&amp;&amp;</span>
<span class="n">root</span><span class="p">[</span><span class="s">&quot;mapping-orange&quot;</span><span class="p">].</span><span class="n">as</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">orange</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">writeln</span><span class="p">(</span><span class="s">&quot;SUCCESS&quot;</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</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="n">writeln</span><span class="p">(</span><span class="s">&quot;FAILURE&quot;</span><span class="p">);</span>
<span class="p">}</span>
</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</em> and pass the <em>Constructor</em>
to it. We then load the YAML document, and finally, read the colors 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
<tt class="docutils literal"><span class="pre">examples/constructor</span></tt> directory in the D:YAML package.</p>
</div>
<div class="section" id="resolver">
<h2>Resolver<a class="headerlink" href="#resolver" title="Permalink to this headline"></a></h2>
<p>Specifying tag for every color can be tedious. D:YAML can implicitly resolve
scalar tags using regular expressions. This is how default types 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>
<p>Add this to your code to add implicit resolution of <tt class="docutils literal"><span class="pre">!color</span></tt>.</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="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>
<span class="n">loader</span><span class="p">.</span><span class="n">constructor</span> <span class="p">=</span> <span class="n">constructor</span><span class="p">;</span>
<span class="n">loader</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="c1">//code from the previous example...</span>
</pre></div>
</div>
<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>
<span class="l-Scalar-Plain">mapping-orange</span><span class="p-Indicator">:</span>
<span class="kt">!color-mapping</span>
<span class="l-Scalar-Plain">r</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
<span class="l-Scalar-Plain">g</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
<span class="l-Scalar-Plain">b</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">0</span>
</pre></div>
</div>
<p>We no longer need to specify the tag for scalar color values. Compile and test
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 can load custom data types, it might be good 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
function per type can be specified. This is asserted in <em>addRepresenter()</em>
preconditions. Default YAML types already have representer functions specified,
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 output for all non-default types. To make dumped
tags implicit, you can pass a <em>Resolver</em> that will resolve them implicitly. Of
course, you will 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">as</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
CSS-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>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/logo210.png" alt="Logo"/>
</a></p>
<h3><a href="../index.html">Table Of Contents</a></h3>
<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="#resolver">Resolver</a></li>
<li><a class="reference internal" href="#representer">Representer</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="yaml_syntax.html" title="YAML syntax"
>next</a></li>
<li class="right" >
<a href="getting_started.html" title="Getting started"
>previous</a> |</li>
<li><a href="../index.html">D:YAML v0.3 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 29, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div>
</body>
</html>