diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle index 9ea0e9f..e329ca1 100644 Binary files a/doc/doctrees/environment.pickle and b/doc/doctrees/environment.pickle differ diff --git a/doc/doctrees/tutorials/custom_types.doctree b/doc/doctrees/tutorials/custom_types.doctree index 4d8a875..5f0a456 100644 Binary files a/doc/doctrees/tutorials/custom_types.doctree and b/doc/doctrees/tutorials/custom_types.doctree differ diff --git a/doc/doctrees/tutorials/getting_started.doctree b/doc/doctrees/tutorials/getting_started.doctree index e213365..18d2b4c 100644 Binary files a/doc/doctrees/tutorials/getting_started.doctree and b/doc/doctrees/tutorials/getting_started.doctree differ diff --git a/doc/html/_sources/tutorials/custom_types.txt b/doc/html/_sources/tutorials/custom_types.txt index 1a22ebe..7137f07 100644 --- a/doc/html/_sources/tutorials/custom_types.txt +++ b/doc/html/_sources/tutorials/custom_types.txt @@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later. Constructor ----------- -D:YAML uses the *Constructor* class to process each node to hold data type -corresponding to its tag. *Constructor* stores a function for each supported -tag to process it. These functions are supplied by the user using the -*addConstructor()* method. *Constructor* is then passed to *Loader*, which -parses YAML input. +D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process +each node to hold data type corresponding to its tag. *Constructor* stores a +function for each supported tag to process it. These functions are supplied by +the user using the *addConstructor()* method. *Constructor* is then passed to +*Loader*, which parses YAML input. + +Struct types have no specific requirements for YAML support. Class types should +define the *opEquals()* operator, as this is used in equality comparisons of +nodes. Default class *opEquals()* compares references, which means two identical +objects might be considered unequal. We will implement support for an RGB color type. It is implemented as the following struct: @@ -111,8 +116,8 @@ RRGGBB, or from a mapping, where we use the following format: return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } -Next, we need some YAML data using our new tag. Create a file called input.yaml -with the following contents: +Next, we need some YAML data using our new tag. Create a file called +``input.yaml`` with the following contents: .. code-block:: yaml @@ -167,7 +172,7 @@ Finally, the code to put it all together: } First, we create a *Constructor* and pass functions to handle the ``!color`` -and ``!color-mapping`` tag. We construct a *Loader*m and pass the *Constructor* +and ``!color-mapping`` tag. We construct a *Loader* and pass the *Constructor* to it. We then load the YAML document, and finally, read the colors using *get()* method to test if they were loaded as expected. @@ -181,12 +186,13 @@ Resolver Specifying tag for every color value can be tedious. D:YAML can implicitly resolve scalar tags using regular expressions. This is how default types such as -int are resolved. We will use the *Resolver* class to add implicit tag -resolution for the Color data type (in its scalar form). +int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ class +to add implicit tag resolution for the Color data type (in its scalar form). -We use the *addImplicitResolver* method of *Resolver*, passing the tag, regular -expression the value must match to resolve to this tag, and a string of possible -starting characters of the value. Then we pass the *Resolver* to *Loader*. +We use the *addImplicitResolver()* method of *Resolver*, passing the tag, +regular expression the scalar must match to resolve to this tag, and a string of +possible starting characters of the scalar. Then we pass the *Resolver* to +*Loader*. Note that resolvers added first override ones added later. If no resolver matches a scalar, YAML string tag is used. Therefore our custom values must not @@ -199,8 +205,8 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... auto resolver = new Resolver; - resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}", - "0123456789abcdefABCDEF")); + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); auto loader = Loader("input.yaml"); @@ -209,7 +215,7 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... -Now, change contents of input.yaml to this: +Now, change contents of ``input.yaml`` to this: .. code-block:: yaml @@ -227,3 +233,107 @@ the example. If everything went as expected, it should report success. You can find the complete code in the ``examples/resolver`` directory in the D:YAML package. + + +----------- +Representer +----------- + +Now that you know how to load custom data types, it might also be useful to know +how to dump them. D:YAML uses the `Representer <../api/dyaml.representer.html>`_ +class for this purpose. + +*Representer* processes YAML nodes into plain mapping, sequence or scalar nodes +ready for output. Just like with *Constructor*, this is done by user specified +functions. These functions take references to a node to process and to the +*Representer*, and return the processed node. + +Representer functions can be added with the *addRepresenter()* method. The +*Representer* is then passed to *Dumper*, which dumps YAML documents. Only one +representer can be added for a type. This is asserted in *addRepresenter()* +preconditions. By default, the default YAML types already have representer +functions, but you can disable them by constructing *Representer* with the +*useDefaultRepresenters* parameter set to false. + +By default, tags are explicitly specified for all non-default types. If you +want the tags to be implicit, you can pass a *Resolver* that will resolve them +implicitly. Of course, you will then need to use an identical *Resolver* when +loading the output. + +With the following code, we will add support for dumping the our Color type. + +.. code-block:: d + + Node representColor(ref Node node, Representer representer) + { + //The node is guaranteed to be Color as we add representer for Color. + Color color = node.get!Color; + + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [color.red, color.green, color.blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return representer.representScalar("!color", scalar); + } + +First we get the *Color* from the node. Then we convert it to a string with the +HTML-like format we've used before. Finally, we use the *representScalar()* +method of *Representer* to get a scalar node ready for output. +There are corresponding *representMapping()* and *representSequence()* methods +as well, with examples in the +`Resolver API documentation <../api/dyaml.resolver.html>`_. + +Since a type can only have one representer function, we don't dump *Color* both +in the scalar and mapping formats we've used before. However, you can decide to +dump the node with different formats/tags in the representer function itself. +E.g. you could dump the Color as a mapping based on some arbitrary condition, +such as the color being white. + +.. code-block:: d + + void main() + { + try + { + auto representer = new Representer; + representer.addRepresenter!Color(&representColor); + + auto resolver = new Resolver; + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + + auto dumper = Dumper("output.yaml"); + dumper.representer = representer; + dumper.resolver = resolver; + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(document); + } + catch(YAMLException e) + { + writeln(e.msg); + } + } + +We construct a new *Representer*, and specify a representer function for the +*Color* (the template argument) type. We also construct a *Resolver*, same as in +the previous section, so the ``!color`` tag will be implicit. Of course, +identical *Resolver* would then have to be used when loading the file. +You don't need to do this if you want the tag to be explicit. + +We construct a *Dumper* to file ``output.yaml`` and pass the *Representer* and +*Resolver* to it. Then, we create a simple node containing a sequence of colors +and finally, we dump it. + +Source code for this section can be found in the ``examples/representer`` +directory of the D:YAML package. diff --git a/doc/html/_sources/tutorials/getting_started.txt b/doc/html/_sources/tutorials/getting_started.txt index 73bd3b0..8e4c7cd 100644 --- a/doc/html/_sources/tutorials/getting_started.txt +++ b/doc/html/_sources/tutorials/getting_started.txt @@ -72,7 +72,7 @@ Create a directory for your project and in that directory, create a file called This will serve as input for our example. -Now we need to parse it. Create a file called "main.d". Paste following code +Now we need to parse it. Create a file called ``main.d``. Paste following code into the file: .. code-block:: d @@ -82,12 +82,18 @@ into the file: void main() { + //Read the input. Node root = Loader("input.yaml").load(); + + //Display the data read. foreach(string word; root["Hello World"]) { writeln(word); } writeln("The answer is ", root["Answer"].get!int); + + //Dump the loaded document to output.yaml. + Dumper("output.yaml").dump(root); } @@ -98,8 +104,8 @@ Explanation of the code First, we import the *yaml* module. This is the only module you need to import to use D:YAML - it automatically imports all needed modules. -Next we load the file using the *Loader.load()* method. *Loader* is the struct -used for parsing YAML documents, and *load()* is a method that loads the file as +Next we load the file using the *Loader.load()* method. *Loader* is a struct +used for parsing YAML documents. The *load()* method loads the file as **one** YAML document, or throws *YAMLException*, D:YAML exception type, if the file could not be parsed or does not contain exactly one document. Note that we don't do any error checking here in order to keep the example as simple as @@ -126,6 +132,15 @@ The *Node.get()* method is used to get value of a scalar node, allowing to specify type. D:YAML will try to return the scalar as this type, converting if needed, throwing *YAMLException* if not possible. +Finally we dump the document we just read to ``output.yaml`` with the +*Dumper.dump()* method. *Dumper* is a struct used to dump YAML documents. +The *dump()* method writes one or more documents to a file, throwing +*YAMLException* if the file could not be written to. + +D:YAML doesn't preserve style information in documents, so even though +``output.yaml`` will contain the same data as ``input.yaml``, it might be +formatted differently. Comments are not preserved, either. + ^^^^^^^^^ Compiling diff --git a/doc/html/api/dyaml.representer.html b/doc/html/api/dyaml.representer.html index 593dcd0..ec00226 100644 --- a/doc/html/api/dyaml.representer.html +++ b/doc/html/api/dyaml.representer.html @@ -39,7 +39,8 @@

dyaml.representer

-

YAML node representer. +

YAML node representer. Prepares YAML nodes for output. A tutorial can be + found here.

Code based on PyYAML.

diff --git a/doc/html/articles/spec_differences.html b/doc/html/articles/spec_differences.html index d8947b6..cff7ce6 100644 --- a/doc/html/articles/spec_differences.html +++ b/doc/html/articles/spec_differences.html @@ -138,7 +138,7 @@ struct appears in Phobos.

diff --git a/doc/html/index.html b/doc/html/index.html index 1d94b8c..5ab4bc5 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -55,6 +55,7 @@
  • Custom YAML data types
  • YAML syntax @@ -284,7 +380,7 @@ D:YAML package.

    diff --git a/doc/html/tutorials/getting_started.html b/doc/html/tutorials/getting_started.html index 5b8b649..ea39080 100644 --- a/doc/html/tutorials/getting_started.html +++ b/doc/html/tutorials/getting_started.html @@ -101,19 +101,25 @@ To do this on Unix/Linux, use the following command:

    This will serve as input for our example.

    -

    Now we need to parse it. Create a file called “main.d”. Paste following code +

    Now we need to parse it. Create a file called main.d. Paste following code into the file:

    import std.stdio;
     import yaml;
     
     void main()
     {
    +    //Read the input.
         Node root = Loader("input.yaml").load();
    +
    +    //Display the data read.
         foreach(string word; root["Hello World"])
         {
             writeln(word);
         }
         writeln("The answer is ", root["Answer"].get!int);
    +
    +    //Dump the loaded document to output.yaml.
    +    Dumper("output.yaml").dump(root);
     }
     
    @@ -121,8 +127,8 @@ into the file:

    Explanation of the code

    First, we import the yaml module. This is the only module you need to import to use D:YAML - it automatically imports all needed modules.

    -

    Next we load the file using the Loader.load() method. Loader is the struct -used for parsing YAML documents, and load() is a method that loads the file as +

    Next we load the file using the Loader.load() method. Loader is a struct +used for parsing YAML documents. The load() method loads the file as one YAML document, or throws YAMLException, D:YAML exception type, if the file could not be parsed or does not contain exactly one document. Note that we don’t do any error checking here in order to keep the example as simple as @@ -144,6 +150,13 @@ cannot be converted to an integer.

    The Node.get() method is used to get value of a scalar node, allowing to specify type. D:YAML will try to return the scalar as this type, converting if needed, throwing YAMLException if not possible.

    +

    Finally we dump the document we just read to output.yaml with the +Dumper.dump() method. Dumper is a struct used to dump YAML documents. +The dump() method writes one or more documents to a file, throwing +YAMLException if the file could not be written to.

    +

    D:YAML doesn’t preserve style information in documents, so even though +output.yaml will contain the same data as input.yaml, it might be +formatted differently. Comments are not preserved, either.

    Compiling

    @@ -224,7 +237,7 @@ example in the example/getting_st
    diff --git a/doc/html/tutorials/yaml_syntax.html b/doc/html/tutorials/yaml_syntax.html index 98bc68f..71a9377 100644 --- a/doc/html/tutorials/yaml_syntax.html +++ b/doc/html/tutorials/yaml_syntax.html @@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).

    diff --git a/docsrc/tutorials/custom_types.rst b/docsrc/tutorials/custom_types.rst index 1a22ebe..7137f07 100644 --- a/docsrc/tutorials/custom_types.rst +++ b/docsrc/tutorials/custom_types.rst @@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later. Constructor ----------- -D:YAML uses the *Constructor* class to process each node to hold data type -corresponding to its tag. *Constructor* stores a function for each supported -tag to process it. These functions are supplied by the user using the -*addConstructor()* method. *Constructor* is then passed to *Loader*, which -parses YAML input. +D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process +each node to hold data type corresponding to its tag. *Constructor* stores a +function for each supported tag to process it. These functions are supplied by +the user using the *addConstructor()* method. *Constructor* is then passed to +*Loader*, which parses YAML input. + +Struct types have no specific requirements for YAML support. Class types should +define the *opEquals()* operator, as this is used in equality comparisons of +nodes. Default class *opEquals()* compares references, which means two identical +objects might be considered unequal. We will implement support for an RGB color type. It is implemented as the following struct: @@ -111,8 +116,8 @@ RRGGBB, or from a mapping, where we use the following format: return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } -Next, we need some YAML data using our new tag. Create a file called input.yaml -with the following contents: +Next, we need some YAML data using our new tag. Create a file called +``input.yaml`` with the following contents: .. code-block:: yaml @@ -167,7 +172,7 @@ Finally, the code to put it all together: } First, we create a *Constructor* and pass functions to handle the ``!color`` -and ``!color-mapping`` tag. We construct a *Loader*m and pass the *Constructor* +and ``!color-mapping`` tag. We construct a *Loader* and pass the *Constructor* to it. We then load the YAML document, and finally, read the colors using *get()* method to test if they were loaded as expected. @@ -181,12 +186,13 @@ Resolver Specifying tag for every color value can be tedious. D:YAML can implicitly resolve scalar tags using regular expressions. This is how default types such as -int are resolved. We will use the *Resolver* class to add implicit tag -resolution for the Color data type (in its scalar form). +int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ class +to add implicit tag resolution for the Color data type (in its scalar form). -We use the *addImplicitResolver* method of *Resolver*, passing the tag, regular -expression the value must match to resolve to this tag, and a string of possible -starting characters of the value. Then we pass the *Resolver* to *Loader*. +We use the *addImplicitResolver()* method of *Resolver*, passing the tag, +regular expression the scalar must match to resolve to this tag, and a string of +possible starting characters of the scalar. Then we pass the *Resolver* to +*Loader*. Note that resolvers added first override ones added later. If no resolver matches a scalar, YAML string tag is used. Therefore our custom values must not @@ -199,8 +205,8 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... auto resolver = new Resolver; - resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}", - "0123456789abcdefABCDEF")); + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); auto loader = Loader("input.yaml"); @@ -209,7 +215,7 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... -Now, change contents of input.yaml to this: +Now, change contents of ``input.yaml`` to this: .. code-block:: yaml @@ -227,3 +233,107 @@ the example. If everything went as expected, it should report success. You can find the complete code in the ``examples/resolver`` directory in the D:YAML package. + + +----------- +Representer +----------- + +Now that you know how to load custom data types, it might also be useful to know +how to dump them. D:YAML uses the `Representer <../api/dyaml.representer.html>`_ +class for this purpose. + +*Representer* processes YAML nodes into plain mapping, sequence or scalar nodes +ready for output. Just like with *Constructor*, this is done by user specified +functions. These functions take references to a node to process and to the +*Representer*, and return the processed node. + +Representer functions can be added with the *addRepresenter()* method. The +*Representer* is then passed to *Dumper*, which dumps YAML documents. Only one +representer can be added for a type. This is asserted in *addRepresenter()* +preconditions. By default, the default YAML types already have representer +functions, but you can disable them by constructing *Representer* with the +*useDefaultRepresenters* parameter set to false. + +By default, tags are explicitly specified for all non-default types. If you +want the tags to be implicit, you can pass a *Resolver* that will resolve them +implicitly. Of course, you will then need to use an identical *Resolver* when +loading the output. + +With the following code, we will add support for dumping the our Color type. + +.. code-block:: d + + Node representColor(ref Node node, Representer representer) + { + //The node is guaranteed to be Color as we add representer for Color. + Color color = node.get!Color; + + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [color.red, color.green, color.blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return representer.representScalar("!color", scalar); + } + +First we get the *Color* from the node. Then we convert it to a string with the +HTML-like format we've used before. Finally, we use the *representScalar()* +method of *Representer* to get a scalar node ready for output. +There are corresponding *representMapping()* and *representSequence()* methods +as well, with examples in the +`Resolver API documentation <../api/dyaml.resolver.html>`_. + +Since a type can only have one representer function, we don't dump *Color* both +in the scalar and mapping formats we've used before. However, you can decide to +dump the node with different formats/tags in the representer function itself. +E.g. you could dump the Color as a mapping based on some arbitrary condition, +such as the color being white. + +.. code-block:: d + + void main() + { + try + { + auto representer = new Representer; + representer.addRepresenter!Color(&representColor); + + auto resolver = new Resolver; + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + + auto dumper = Dumper("output.yaml"); + dumper.representer = representer; + dumper.resolver = resolver; + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(document); + } + catch(YAMLException e) + { + writeln(e.msg); + } + } + +We construct a new *Representer*, and specify a representer function for the +*Color* (the template argument) type. We also construct a *Resolver*, same as in +the previous section, so the ``!color`` tag will be implicit. Of course, +identical *Resolver* would then have to be used when loading the file. +You don't need to do this if you want the tag to be explicit. + +We construct a *Dumper* to file ``output.yaml`` and pass the *Representer* and +*Resolver* to it. Then, we create a simple node containing a sequence of colors +and finally, we dump it. + +Source code for this section can be found in the ``examples/representer`` +directory of the D:YAML package. diff --git a/docsrc/tutorials/getting_started.rst b/docsrc/tutorials/getting_started.rst index 73bd3b0..8e4c7cd 100644 --- a/docsrc/tutorials/getting_started.rst +++ b/docsrc/tutorials/getting_started.rst @@ -72,7 +72,7 @@ Create a directory for your project and in that directory, create a file called This will serve as input for our example. -Now we need to parse it. Create a file called "main.d". Paste following code +Now we need to parse it. Create a file called ``main.d``. Paste following code into the file: .. code-block:: d @@ -82,12 +82,18 @@ into the file: void main() { + //Read the input. Node root = Loader("input.yaml").load(); + + //Display the data read. foreach(string word; root["Hello World"]) { writeln(word); } writeln("The answer is ", root["Answer"].get!int); + + //Dump the loaded document to output.yaml. + Dumper("output.yaml").dump(root); } @@ -98,8 +104,8 @@ Explanation of the code First, we import the *yaml* module. This is the only module you need to import to use D:YAML - it automatically imports all needed modules. -Next we load the file using the *Loader.load()* method. *Loader* is the struct -used for parsing YAML documents, and *load()* is a method that loads the file as +Next we load the file using the *Loader.load()* method. *Loader* is a struct +used for parsing YAML documents. The *load()* method loads the file as **one** YAML document, or throws *YAMLException*, D:YAML exception type, if the file could not be parsed or does not contain exactly one document. Note that we don't do any error checking here in order to keep the example as simple as @@ -126,6 +132,15 @@ The *Node.get()* method is used to get value of a scalar node, allowing to specify type. D:YAML will try to return the scalar as this type, converting if needed, throwing *YAMLException* if not possible. +Finally we dump the document we just read to ``output.yaml`` with the +*Dumper.dump()* method. *Dumper* is a struct used to dump YAML documents. +The *dump()* method writes one or more documents to a file, throwing +*YAMLException* if the file could not be written to. + +D:YAML doesn't preserve style information in documents, so even though +``output.yaml`` will contain the same data as ``input.yaml``, it might be +formatted differently. Comments are not preserved, either. + ^^^^^^^^^ Compiling diff --git a/dyaml/dumper.d b/dyaml/dumper.d index bfd59e1..f0e9109 100644 --- a/dyaml/dumper.d +++ b/dyaml/dumper.d @@ -152,7 +152,7 @@ struct Dumper */ this(string filename) { - try{this(new File(filename));} + try{this(new File(filename, FileMode.OutNew));} catch(StreamException e) { throw new YAMLException("Unable to use file for YAML dumping " ~ filename ~ " : " ~ e.msg); diff --git a/dyaml/representer.d b/dyaml/representer.d index 0defeb4..f6a3f71 100644 --- a/dyaml/representer.d +++ b/dyaml/representer.d @@ -5,7 +5,8 @@ // http://www.boost.org/LICENSE_1_0.txt) /** - * YAML node _representer. + * YAML node _representer. Prepares YAML nodes for output. A tutorial can be + * found $(LINK2 ../tutorials/custom_types.html, here). * * Code based on $(LINK2 http://www.pyyaml.org, PyYAML). */ diff --git a/examples/getting_started/main.d b/examples/getting_started/main.d index eb0567b..26cd944 100644 --- a/examples/getting_started/main.d +++ b/examples/getting_started/main.d @@ -3,10 +3,16 @@ import yaml; void main() { - yaml.Node root = Loader("input.yaml").load(); + //Read the input. + Node root = Loader("input.yaml").load(); + + //Display the data read. foreach(string word; root["Hello World"]) { writeln(word); } writeln("The answer is ", root["Answer"].get!int); + + //Dump the loaded document to output.yaml. + Dumper("output.yaml").dump(root); } diff --git a/examples/representer/Makefile b/examples/representer/Makefile new file mode 100644 index 0000000..55dfe3d --- /dev/null +++ b/examples/representer/Makefile @@ -0,0 +1,2 @@ +main: + dmd -w -I../../ -L-L../../ -L-ldyaml main.d diff --git a/examples/representer/main.d b/examples/representer/main.d new file mode 100644 index 0000000..7c30007 --- /dev/null +++ b/examples/representer/main.d @@ -0,0 +1,55 @@ +import std.stdio; +import yaml; + +struct Color +{ + ubyte red; + ubyte green; + ubyte blue; +} + +Node representColor(ref Node node, Representer representer) +{ + //The node is guaranteed to be Color as we add representer for Color. + Color color = node.get!Color; + + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [color.red, color.green, color.blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return representer.representScalar("!color", scalar); +} + +void main() +{ + try + { + auto representer = new Representer; + representer.addRepresenter!Color(&representColor); + + auto resolver = new Resolver; + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + + auto dumper = Dumper("output.yaml"); + dumper.representer = representer; + dumper.resolver = resolver; + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(document); + } + catch(YAMLException e) + { + writeln(e.msg); + } +}