Simplified the Constructor API.
This commit is contained in:
parent
ab154480fb
commit
fbc962623d
Binary file not shown.
Binary file not shown.
|
@ -3,13 +3,13 @@ Custom YAML data types
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Sometimes you need to serialize complex data types such as classes. To do this
|
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,
|
you could use plain nodes such as mappings with class data members. YAML also
|
||||||
YAML supports custom types with identifiers called *tags*. That is the topic of
|
supports custom types with identifiers called *tags*. That is the topic of this
|
||||||
this tutorial.
|
tutorial.
|
||||||
|
|
||||||
Each YAML node has a tag specifying its type. For instance: strings use the tag
|
Each YAML node has a tag specifying its type. For instance: strings use the tag
|
||||||
``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved*
|
``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved*
|
||||||
during parsing, so you don't need to specify tag for each float, integer, etc.
|
during parsing - you don't need to specify tag for each float, integer, etc.
|
||||||
D:YAML can also implicitly resolve custom tags, as we will show later.
|
D:YAML can also implicitly resolve custom tags, as we will show later.
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ the *addConstructorXXX()* methods, where *XXX* is *Scalar*, *Sequence* or
|
||||||
*Mapping*. *Constructor* is then passed to *Loader*, which parses YAML input.
|
*Mapping*. *Constructor* is then passed to *Loader*, which parses YAML input.
|
||||||
|
|
||||||
Struct types have no specific requirements for YAML support. Class types should
|
Struct types have no specific requirements for YAML support. Class types should
|
||||||
define the *opEquals()* operator, as this is used in equality comparisons of
|
define the *opEquals()* operator - this is used in equality comparisons of
|
||||||
nodes. Default class *opEquals()* compares references, which means two identical
|
nodes. Default class *opEquals()* compares references, which means two identical
|
||||||
objects might be considered unequal. (Default struct *opEquals()* compares
|
objects might be considered unequal. (Default struct *opEquals()* compares
|
||||||
byte-by-byte, sometimes you might want to override that as well.)
|
byte-by-byte, sometimes you might want to override that as well.)
|
||||||
|
@ -41,24 +41,26 @@ following struct:
|
||||||
ubyte blue;
|
ubyte blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
First, we need a function to construct our data type. It must take two *Mark*
|
First, we need a function to construct our data type. The function will take a
|
||||||
structs, which store position of the node in the file, and a reference to *Node*
|
reference to *Node* to construct from. The node is guaranteed to contain either
|
||||||
to construct from. The node is guaranteed to contain either a *string*, an array
|
a *string*, an array of *Node* or of *Node.Pair*, depending on whether we're
|
||||||
of *Node* or of *Node.Pair*, depending on whether we're constructing our value
|
constructing our value from a scalar, sequence, or mapping, respectively.
|
||||||
from a scalar, sequence, or mapping, respectively. In this tutorial, we have
|
If this function throws any exception, D:YAML handles it and adds its message
|
||||||
functions to construct a color from a scalar, using CSS-like format, RRGGBB, or
|
to a *YAMLException* that will be thrown when loading the file.
|
||||||
from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code
|
|
||||||
of these functions:
|
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:
|
||||||
|
|
||||||
.. code-block:: d
|
.. code-block:: d
|
||||||
|
|
||||||
Color constructColorScalar(Mark start, Mark end, ref Node node)
|
Color constructColorScalar(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string;
|
string value = node.as!string;
|
||||||
|
|
||||||
if(value.length != 6)
|
if(value.length != 6)
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
//We don't need to check for uppercase chars this way.
|
//We don't need to check for uppercase chars this way.
|
||||||
value = value.toLower();
|
value = value.toLower();
|
||||||
|
@ -68,7 +70,7 @@ of these functions:
|
||||||
{
|
{
|
||||||
if(!std.ascii.isHexDigit(c))
|
if(!std.ascii.isHexDigit(c))
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std.ascii.isDigit(c))
|
if(std.ascii.isDigit(c))
|
||||||
|
@ -86,21 +88,16 @@ of these functions:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color constructColorMapping(Mark start, Mark end, ref Node node)
|
Color constructColorMapping(ref Node node)
|
||||||
{
|
{
|
||||||
ubyte r,g,b;
|
ubyte r,g,b;
|
||||||
|
|
||||||
//Might throw if a value is missing is not an integer, or is out of range.
|
//Might throw if a value is missing is not an integer, or is out of range.
|
||||||
try
|
//If this happens, D:YAML will handle the exception and use its message
|
||||||
{
|
//in a YAMLException thrown when loading.
|
||||||
r = node["r"].as!ubyte;
|
r = node["r"].as!ubyte;
|
||||||
g = node["g"].as!ubyte;
|
g = node["g"].as!ubyte;
|
||||||
b = node["b"].as!ubyte;
|
b = node["b"].as!ubyte;
|
||||||
}
|
|
||||||
catch(NodeException e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Invalid color: " ~ e.msg, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,14 +95,20 @@
|
||||||
</table></div>
|
</table></div>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">void <a name="addConstructorScalar"></a><span class="ddoc_psymbol">addConstructorScalar</span>(T)(in string <b>tag</b>, T function(Mark, Mark, ref Node) <b>ctor</b>);
|
<dt class="d_decl">void <a name="addConstructorScalar"></a><span class="ddoc_psymbol">addConstructorScalar</span>(T)(in string <b>tag</b>, T function(ref Node) <b>ctor</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Add a constructor function from scalar.
|
<dd><p>Add a constructor function from scalar.
|
||||||
</p>
|
</p>
|
||||||
<p>The function must take two Marks (start and end positions of
|
<p>The function must take a reference to Node to construct from.
|
||||||
the node in file) and a reference to Node to construct from.
|
|
||||||
The node contains a string for scalars, Node[] for sequences and
|
The node contains a string for scalars, Node[] for sequences and
|
||||||
Node.Pair[] for mappings.
|
Node.Pair[] for mappings.
|
||||||
|
<br>
|
||||||
|
|
||||||
|
Any exception thrown by this function will be caught by D:YAML and
|
||||||
|
its message will be added to a YAMLException that will also tell the
|
||||||
|
user which type failed to construct, and position in the file.
|
||||||
|
<br>
|
||||||
|
|
||||||
The value returned by this function will be stored in the resulting node.
|
The value returned by this function will be stored in the resulting node.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
@ -124,20 +130,13 @@
|
||||||
<span class="d_keyword">int</span> x, y, z;
|
<span class="d_keyword">int</span> x, y, z;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructScalar(Mark start, Mark end, <span class="d_keyword">ref</span> Node node)
|
MyStruct constructMyStructScalar(<span class="d_keyword">ref</span> Node node)
|
||||||
{
|
{
|
||||||
<span class="d_comment">//Guaranteed to be string as we construct from scalar.
|
<span class="d_comment">//Guaranteed to be string as we construct from scalar.
|
||||||
</span> <span class="d_comment">//!mystruct x:y:z
|
</span> <span class="d_comment">//!mystruct x:y:z
|
||||||
</span> <span class="d_keyword">auto</span> parts = node.as!string().split(<span class="d_string">":"</span>);
|
</span> <span class="d_keyword">auto</span> parts = node.as!string().split(<span class="d_string">":"</span>);
|
||||||
<span class="d_keyword">try</span>
|
<span class="d_comment">//If this throws, the D:YAML will handle it and throw a YAMLException.
|
||||||
{
|
</span> <span class="d_keyword">return</span> MyStruct(to!<span class="d_keyword">int</span>(parts[0]), to!<span class="d_keyword">int</span>(parts[1]), to!<span class="d_keyword">int</span>(parts[2]));
|
||||||
<span class="d_keyword">return</span> MyStruct(to!<span class="d_keyword">int</span>(parts[0]), to!<span class="d_keyword">int</span>(parts[1]), to!<span class="d_keyword">int</span>(parts[2]));
|
|
||||||
}
|
|
||||||
<span class="d_keyword">catch</span>(Exception e)
|
|
||||||
{
|
|
||||||
<span class="d_keyword">throw</span> <span class="d_keyword">new</span> ConstructorException(<span class="d_string">"Could not construct MyStruct: "</span> ~ e.msg,
|
|
||||||
start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<span class="d_keyword">void</span> main()
|
<span class="d_keyword">void</span> main()
|
||||||
|
@ -152,7 +151,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">void <a name="addConstructorSequence"></a><span class="ddoc_psymbol">addConstructorSequence</span>(T)(in string <b>tag</b>, T function(Mark, Mark, ref Node) <b>ctor</b>);
|
<dt class="d_decl">void <a name="addConstructorSequence"></a><span class="ddoc_psymbol">addConstructorSequence</span>(T)(in string <b>tag</b>, T function(ref Node) <b>ctor</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Add a constructor function from sequence.
|
<dd><p>Add a constructor function from sequence.
|
||||||
</p>
|
</p>
|
||||||
|
@ -169,19 +168,11 @@
|
||||||
<span class="d_keyword">int</span> x, y, z;
|
<span class="d_keyword">int</span> x, y, z;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructSequence(Mark start, Mark end, <span class="d_keyword">ref</span> Node node)
|
MyStruct constructMyStructSequence(<span class="d_keyword">ref</span> Node node)
|
||||||
{
|
{
|
||||||
<span class="d_comment">//node is guaranteed to be sequence.
|
<span class="d_comment">//node is guaranteed to be sequence.
|
||||||
</span> <span class="d_comment">//!mystruct [x, y, z]
|
</span> <span class="d_comment">//!mystruct [x, y, z]
|
||||||
</span> <span class="d_keyword">try</span>
|
</span> <span class="d_keyword">return</span> MyStruct(node[0].as!<span class="d_keyword">int</span>, node[1].as!<span class="d_keyword">int</span>, node[2].as!<span class="d_keyword">int</span>);
|
||||||
{
|
|
||||||
<span class="d_keyword">return</span> MyStruct(node[0].as!<span class="d_keyword">int</span>, node[1].as!<span class="d_keyword">int</span>, node[2].as!<span class="d_keyword">int</span>);
|
|
||||||
}
|
|
||||||
<span class="d_keyword">catch</span>(NodeException e)
|
|
||||||
{
|
|
||||||
<span class="d_keyword">throw</span> <span class="d_keyword">new</span> ConstructorException(<span class="d_string">"Could not construct MyStruct: "</span> ~ e.msg,
|
|
||||||
start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<span class="d_keyword">void</span> main()
|
<span class="d_keyword">void</span> main()
|
||||||
|
@ -196,7 +187,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">void <a name="addConstructorMapping"></a><span class="ddoc_psymbol">addConstructorMapping</span>(T)(in string <b>tag</b>, T function(Mark, Mark, ref Node) <b>ctor</b>);
|
<dt class="d_decl">void <a name="addConstructorMapping"></a><span class="ddoc_psymbol">addConstructorMapping</span>(T)(in string <b>tag</b>, T function(ref Node) <b>ctor</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Add a constructor function from a mapping.
|
<dd><p>Add a constructor function from a mapping.
|
||||||
</p>
|
</p>
|
||||||
|
@ -213,19 +204,11 @@
|
||||||
<span class="d_keyword">int</span> x, y, z;
|
<span class="d_keyword">int</span> x, y, z;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructMapping(Mark start, Mark end, <span class="d_keyword">ref</span> Node node)
|
MyStruct constructMyStructMapping(<span class="d_keyword">ref</span> Node node)
|
||||||
{
|
{
|
||||||
<span class="d_comment">//node is guaranteed to be mapping.
|
<span class="d_comment">//node is guaranteed to be mapping.
|
||||||
</span> <span class="d_comment">//!mystruct {"x": x, "y": y, "z": z}
|
</span> <span class="d_comment">//!mystruct {"x": x, "y": y, "z": z}
|
||||||
</span> <span class="d_keyword">try</span>
|
</span> <span class="d_keyword">return</span> MyStruct(node[<span class="d_string">"x"</span>].as!<span class="d_keyword">int</span>, node[<span class="d_string">"y"</span>].as!<span class="d_keyword">int</span>, node[<span class="d_string">"z"</span>].as!<span class="d_keyword">int</span>);
|
||||||
{
|
|
||||||
<span class="d_keyword">return</span> MyStruct(node[<span class="d_string">"x"</span>].as!<span class="d_keyword">int</span>, node[<span class="d_string">"y"</span>].as!<span class="d_keyword">int</span>, node[<span class="d_string">"z"</span>].as!<span class="d_keyword">int</span>);
|
|
||||||
}
|
|
||||||
<span class="d_keyword">catch</span>(NodeException e)
|
|
||||||
{
|
|
||||||
<span class="d_keyword">throw</span> <span class="d_keyword">new</span> ConstructorException(<span class="d_string">"Could not construct MyStruct: "</span> ~ e.msg,
|
|
||||||
start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<span class="d_keyword">void</span> main()
|
<span class="d_keyword">void</span> main()
|
||||||
|
@ -242,72 +225,72 @@
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">YAMLNull <a name="constructNull"></a><span class="ddoc_psymbol">constructNull</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">YAMLNull <a name="constructNull"></a><span class="ddoc_psymbol">constructNull</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a <b>null</b> <b>node</b>.</p>
|
<dd><p>Construct a <b>null</b> <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">YAMLMerge <a name="constructMerge"></a><span class="ddoc_psymbol">constructMerge</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">YAMLMerge <a name="constructMerge"></a><span class="ddoc_psymbol">constructMerge</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a merge <b>node</b> - a <b>node</b> that merges another <b>node</b> into a mapping.</p>
|
<dd><p>Construct a merge <b>node</b> - a <b>node</b> that merges another <b>node</b> into a mapping.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">bool <a name="constructBool"></a><span class="ddoc_psymbol">constructBool</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">bool <a name="constructBool"></a><span class="ddoc_psymbol">constructBool</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a boolean <b>node</b>.</p>
|
<dd><p>Construct a boolean <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">long <a name="constructLong"></a><span class="ddoc_psymbol">constructLong</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">long <a name="constructLong"></a><span class="ddoc_psymbol">constructLong</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct an integer (long) <b>node</b>.</p>
|
<dd><p>Construct an integer (long) <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">real <a name="constructReal"></a><span class="ddoc_psymbol">constructReal</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">real <a name="constructReal"></a><span class="ddoc_psymbol">constructReal</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a floating point (real) <b>node</b>.</p>
|
<dd><p>Construct a floating point (real) <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">ubyte[] <a name="constructBinary"></a><span class="ddoc_psymbol">constructBinary</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">ubyte[] <a name="constructBinary"></a><span class="ddoc_psymbol">constructBinary</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a binary (base64) <b>node</b>.</p>
|
<dd><p>Construct a binary (base64) <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">SysTime <a name="constructTimestamp"></a><span class="ddoc_psymbol">constructTimestamp</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">SysTime <a name="constructTimestamp"></a><span class="ddoc_psymbol">constructTimestamp</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a timestamp (SysTime) <b>node</b>.</p>
|
<dd><p>Construct a timestamp (SysTime) <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">string <a name="constructString"></a><span class="ddoc_psymbol">constructString</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">string <a name="constructString"></a><span class="ddoc_psymbol">constructString</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a string <b>node</b>.</p>
|
<dd><p>Construct a string <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">Pair[] <a name="getPairs"></a><span class="ddoc_psymbol">getPairs</span>(string <b>type</b>, Mark <b>start</b>, Mark <b>end</b>, Node[] <b>nodes</b>);
|
<dt class="d_decl">Pair[] <a name="getPairs"></a><span class="ddoc_psymbol">getPairs</span>(string <b>type</b>, Node[] <b>nodes</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Convert a sequence of single-element mappings into a sequence of pairs.</p>
|
<dd><p>Convert a sequence of single-element mappings into a sequence of pairs.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">Pair[] <a name="constructOrderedMap"></a><span class="ddoc_psymbol">constructOrderedMap</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">Pair[] <a name="constructOrderedMap"></a><span class="ddoc_psymbol">constructOrderedMap</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct an ordered map (ordered sequence of key:value pairs without duplicates) <b>node</b>.</p>
|
<dd><p>Construct an ordered map (ordered sequence of key:value pairs without duplicates) <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">Pair[] <a name="constructPairs"></a><span class="ddoc_psymbol">constructPairs</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">Pair[] <a name="constructPairs"></a><span class="ddoc_psymbol">constructPairs</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a pairs (ordered sequence of key: value pairs allowing duplicates) <b>node</b>.</p>
|
<dd><p>Construct a pairs (ordered sequence of key: value pairs allowing duplicates) <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">Node[] <a name="constructSet"></a><span class="ddoc_psymbol">constructSet</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">Node[] <a name="constructSet"></a><span class="ddoc_psymbol">constructSet</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a set <b>node</b>.</p>
|
<dd><p>Construct a set <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">Node[] <a name="constructSequence"></a><span class="ddoc_psymbol">constructSequence</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">Node[] <a name="constructSequence"></a><span class="ddoc_psymbol">constructSequence</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct a sequence (array) <b>node</b>.</p>
|
<dd><p>Construct a sequence (array) <b>node</b>.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="d_decl">Pair[] <a name="constructMap"></a><span class="ddoc_psymbol">constructMap</span>(Mark <b>start</b>, Mark <b>end</b>, ref Node <b>node</b>);
|
<dt class="d_decl">Pair[] <a name="constructMap"></a><span class="ddoc_psymbol">constructMap</span>(ref Node <b>node</b>);
|
||||||
</dt>
|
</dt>
|
||||||
<dd><p>Construct an unordered map (unordered set of key: value pairs without duplicates) <b>node</b>.</p>
|
<dd><p>Construct an unordered map (unordered set of key: value pairs without duplicates) <b>node</b>.</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 Nov 16, 2011.
|
Last updated on Nov 17, 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>
|
||||||
|
|
|
@ -104,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 Nov 16, 2011.
|
Last updated on Nov 17, 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 Nov 16, 2011.
|
Last updated on Nov 17, 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
|
@ -48,12 +48,12 @@
|
||||||
<div class="section" id="custom-yaml-data-types">
|
<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>
|
<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
|
<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,
|
you could use plain nodes such as mappings with class data members. YAML also
|
||||||
YAML supports custom types with identifiers called <em>tags</em>. That is the topic of
|
supports custom types with identifiers called <em>tags</em>. That is the topic of this
|
||||||
this tutorial.</p>
|
tutorial.</p>
|
||||||
<p>Each YAML node has a tag specifying its type. For instance: strings use the tag
|
<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>
|
<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’t need to specify tag for each float, integer, etc.
|
during parsing - you don’t need to specify tag for each float, integer, etc.
|
||||||
D:YAML can also implicitly resolve custom tags, as we will show later.</p>
|
D:YAML can also 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>
|
||||||
|
@ -63,7 +63,7 @@ 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
|
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>
|
<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
|
<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
|
define the <em>opEquals()</em> operator - this is used in equality comparisons of
|
||||||
nodes. Default class <em>opEquals()</em> compares references, which means two identical
|
nodes. Default class <em>opEquals()</em> compares references, which means two identical
|
||||||
objects might be considered unequal. (Default struct <em>opEquals()</em> compares
|
objects might be considered unequal. (Default struct <em>opEquals()</em> compares
|
||||||
byte-by-byte, sometimes you might want to override that as well.)</p>
|
byte-by-byte, sometimes you might want to override that as well.)</p>
|
||||||
|
@ -77,21 +77,22 @@ following struct:</p>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
</div>
|
</div>
|
||||||
<p>First, we need a function to construct our data type. It must take two <em>Mark</em>
|
<p>First, we need a function to construct our data type. The function will take a
|
||||||
structs, which store position of the node in the file, and a reference to <em>Node</em>
|
reference to <em>Node</em> to construct from. The node is guaranteed to contain either
|
||||||
to construct from. The node is guaranteed to contain either a <em>string</em>, an array
|
a <em>string</em>, an array of <em>Node</em> or of <em>Node.Pair</em>, depending on whether we’re
|
||||||
of <em>Node</em> or of <em>Node.Pair</em>, depending on whether we’re constructing our value
|
constructing our value from a scalar, sequence, or mapping, respectively.
|
||||||
from a scalar, sequence, or mapping, respectively. In this tutorial, we have
|
If this function throws any exception, D:YAML handles it and adds its message
|
||||||
functions to construct a color from a scalar, using CSS-like format, RRGGBB, or
|
to a <em>YAMLException</em> that will be thrown when loading the file.</p>
|
||||||
from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code
|
<p>In this tutorial, we have functions to construct a color from a scalar, using
|
||||||
of these functions:</p>
|
CSS-like format, RRGGBB, or from a mapping, where we use the following format:
|
||||||
<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>
|
{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="k">ref</span> <span class="n">Node</span> <span class="n">node</span><span class="p">)</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="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="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="p">{</span>
|
||||||
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">"Invalid color: "</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="k">throw</span> <span class="k">new</span> <span class="n">Exception</span><span class="p">(</span><span class="s">"Invalid color: "</span> <span class="p">~</span> <span class="n">value</span><span class="p">);</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
<span class="c1">//We don't need to check for uppercase chars this way.</span>
|
<span class="c1">//We don'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="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>
|
||||||
|
@ -101,7 +102,7 @@ of these functions:</p>
|
||||||
<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="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="p">{</span>
|
||||||
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">"Invalid color: "</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="k">throw</span> <span class="k">new</span> <span class="n">Exception</span><span class="p">(</span><span class="s">"Invalid color: "</span> <span class="p">~</span> <span class="n">value</span><span class="p">);</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="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>
|
||||||
|
@ -119,21 +120,16 @@ of these functions:</p>
|
||||||
<span class="k">return</span> <span class="n">result</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="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="n">Color</span> <span class="n">constructColorMapping</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="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="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="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="c1">//If this happens, D:YAML will handle the exception and use its message</span>
|
||||||
<span class="p">{</span>
|
<span class="c1">//in a YAMLException thrown when loading.</span>
|
||||||
<span class="n">r</span> <span class="p">=</span> <span class="n">node</span><span class="p">[</span><span class="s">"r"</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">r</span> <span class="p">=</span> <span class="n">node</span><span class="p">[</span><span class="s">"r"</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">"g"</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">"g"</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">"b"</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">"b"</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">"Invalid color: "</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="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>
|
<span class="p">}</span>
|
||||||
|
@ -368,7 +364,7 @@ directory of the 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 Nov 16, 2011.
|
Last updated on Nov 17, 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>
|
||||||
|
|
|
@ -237,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 Nov 16, 2011.
|
Last updated on Nov 17, 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 Nov 16, 2011.
|
Last updated on Nov 17, 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>
|
||||||
|
|
|
@ -3,13 +3,13 @@ Custom YAML data types
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Sometimes you need to serialize complex data types such as classes. To do this
|
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,
|
you could use plain nodes such as mappings with class data members. YAML also
|
||||||
YAML supports custom types with identifiers called *tags*. That is the topic of
|
supports custom types with identifiers called *tags*. That is the topic of this
|
||||||
this tutorial.
|
tutorial.
|
||||||
|
|
||||||
Each YAML node has a tag specifying its type. For instance: strings use the tag
|
Each YAML node has a tag specifying its type. For instance: strings use the tag
|
||||||
``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved*
|
``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved*
|
||||||
during parsing, so you don't need to specify tag for each float, integer, etc.
|
during parsing - you don't need to specify tag for each float, integer, etc.
|
||||||
D:YAML can also implicitly resolve custom tags, as we will show later.
|
D:YAML can also implicitly resolve custom tags, as we will show later.
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ the *addConstructorXXX()* methods, where *XXX* is *Scalar*, *Sequence* or
|
||||||
*Mapping*. *Constructor* is then passed to *Loader*, which parses YAML input.
|
*Mapping*. *Constructor* is then passed to *Loader*, which parses YAML input.
|
||||||
|
|
||||||
Struct types have no specific requirements for YAML support. Class types should
|
Struct types have no specific requirements for YAML support. Class types should
|
||||||
define the *opEquals()* operator, as this is used in equality comparisons of
|
define the *opEquals()* operator - this is used in equality comparisons of
|
||||||
nodes. Default class *opEquals()* compares references, which means two identical
|
nodes. Default class *opEquals()* compares references, which means two identical
|
||||||
objects might be considered unequal. (Default struct *opEquals()* compares
|
objects might be considered unequal. (Default struct *opEquals()* compares
|
||||||
byte-by-byte, sometimes you might want to override that as well.)
|
byte-by-byte, sometimes you might want to override that as well.)
|
||||||
|
@ -41,24 +41,26 @@ following struct:
|
||||||
ubyte blue;
|
ubyte blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
First, we need a function to construct our data type. It must take two *Mark*
|
First, we need a function to construct our data type. The function will take a
|
||||||
structs, which store position of the node in the file, and a reference to *Node*
|
reference to *Node* to construct from. The node is guaranteed to contain either
|
||||||
to construct from. The node is guaranteed to contain either a *string*, an array
|
a *string*, an array of *Node* or of *Node.Pair*, depending on whether we're
|
||||||
of *Node* or of *Node.Pair*, depending on whether we're constructing our value
|
constructing our value from a scalar, sequence, or mapping, respectively.
|
||||||
from a scalar, sequence, or mapping, respectively. In this tutorial, we have
|
If this function throws any exception, D:YAML handles it and adds its message
|
||||||
functions to construct a color from a scalar, using CSS-like format, RRGGBB, or
|
to a *YAMLException* that will be thrown when loading the file.
|
||||||
from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code
|
|
||||||
of these functions:
|
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:
|
||||||
|
|
||||||
.. code-block:: d
|
.. code-block:: d
|
||||||
|
|
||||||
Color constructColorScalar(Mark start, Mark end, ref Node node)
|
Color constructColorScalar(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string;
|
string value = node.as!string;
|
||||||
|
|
||||||
if(value.length != 6)
|
if(value.length != 6)
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
//We don't need to check for uppercase chars this way.
|
//We don't need to check for uppercase chars this way.
|
||||||
value = value.toLower();
|
value = value.toLower();
|
||||||
|
@ -68,7 +70,7 @@ of these functions:
|
||||||
{
|
{
|
||||||
if(!std.ascii.isHexDigit(c))
|
if(!std.ascii.isHexDigit(c))
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std.ascii.isDigit(c))
|
if(std.ascii.isDigit(c))
|
||||||
|
@ -86,21 +88,16 @@ of these functions:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color constructColorMapping(Mark start, Mark end, ref Node node)
|
Color constructColorMapping(ref Node node)
|
||||||
{
|
{
|
||||||
ubyte r,g,b;
|
ubyte r,g,b;
|
||||||
|
|
||||||
//Might throw if a value is missing is not an integer, or is out of range.
|
//Might throw if a value is missing is not an integer, or is out of range.
|
||||||
try
|
//If this happens, D:YAML will handle the exception and use its message
|
||||||
{
|
//in a YAMLException thrown when loading.
|
||||||
r = node["r"].as!ubyte;
|
r = node["r"].as!ubyte;
|
||||||
g = node["g"].as!ubyte;
|
g = node["g"].as!ubyte;
|
||||||
b = node["b"].as!ubyte;
|
b = node["b"].as!ubyte;
|
||||||
}
|
|
||||||
catch(NodeException e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Invalid color: " ~ e.msg, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ import dyaml.style;
|
||||||
*
|
*
|
||||||
* Can be thrown by custom constructor functions.
|
* Can be thrown by custom constructor functions.
|
||||||
*/
|
*/
|
||||||
class ConstructorException : YAMLException
|
package class ConstructorException : YAMLException
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Construct a ConstructorException.
|
* Construct a ConstructorException.
|
||||||
|
@ -70,11 +70,11 @@ final class Constructor
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
///Constructor functions from scalars.
|
///Constructor functions from scalars.
|
||||||
Node.Value delegate(Mark, Mark, ref Node)[Tag] fromScalar_;
|
Node.Value delegate(ref Node)[Tag] fromScalar_;
|
||||||
///Constructor functions from sequences.
|
///Constructor functions from sequences.
|
||||||
Node.Value delegate(Mark, Mark, ref Node)[Tag] fromSequence_;
|
Node.Value delegate(ref Node)[Tag] fromSequence_;
|
||||||
///Constructor functions from mappings.
|
///Constructor functions from mappings.
|
||||||
Node.Value delegate(Mark, Mark, ref Node)[Tag] fromMapping_;
|
Node.Value delegate(ref Node)[Tag] fromMapping_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -122,10 +122,14 @@ final class Constructor
|
||||||
/**
|
/**
|
||||||
* Add a constructor function from scalar.
|
* Add a constructor function from scalar.
|
||||||
*
|
*
|
||||||
* The function must take two Marks (start and end positions of
|
* The function must take a reference to Node to construct from.
|
||||||
* the node in file) and a reference to Node to construct from.
|
|
||||||
* The node contains a string for scalars, Node[] for sequences and
|
* The node contains a string for scalars, Node[] for sequences and
|
||||||
* Node.Pair[] for mappings.
|
* Node.Pair[] for mappings.
|
||||||
|
*
|
||||||
|
* Any exception thrown by this function will be caught by D:YAML and
|
||||||
|
* its message will be added to a YAMLException that will also tell the
|
||||||
|
* user which type failed to construct, and position in the file.
|
||||||
|
*
|
||||||
* The value returned by this function will be stored in the resulting node.
|
* The value returned by this function will be stored in the resulting node.
|
||||||
*
|
*
|
||||||
* Only one constructor function can be set for one tag.
|
* Only one constructor function can be set for one tag.
|
||||||
|
@ -145,21 +149,14 @@ final class Constructor
|
||||||
* int x, y, z;
|
* int x, y, z;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* MyStruct constructMyStructScalar(Mark start, Mark end, ref Node node)
|
* MyStruct constructMyStructScalar(ref Node node)
|
||||||
* {
|
* {
|
||||||
* //Guaranteed to be string as we construct from scalar.
|
* //Guaranteed to be string as we construct from scalar.
|
||||||
* //!mystruct x:y:z
|
* //!mystruct x:y:z
|
||||||
* auto parts = node.as!string().split(":");
|
* auto parts = node.as!string().split(":");
|
||||||
* try
|
* //If this throws, the D:YAML will handle it and throw a YAMLException.
|
||||||
* {
|
|
||||||
* return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2]));
|
* return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2]));
|
||||||
* }
|
* }
|
||||||
* catch(Exception e)
|
|
||||||
* {
|
|
||||||
* throw new ConstructorException("Could not construct MyStruct: " ~ e.msg,
|
|
||||||
* start, end);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
*
|
||||||
* void main()
|
* void main()
|
||||||
* {
|
* {
|
||||||
|
@ -171,7 +168,7 @@ final class Constructor
|
||||||
* }
|
* }
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
void addConstructorScalar(T)(in string tag, T function(Mark, Mark, ref Node) ctor)
|
void addConstructorScalar(T)(in string tag, T function(ref Node) ctor)
|
||||||
{
|
{
|
||||||
const t = Tag(tag);
|
const t = Tag(tag);
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
|
@ -195,20 +192,12 @@ final class Constructor
|
||||||
* int x, y, z;
|
* int x, y, z;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* MyStruct constructMyStructSequence(Mark start, Mark end, ref Node node)
|
* MyStruct constructMyStructSequence(ref Node node)
|
||||||
* {
|
* {
|
||||||
* //node is guaranteed to be sequence.
|
* //node is guaranteed to be sequence.
|
||||||
* //!mystruct [x, y, z]
|
* //!mystruct [x, y, z]
|
||||||
* try
|
|
||||||
* {
|
|
||||||
* return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
|
* return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
|
||||||
* }
|
* }
|
||||||
* catch(NodeException e)
|
|
||||||
* {
|
|
||||||
* throw new ConstructorException("Could not construct MyStruct: " ~ e.msg,
|
|
||||||
* start, end);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
*
|
||||||
* void main()
|
* void main()
|
||||||
* {
|
* {
|
||||||
|
@ -220,7 +209,7 @@ final class Constructor
|
||||||
* }
|
* }
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
void addConstructorSequence(T)(in string tag, T function(Mark, Mark, ref Node) ctor)
|
void addConstructorSequence(T)(in string tag, T function(ref Node) ctor)
|
||||||
{
|
{
|
||||||
const t = Tag(tag);
|
const t = Tag(tag);
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
|
@ -244,20 +233,12 @@ final class Constructor
|
||||||
* int x, y, z;
|
* int x, y, z;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* MyStruct constructMyStructMapping(Mark start, Mark end, ref Node node)
|
* MyStruct constructMyStructMapping(ref Node node)
|
||||||
* {
|
* {
|
||||||
* //node is guaranteed to be mapping.
|
* //node is guaranteed to be mapping.
|
||||||
* //!mystruct {"x": x, "y": y, "z": z}
|
* //!mystruct {"x": x, "y": y, "z": z}
|
||||||
* try
|
|
||||||
* {
|
|
||||||
* return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
* return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
||||||
* }
|
* }
|
||||||
* catch(NodeException e)
|
|
||||||
* {
|
|
||||||
* throw new ConstructorException("Could not construct MyStruct: " ~ e.msg,
|
|
||||||
* start, end);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
*
|
||||||
* void main()
|
* void main()
|
||||||
* {
|
* {
|
||||||
|
@ -269,7 +250,7 @@ final class Constructor
|
||||||
* }
|
* }
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
void addConstructorMapping(T)(in string tag, T function(Mark, Mark, ref Node) ctor)
|
void addConstructorMapping(T)(in string tag, T function(ref Node) ctor)
|
||||||
{
|
{
|
||||||
const t = Tag(tag);
|
const t = Tag(tag);
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
|
@ -295,18 +276,26 @@ final class Constructor
|
||||||
enforce((tag in *delegates!T) !is null,
|
enforce((tag in *delegates!T) !is null,
|
||||||
new Error("No constructor function for tag " ~ tag.get(), start, end));
|
new Error("No constructor function for tag " ~ tag.get(), start, end));
|
||||||
Node node = Node(value);
|
Node node = Node(value);
|
||||||
|
try
|
||||||
|
{
|
||||||
static if(is(U : ScalarStyle))
|
static if(is(U : ScalarStyle))
|
||||||
{
|
{
|
||||||
return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag,
|
return Node.rawNode((*delegates!T)[tag](node), start, tag,
|
||||||
style, CollectionStyle.Invalid);
|
style, CollectionStyle.Invalid);
|
||||||
}
|
}
|
||||||
else static if(is(U : CollectionStyle))
|
else static if(is(U : CollectionStyle))
|
||||||
{
|
{
|
||||||
return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag,
|
return Node.rawNode((*delegates!T)[tag](node), start, tag,
|
||||||
ScalarStyle.Invalid, style);
|
ScalarStyle.Invalid, style);
|
||||||
}
|
}
|
||||||
else static assert(false);
|
else static assert(false);
|
||||||
}
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new Error("Error constructing " ~ typeid(T).toString()
|
||||||
|
~ ":\n" ~ e.msg, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
|
@ -315,7 +304,7 @@ final class Constructor
|
||||||
* Params: tag = Tag for the function to handle.
|
* Params: tag = Tag for the function to handle.
|
||||||
* ctor = Constructor function.
|
* ctor = Constructor function.
|
||||||
*/
|
*/
|
||||||
auto addConstructor(T)(in Tag tag, T function(Mark, Mark, ref Node) ctor)
|
auto addConstructor(T)(in Tag tag, T function(ref Node) ctor)
|
||||||
{
|
{
|
||||||
assert((tag in fromScalar_) is null &&
|
assert((tag in fromScalar_) is null &&
|
||||||
(tag in fromSequence_) is null &&
|
(tag in fromSequence_) is null &&
|
||||||
|
@ -323,10 +312,10 @@ final class Constructor
|
||||||
"Constructor function for tag " ~ tag.get ~ " is already "
|
"Constructor function for tag " ~ tag.get ~ " is already "
|
||||||
"specified. Can't specify another one.");
|
"specified. Can't specify another one.");
|
||||||
|
|
||||||
return (Mark s, Mark e, ref Node n)
|
return (ref Node n)
|
||||||
{
|
{
|
||||||
static if(Node.Value.allowed!T){return Node.Value(ctor(s,e,n));}
|
static if(Node.Value.allowed!T){return Node.Value(ctor(n));}
|
||||||
else {return Node.userValue(ctor(s,e,n));}
|
else {return Node.userValue(ctor(n));}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,30 +331,30 @@ final class Constructor
|
||||||
|
|
||||||
|
|
||||||
///Construct a null node.
|
///Construct a null node.
|
||||||
YAMLNull constructNull(Mark start, Mark end, ref Node node)
|
YAMLNull constructNull(ref Node node)
|
||||||
{
|
{
|
||||||
return YAMLNull();
|
return YAMLNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a merge node - a node that merges another node into a mapping.
|
///Construct a merge node - a node that merges another node into a mapping.
|
||||||
YAMLMerge constructMerge(Mark start, Mark end, ref Node node)
|
YAMLMerge constructMerge(ref Node node)
|
||||||
{
|
{
|
||||||
return YAMLMerge();
|
return YAMLMerge();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a boolean node.
|
///Construct a boolean node.
|
||||||
bool constructBool(Mark start, Mark end, ref Node node)
|
bool constructBool(ref Node node)
|
||||||
{
|
{
|
||||||
static yes = ["yes", "true", "on"];
|
static yes = ["yes", "true", "on"];
|
||||||
static no = ["no", "false", "off"];
|
static no = ["no", "false", "off"];
|
||||||
string value = node.as!string().toLower();
|
string value = node.as!string().toLower();
|
||||||
if(yes.canFind(value)){return true;}
|
if(yes.canFind(value)){return true;}
|
||||||
if(no.canFind(value)) {return false;}
|
if(no.canFind(value)) {return false;}
|
||||||
throw new Error("Unable to parse boolean value: " ~ value, start, end);
|
throw new Exception("Unable to parse boolean value: " ~ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct an integer (long) node.
|
///Construct an integer (long) node.
|
||||||
long constructLong(Mark start, Mark end, ref Node node)
|
long constructLong(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string().replace("_", "");
|
string value = node.as!string().replace("_", "");
|
||||||
const char c = value[0];
|
const char c = value[0];
|
||||||
|
@ -375,7 +364,7 @@ long constructLong(Mark start, Mark end, ref Node node)
|
||||||
value = value[1 .. $];
|
value = value[1 .. $];
|
||||||
}
|
}
|
||||||
|
|
||||||
enforce(value != "", new Error("Unable to parse float value: " ~ value, start, end));
|
enforce(value != "", new Exception("Unable to parse float value: " ~ value));
|
||||||
|
|
||||||
long result;
|
long result;
|
||||||
try
|
try
|
||||||
|
@ -405,7 +394,7 @@ long constructLong(Mark start, Mark end, ref Node node)
|
||||||
}
|
}
|
||||||
catch(ConvException e)
|
catch(ConvException e)
|
||||||
{
|
{
|
||||||
throw new Error("Unable to parse integer value: " ~ value, start, end);
|
throw new Exception("Unable to parse integer value: " ~ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -414,7 +403,7 @@ unittest
|
||||||
{
|
{
|
||||||
long getLong(string str)
|
long getLong(string str)
|
||||||
{
|
{
|
||||||
return constructLong(Mark(), Mark(), Node(str));
|
return constructLong(Node(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
string canonical = "685230";
|
string canonical = "685230";
|
||||||
|
@ -433,7 +422,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a floating point (real) node.
|
///Construct a floating point (real) node.
|
||||||
real constructReal(Mark start, Mark end, ref Node node)
|
real constructReal(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string().replace("_", "").toLower();
|
string value = node.as!string().replace("_", "").toLower();
|
||||||
const char c = value[0];
|
const char c = value[0];
|
||||||
|
@ -444,7 +433,7 @@ real constructReal(Mark start, Mark end, ref Node node)
|
||||||
}
|
}
|
||||||
|
|
||||||
enforce(value != "" && value != "nan" && value != "inf" && value != "-inf",
|
enforce(value != "" && value != "nan" && value != "inf" && value != "-inf",
|
||||||
new Error("Unable to parse float value: " ~ value, start, end));
|
new Exception("Unable to parse float value: " ~ value));
|
||||||
|
|
||||||
real result;
|
real result;
|
||||||
try
|
try
|
||||||
|
@ -470,7 +459,7 @@ real constructReal(Mark start, Mark end, ref Node node)
|
||||||
}
|
}
|
||||||
catch(ConvException e)
|
catch(ConvException e)
|
||||||
{
|
{
|
||||||
throw new Error("Unable to parse float value: " ~ value, start, end);
|
throw new Exception("Unable to parse float value: " ~ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -484,7 +473,7 @@ unittest
|
||||||
|
|
||||||
real getReal(string str)
|
real getReal(string str)
|
||||||
{
|
{
|
||||||
return constructReal(Mark(), Mark(), Node(str));
|
return constructReal(Node(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
string canonical = "6.8523015e+5";
|
string canonical = "6.8523015e+5";
|
||||||
|
@ -503,7 +492,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a binary (base64) node.
|
///Construct a binary (base64) node.
|
||||||
ubyte[] constructBinary(Mark start, Mark end, ref Node node)
|
ubyte[] constructBinary(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string;
|
string value = node.as!string;
|
||||||
//For an unknown reason, this must be nested to work (compiler bug?).
|
//For an unknown reason, this must be nested to work (compiler bug?).
|
||||||
|
@ -512,12 +501,12 @@ ubyte[] constructBinary(Mark start, Mark end, ref Node node)
|
||||||
try{return Base64.decode(value.removechars("\n"));}
|
try{return Base64.decode(value.removechars("\n"));}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
throw new Error("Unable to decode base64 value: " ~ e.msg, start, end);
|
throw new Exception("Unable to decode base64 value: " ~ e.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(UtfException e)
|
catch(UtfException e)
|
||||||
{
|
{
|
||||||
throw new Error("Unable to decode base64 value: " ~ e.msg, start, end);
|
throw new Exception("Unable to decode base64 value: " ~ e.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unittest
|
unittest
|
||||||
|
@ -526,12 +515,12 @@ unittest
|
||||||
char[] buffer;
|
char[] buffer;
|
||||||
buffer.length = 256;
|
buffer.length = 256;
|
||||||
string input = cast(string)Base64.encode(test, buffer);
|
string input = cast(string)Base64.encode(test, buffer);
|
||||||
auto value = constructBinary(Mark(), Mark(), Node(input));
|
auto value = constructBinary(Node(input));
|
||||||
assert(value == test);
|
assert(value == test);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a timestamp (SysTime) node.
|
///Construct a timestamp (SysTime) node.
|
||||||
SysTime constructTimestamp(Mark start, Mark end, ref Node node)
|
SysTime constructTimestamp(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string;
|
string value = node.as!string;
|
||||||
|
|
||||||
|
@ -545,7 +534,7 @@ SysTime constructTimestamp(Mark start, Mark end, ref Node node)
|
||||||
auto matches = match(value, YMDRegexp);
|
auto matches = match(value, YMDRegexp);
|
||||||
|
|
||||||
enforce(!matches.empty,
|
enforce(!matches.empty,
|
||||||
new Error("Unable to parse timestamp value: " ~ value, start, end));
|
new Exception("Unable to parse timestamp value: " ~ value));
|
||||||
|
|
||||||
auto captures = matches.front.captures;
|
auto captures = matches.front.captures;
|
||||||
const year = to!int(captures[1]);
|
const year = to!int(captures[1]);
|
||||||
|
@ -592,11 +581,11 @@ SysTime constructTimestamp(Mark start, Mark end, ref Node node)
|
||||||
}
|
}
|
||||||
catch(ConvException e)
|
catch(ConvException e)
|
||||||
{
|
{
|
||||||
throw new Error("Unable to parse timestamp value " ~ value ~ " : " ~ e.msg, start, end);
|
throw new Exception("Unable to parse timestamp value " ~ value ~ " : " ~ e.msg);
|
||||||
}
|
}
|
||||||
catch(DateTimeException e)
|
catch(DateTimeException e)
|
||||||
{
|
{
|
||||||
throw new Error("Invalid timestamp value " ~ value ~ " : " ~ e.msg, start, end);
|
throw new Exception("Invalid timestamp value " ~ value ~ " : " ~ e.msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false, "This code should never be reached");
|
assert(false, "This code should never be reached");
|
||||||
|
@ -607,7 +596,7 @@ unittest
|
||||||
|
|
||||||
string timestamp(string value)
|
string timestamp(string value)
|
||||||
{
|
{
|
||||||
return constructTimestamp(Mark(), Mark(), Node(value)).toISOString();
|
return constructTimestamp(Node(value)).toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
string canonical = "2001-12-15T02:59:43.1Z";
|
string canonical = "2001-12-15T02:59:43.1Z";
|
||||||
|
@ -630,21 +619,21 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a string node.
|
///Construct a string node.
|
||||||
string constructString(Mark start, Mark end, ref Node node)
|
string constructString(ref Node node)
|
||||||
{
|
{
|
||||||
return node.as!string;
|
return node.as!string;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Convert a sequence of single-element mappings into a sequence of pairs.
|
///Convert a sequence of single-element mappings into a sequence of pairs.
|
||||||
Node.Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes)
|
Node.Pair[] getPairs(string type, Node[] nodes)
|
||||||
{
|
{
|
||||||
Node.Pair[] pairs;
|
Node.Pair[] pairs;
|
||||||
|
|
||||||
foreach(ref node; nodes)
|
foreach(ref node; nodes)
|
||||||
{
|
{
|
||||||
enforce(node.isMapping && node.length == 1,
|
enforce(node.isMapping && node.length == 1,
|
||||||
new Error("While constructing " ~ type ~
|
new Exception("While constructing " ~ type ~
|
||||||
", expected a mapping with single element", start, end));
|
", expected a mapping with single element"));
|
||||||
|
|
||||||
pairs ~= node.as!(Node.Pair[]);
|
pairs ~= node.as!(Node.Pair[]);
|
||||||
}
|
}
|
||||||
|
@ -653,9 +642,9 @@ Node.Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.
|
///Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.
|
||||||
Node.Pair[] constructOrderedMap(Mark start, Mark end, ref Node node)
|
Node.Pair[] constructOrderedMap(ref Node node)
|
||||||
{
|
{
|
||||||
auto pairs = getPairs("ordered map", start, end, node.as!(Node[]));
|
auto pairs = getPairs("ordered map", node.as!(Node[]));
|
||||||
|
|
||||||
//TODO: the map here should be replaced with something with deterministic
|
//TODO: the map here should be replaced with something with deterministic
|
||||||
//memory allocation if possible.
|
//memory allocation if possible.
|
||||||
|
@ -664,7 +653,7 @@ Node.Pair[] constructOrderedMap(Mark start, Mark end, ref Node node)
|
||||||
foreach(ref pair; pairs)
|
foreach(ref pair; pairs)
|
||||||
{
|
{
|
||||||
enforce((pair.key in map) is null,
|
enforce((pair.key in map) is null,
|
||||||
new Error("Duplicate entry in an ordered map", start, end));
|
new Exception("Duplicate entry in an ordered map"));
|
||||||
map[pair.key] = true;
|
map[pair.key] = true;
|
||||||
}
|
}
|
||||||
clear(map);
|
clear(map);
|
||||||
|
@ -701,7 +690,7 @@ unittest
|
||||||
|
|
||||||
bool hasDuplicates(Node[] nodes)
|
bool hasDuplicates(Node[] nodes)
|
||||||
{
|
{
|
||||||
return null !is collectException(constructOrderedMap(Mark(), Mark(), Node(nodes)));
|
return null !is collectException(constructOrderedMap(Node(nodes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(hasDuplicates(alternateTypes(8) ~ alternateTypes(2)));
|
assert(hasDuplicates(alternateTypes(8) ~ alternateTypes(2)));
|
||||||
|
@ -713,13 +702,13 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.
|
///Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.
|
||||||
Node.Pair[] constructPairs(Mark start, Mark end, ref Node node)
|
Node.Pair[] constructPairs(ref Node node)
|
||||||
{
|
{
|
||||||
return getPairs("pairs", start, end, node.as!(Node[]));
|
return getPairs("pairs", node.as!(Node[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a set node.
|
///Construct a set node.
|
||||||
Node[] constructSet(Mark start, Mark end, ref Node node)
|
Node[] constructSet(ref Node node)
|
||||||
{
|
{
|
||||||
auto pairs = node.as!(Node.Pair[]);
|
auto pairs = node.as!(Node.Pair[]);
|
||||||
|
|
||||||
|
@ -732,7 +721,7 @@ Node[] constructSet(Mark start, Mark end, ref Node node)
|
||||||
foreach(ref pair; pairs)
|
foreach(ref pair; pairs)
|
||||||
{
|
{
|
||||||
enforce((pair.key in map) is null,
|
enforce((pair.key in map) is null,
|
||||||
new Error("Duplicate entry in a set", start, end));
|
new Exception("Duplicate entry in a set"));
|
||||||
map[pair.key] = 0;
|
map[pair.key] = 0;
|
||||||
nodes ~= pair.key;
|
nodes ~= pair.key;
|
||||||
}
|
}
|
||||||
|
@ -773,23 +762,23 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(null !is collectException
|
assert(null !is collectException
|
||||||
(constructSet(Mark(), Mark(), Node(DuplicatesShort.dup))));
|
(constructSet(Node(DuplicatesShort.dup))));
|
||||||
assert(null is collectException
|
assert(null is collectException
|
||||||
(constructSet(Mark(), Mark(), Node(noDuplicatesShort.dup))));
|
(constructSet(Node(noDuplicatesShort.dup))));
|
||||||
assert(null !is collectException
|
assert(null !is collectException
|
||||||
(constructSet(Mark(), Mark(), Node(DuplicatesLong.dup))));
|
(constructSet(Node(DuplicatesLong.dup))));
|
||||||
assert(null is collectException
|
assert(null is collectException
|
||||||
(constructSet(Mark(), Mark(), Node(noDuplicatesLong.dup))));
|
(constructSet(Node(noDuplicatesLong.dup))));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct a sequence (array) node.
|
///Construct a sequence (array) node.
|
||||||
Node[] constructSequence(Mark start, Mark end, ref Node node)
|
Node[] constructSequence(ref Node node)
|
||||||
{
|
{
|
||||||
return node.as!(Node[]);
|
return node.as!(Node[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Construct an unordered map (unordered set of key: value _pairs without duplicates) node.
|
///Construct an unordered map (unordered set of key: value _pairs without duplicates) node.
|
||||||
Node.Pair[] constructMap(Mark start, Mark end, ref Node node)
|
Node.Pair[] constructMap(ref Node node)
|
||||||
{
|
{
|
||||||
auto pairs = node.as!(Node.Pair[]);
|
auto pairs = node.as!(Node.Pair[]);
|
||||||
//TODO: the map here should be replaced with something with deterministic
|
//TODO: the map here should be replaced with something with deterministic
|
||||||
|
@ -800,7 +789,7 @@ Node.Pair[] constructMap(Mark start, Mark end, ref Node node)
|
||||||
foreach(ref pair; pairs)
|
foreach(ref pair; pairs)
|
||||||
{
|
{
|
||||||
enforce((pair.key in map) is null,
|
enforce((pair.key in map) is null,
|
||||||
new Error("Duplicate entry in a map", start, end));
|
new Exception("Duplicate entry in a map"));
|
||||||
map[pair.key] = true;
|
map[pair.key] = true;
|
||||||
}
|
}
|
||||||
return pairs;
|
return pairs;
|
||||||
|
@ -818,47 +807,23 @@ struct MyStruct
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructScalar(Mark start, Mark end, ref Node node)
|
MyStruct constructMyStructScalar(ref Node node)
|
||||||
{
|
{
|
||||||
//Guaranteed to be string as we construct from scalar.
|
//Guaranteed to be string as we construct from scalar.
|
||||||
auto parts = node.as!string().split(":");
|
auto parts = node.as!string().split(":");
|
||||||
try
|
|
||||||
{
|
|
||||||
return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2]));
|
return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2]));
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Could not construct MyStruct: " ~ e.msg,
|
|
||||||
start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructSequence(Mark start, Mark end, ref Node node)
|
MyStruct constructMyStructSequence(ref Node node)
|
||||||
{
|
{
|
||||||
//node is guaranteed to be sequence.
|
//node is guaranteed to be sequence.
|
||||||
try
|
|
||||||
{
|
|
||||||
return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
|
return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
|
||||||
}
|
|
||||||
catch(NodeException e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Could not construct MyStruct: " ~ e.msg,
|
|
||||||
start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructMapping(Mark start, Mark end, ref Node node)
|
MyStruct constructMyStructMapping(ref Node node)
|
||||||
{
|
{
|
||||||
//node is guaranteed to be mapping.
|
//node is guaranteed to be mapping.
|
||||||
try
|
|
||||||
{
|
|
||||||
return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
||||||
}
|
|
||||||
catch(NodeException e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Could not construct MyStruct: " ~ e.msg,
|
|
||||||
start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
|
|
@ -10,13 +10,13 @@ struct Color
|
||||||
ubyte blue;
|
ubyte blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color constructColorScalar(Mark start, Mark end, ref Node node)
|
Color constructColorScalar(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string;
|
string value = node.as!string;
|
||||||
|
|
||||||
if(value.length != 6)
|
if(value.length != 6)
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
//We don't need to check for uppercase chars this way.
|
//We don't need to check for uppercase chars this way.
|
||||||
value = value.toLower();
|
value = value.toLower();
|
||||||
|
@ -26,7 +26,7 @@ Color constructColorScalar(Mark start, Mark end, ref Node node)
|
||||||
{
|
{
|
||||||
if(!std.ascii.isHexDigit(c))
|
if(!std.ascii.isHexDigit(c))
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std.ascii.isDigit(c))
|
if(std.ascii.isDigit(c))
|
||||||
|
@ -44,21 +44,16 @@ Color constructColorScalar(Mark start, Mark end, ref Node node)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color constructColorMapping(Mark start, Mark end, ref Node node)
|
Color constructColorMapping(ref Node node)
|
||||||
{
|
{
|
||||||
ubyte r,g,b;
|
ubyte r,g,b;
|
||||||
|
|
||||||
//Might throw if a value is missing is not an integer, or is out of range.
|
//Might throw if a value is missing is not an integer, or is out of range.
|
||||||
try
|
//If this happens, D:YAML will handle the exception and use its message
|
||||||
{
|
//in a YAMLException thrown when loading.
|
||||||
r = node["r"].as!ubyte;
|
r = node["r"].as!ubyte;
|
||||||
g = node["g"].as!ubyte;
|
g = node["g"].as!ubyte;
|
||||||
b = node["b"].as!ubyte;
|
b = node["b"].as!ubyte;
|
||||||
}
|
|
||||||
catch(NodeException e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Invalid color: " ~ e.msg, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,13 @@ struct Color
|
||||||
ubyte blue;
|
ubyte blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color constructColorScalar(Mark start, Mark end, ref Node node)
|
Color constructColorScalar(ref Node node)
|
||||||
{
|
{
|
||||||
string value = node.as!string;
|
string value = node.as!string;
|
||||||
|
|
||||||
if(value.length != 6)
|
if(value.length != 6)
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
//We don't need to check for uppercase chars this way.
|
//We don't need to check for uppercase chars this way.
|
||||||
value = value.toLower();
|
value = value.toLower();
|
||||||
|
@ -26,7 +26,7 @@ Color constructColorScalar(Mark start, Mark end, ref Node node)
|
||||||
{
|
{
|
||||||
if(!std.ascii.isHexDigit(c))
|
if(!std.ascii.isHexDigit(c))
|
||||||
{
|
{
|
||||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
throw new Exception("Invalid color: " ~ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std.ascii.isDigit(c))
|
if(std.ascii.isDigit(c))
|
||||||
|
@ -44,21 +44,16 @@ Color constructColorScalar(Mark start, Mark end, ref Node node)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color constructColorMapping(Mark start, Mark end, ref Node node)
|
Color constructColorMapping(ref Node node)
|
||||||
{
|
{
|
||||||
ubyte r,g,b;
|
ubyte r,g,b;
|
||||||
|
|
||||||
//Might throw if a value is missing is not an integer, or is out of range.
|
//Might throw if a value is missing is not an integer, or is out of range.
|
||||||
try
|
//If this happens, D:YAML will handle the exception and use its message
|
||||||
{
|
//in a YAMLException thrown when loading.
|
||||||
r = node["r"].as!ubyte;
|
r = node["r"].as!ubyte;
|
||||||
g = node["g"].as!ubyte;
|
g = node["g"].as!ubyte;
|
||||||
b = node["b"].as!ubyte;
|
b = node["b"].as!ubyte;
|
||||||
}
|
|
||||||
catch(NodeException e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Invalid color: " ~ e.msg, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,17 +337,9 @@ struct TestStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
///Constructor function for TestClass.
|
///Constructor function for TestClass.
|
||||||
TestClass constructClass(Mark start, Mark end, ref Node node)
|
TestClass constructClass(ref Node node)
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
||||||
}
|
|
||||||
catch(NodeException e)
|
|
||||||
{
|
|
||||||
throw new ConstructorException("Error constructing TestClass (missing data members?) "
|
|
||||||
~ e.msg, start, end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Node representClass(ref Node node, Representer representer)
|
Node representClass(ref Node node, Representer representer)
|
||||||
|
@ -362,7 +354,7 @@ Node representClass(ref Node node, Representer representer)
|
||||||
}
|
}
|
||||||
|
|
||||||
///Constructor function for TestStruct.
|
///Constructor function for TestStruct.
|
||||||
TestStruct constructStruct(Mark start, Mark end, ref Node node)
|
TestStruct constructStruct(ref Node node)
|
||||||
{
|
{
|
||||||
return TestStruct(to!int(node.as!string));
|
return TestStruct(to!int(node.as!string));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue