convert docs to markdown and remove built doc artifacts (#153)

convert docs to markdown and remove built doc artifacts
merged-on-behalf-of: BBasile <BBasile@users.noreply.github.com>
This commit is contained in:
Cameron Ross 2018-06-12 02:57:28 -03:00 committed by The Dlang Bot
parent ab0e2c0519
commit 03c9972485
83 changed files with 656 additions and 10839 deletions

View file

@ -0,0 +1,64 @@
# Differences between D:YAML and the YAML specification
There are some differences between D:YAML and the YAML 1.1
specification. Some are caused by difficulty of implementation of some
features, such as multiple Unicode encodings within single stream, and
some by unnecessary restrictions or ambiguities in the specification.
Still, D:YAML tries to be as close to the specification as possible. It
should never load documents with different meaning than according to the
specification, and documents that fail to load should be very rare (for
instance, very few files use multiple Unicode encodings).
## List of known differences:
Differences that can cause valid YAML documents not to load:
- No support for byte order marks and multiple Unicode encodings in a
stream.
- Plain scalars in flow context cannot contain `,`, `:` and `?`. This
might change with `:` in the future. See
<http://pyyaml.org/wiki/YAMLColonInFlowContext> for details.
- The specification does not restrict characters for anchors and
aliases. This may lead to problems, for instance, the document:
[ *alias, value ]
can be interpteted in two ways, as:
[ "value" ]
and:
[ *alias , "value" ]
Therefore we restrict aliases and anchors to ASCII alphanumeric
characters.
- The specification is confusing about tabs in plain scalars. We don't
use tabs in plain scalars at all.
- There is no support for recursive data structures in DYAML.
Other differences:
- Indentation is ignored in the flow context, which is less
restrictive than the specification. This allows code such as:
key: {
}
- Indentation rules for quoted scalars are loosed: They don't need to
adhere indentation as `"` and `'` clearly mark the beginning and the
end of them.
- We allow `_` in tag handles.
- Right now, two mappings with the same contents but different
orderings are considered unequal, even if they are unordered
mappings. This is because all mappings are ordered in the D:YAML
implementation. This should change in future, once D associative
arrays work with variant types or a map class or struct appears in
Phobos.

11
docs/index.md Normal file
View file

@ -0,0 +1,11 @@
# Welcome to D:YAML documentation!
API Documentation [online](https://dyaml.dpldocs.info/dyaml.html)
Tutorials:
- [Getting Started](tutorials/getting_started.md)
- [Custom Types](tutorials/custom_types.md)
- [YAML Syntax](tutorials/yaml_syntax.md)
Articles:
- [Spec Differences](articles/spec_differences.md)

BIN
docs/logo128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
docs/logo210.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

@ -0,0 +1,336 @@
# Custom YAML data types
Sometimes you need to serialize complex data types such as classes. To
do this you could use plain nodes such as mappings with classes' fields.
YAML also supports custom types with identifiers called *tags*. That is
the topic of this tutorial.
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* 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.
## Constructor
D:YAML uses the [Constructor](https://dyaml.dpldocs.info/dyaml.constructor.Constructor.html)
class to process each node to hold data type corresponding to its tag.
*Constructor* stores functions to process each supported tag. These are
supplied by the user using the *addConstructorXXX()* methods, where
*XXX* is *Scalar*, *Sequence* or *Mapping*. *Constructor* is then passed
to *Loader*, which parses YAML input.
Structs and classes must implement the *opCmp()* operator for YAML
support. This is used for duplicate detection in mappings, sorting and
equality comparisons of nodes. The signature of the operator that must
be implemented is `const int opCmp(ref const MyStruct s)` for structs
where *MyStruct* is the struct type, and `int opCmp(Object o)` for
classes. Note that the class *opCmp()* should not alter the compared
values - it is not const for compatibility reasons.
We will implement support for an RGB color type. It is implemented as
the following struct:
```D
struct Color
{
ubyte red;
ubyte green;
ubyte blue;
const int opCmp(ref const Color c)
{
if(red != c.red) {return red - c.red;}
if(green != c.green){return green - c.green;}
if(blue != c.blue) {return blue - c.blue;}
return 0;
}
}
```
First, we need a function to construct our data type. The function will
take a reference to *Node* to construct from. The node is guaranteed to
contain either a *string*, an array of *Node* or of *Node.Pair*,
depending on whether we're constructing our value from a scalar,
sequence, or mapping, respectively. If this function throws any
exception, D:YAML handles it and adds its message to a *YAMLException*
that will be thrown when loading the file.
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:
```D
Color constructColorScalar(ref Node node)
{
string value = node.as!string;
if(value.length != 6)
{
throw new Exception("Invalid color: " ~ value);
}
//We don't need to check for uppercase chars this way.
value = value.toLower();
//Get value of a hex digit.
uint hex(char c)
{
import std.ascii;
if(!std.ascii.isHexDigit(c))
{
throw new Exception("Invalid color: " ~ value);
}
if(std.ascii.isDigit(c))
{
return c - '0';
}
return c - 'a' + 10;
}
Color result;
result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1]));
result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3]));
result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5]));
return result;
}
Color constructColorMapping(ref Node node)
{
ubyte r,g,b;
//Might throw if a value is missing is not an integer, or is out of range.
//If this happens, D:YAML will handle the exception and use its message
//in a YAMLException thrown when loading.
r = node["r"].as!ubyte;
g = node["g"].as!ubyte;
b = node["b"].as!ubyte;
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:
```YAML
scalar-red: !color FF0000
scalar-orange: !color FFFF00
mapping-red: !color-mapping {r: 255, g: 0, b: 0}
mapping-orange:
!color-mapping
r: 255
g: 255
b: 0
```
You can see that we're using tag `!color` for scalar colors, and
`!color-mapping` for colors expressed as mappings.
Finally, the code to put it all together:
```D
void main()
{
auto red = Color(255, 0, 0);
auto orange = Color(255, 255, 0);
try
{
auto constructor = new Constructor;
//both functions handle the same tag, but one handles scalar, one mapping.
constructor.addConstructorScalar("!color", &constructColorScalar);
constructor.addConstructorMapping("!color-mapping", &constructColorMapping);
auto loader = Loader("input.yaml");
loader.constructor = constructor;
auto root = loader.load();
if(root["scalar-red"].as!Color == red &&
root["mapping-red"].as!Color == red &&
root["scalar-orange"].as!Color == orange &&
root["mapping-orange"].as!Color == orange)
{
writeln("SUCCESS");
return;
}
}
catch(YAMLException e)
{
writeln(e.msg);
}
writeln("FAILURE");
}
```
First, we create a *Constructor* and pass functions to handle the
`!color` 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 to test if they were loaded as expected.
You can find the source code for what we've done so far in the
`examples/constructor` directory in the D:YAML package.
## Resolver
Specifying tag for every color can be tedious. D:YAML can implicitly
resolve scalar tags using regular expressions. This is how default types
are resolved. We will use the [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 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 be resolvable as any non-string YAML data type.
Add this to your code to add implicit resolution of `!color`.
```D
//code from the previous example...
auto resolver = new Resolver;
import std.regex;
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
"0123456789abcdefABCDEF");
auto loader = Loader("input.yaml");
loader.constructor = constructor;
loader.resolver = resolver;
//code from the previous example...
```
Now, change contents of `input.yaml` to this:
```YAML
scalar-red: FF0000
scalar-orange: FFFF00
mapping-red: !color-mapping {r: 255, g: 0, b: 0}
mapping-orange:
!color-mapping
r: 255
g: 255
b: 0
```
We no longer need to specify the tag for scalar color values. Compile
and test the example. If everything went as expected, it should report
success.
You can find the complete code in the `examples/resolver` directory in
the D:YAML package.
## Representer
Now that you can load custom data types, it might be good to know how to
dump them. D:YAML uses the [Representer](https://dyaml.dpldocs.info/dyaml.representer.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 function per type can be specified. This is asserted
in *addRepresenter()* preconditions. Default YAML types already have
representer functions specified, but you can disable them by
constructing *Representer* with the *useDefaultRepresenters* parameter
set to false.
By default, tags are explicitly output for all non-default types. To
make dumped tags implicit, you can pass a *Resolver* that will resolve
them implicitly. Of course, you will need to use an identical *Resolver*
when loading the output.
With the following code, we will add support for dumping the our Color
type.
```D
Node representColor(ref Node node, Representer representer)
{
//The node is guaranteed to be Color as we add representer for Color.
Color color = node.as!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 CSS-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](https://dyaml.dpldocs.info/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.
```D
void main()
{
try
{
auto representer = new Representer;
representer.addRepresenter!Color(&representColor);
auto resolver = new Resolver;
import std.regex;
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
"0123456789abcdefABCDEF");
auto dumper = Dumper("output.yaml");
dumper.representer = representer;
dumper.resolver = resolver;
auto document = Node([Color(255, 0, 0),
Color(0, 255, 0),
Color(0, 0, 255)]);
dumper.dump(document);
}
catch(YAMLException e)
{
writeln(e.msg);
}
}
```
We construct a new *Representer*, and specify a representer function for
the *Color* (the template argument) type. We also construct a
*Resolver*, same as in the previous section, so the `!color` tag will be
implicit. Of course, identical *Resolver* would then have to be used
when loading the file. You don't need to do this if you want the tag to
be explicit.
We construct a *Dumper* to file `output.yaml` and pass the *Representer*
and *Resolver* to it. Then, we create a simple node containing a
sequence of colors and finally, we dump it.
Source code for this section can be found in the `examples/representer`
directory of the D:YAML package.

View file

@ -0,0 +1,164 @@
# Getting started
Welcome to D:YAML\! D:YAML is a
[YAML](http://en.wikipedia.org/wiki/YAML) parser library for the [D
programming language](http://dlang.org). This tutorial will explain how
to set D:YAML up and use it in your projects.
This is meant to be the **simplest possible** introduction to D:YAML.
Some of this information might already be known to you. Only basic usage
is covered.
## Setting up
### Install the DMD compiler
Digital Mars D compiler, or DMD, is the most commonly used D compiler.
You can find its newest version [here](http://dlang.org/download.html).
Download the version of DMD for your operating system and install it.
Note: Other D compilers exist, such as [GDC](http://gdcproject.org/) and
[LDC](https://github.com/ldc-developers/ldc).
### Install dub
[dub](http://code.dlang.org/about) is a build system and package manager
for D. It is the standard way to manage D projects and their
dependencies, compilation and so on.
DMD may include DUB in future releases, but at this point we need to
install it separately. See [installation
instructions](https://github.com/D-Programming-Language/dub#installation).
## Your first D:YAML project
Create a directory for your project and in that directory, create a new
file named `input.yaml` and paste this code into the file:
```YAML
Hello World : [Hello, World]
Answer: 42
```
This will serve as input for our example.
Now we need to parse it. Create a new file with name `main.d`. Paste
following code into the file:
```D
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"].as!int);
//Dump the loaded document to output.yaml.
Dumper("output.yaml").dump(root);
}
```
### Explanation of the code
First, we import the *dyaml.all* module. This is the only D:YAML module
you need to import - it automatically imports all needed modules.
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 contains more than
one document. Note that we don't do any error checking here in order to
keep the example as simple as possible.
*Node* represents a node in a YAML document. It can be a sequence
(array), mapping (associative array) or a scalar (value). Here the root
node is a mapping, and we use the index operator to get subnodes with
keys "Hello World" and "Answer". We iterate over the former, as it is a
sequence, and use the *Node.as()* method on the latter to read its value
as an integer.
You can iterate over a mapping or sequence as if it was an associative
or normal array, respectively. If you try to iterate over a scalar, it
will throw a *YAMLException*.
You can iterate using *Node* as the iterated type, or specify the type
iterated nodes are expected to have. D:YAML will automatically convert
to that type if possible. Here we specify the *string* type, so we
iterate over the "Hello World" sequence as an array of strings. If it is
not possible to convert to iterated type, a *YAMLException* is thrown.
For instance, if we specified *int* here, we would get an error, as
"Hello" cannot be converted to an integer.
The *Node.as()* method is used to read value of a scalar node as
specified type. If the scalar does not have the specified type, D:YAML
will try to convert it, 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 tries to preserve style information in documents so e.g. `[Hello,
World]` is not turned into:
```YAML
- Hello
- World
```
However, comments are not preserved and neither are any extra formatting
whitespace that doesn't affect the meaning of YAML contents.
### Compiling
We're going to use dub, which we installed at the beginning, to compile
our project.
Create a file called `dub.json` with the following contents:
```JSON
{
"name": "getting-started",
"targetType": "executable",
"sourceFiles": ["main.d"],
"mainSourceFile": "main.d",
"dependencies":
{
"dyaml": { "version" : "~>0.5.0" },
},
}
```
This file tells dub that we're building an executable called
`getting-started` from a D source file `main.d`, and that our project
depends on D:YAML 0.5.0 or any newer, bugfix release of D:YAML 0.5 . DUB
will automatically find and download the correct version of D:YAML when
the project is built.
Now run the following command in your project's directory:
dub build
dub will automatically download D:YAML and compile it, and then then it
will compile our program. This will generate an executable called
`getting-started` or `getting-started.exe` in your directory. When you
run it, it should produce the following output:
Hello
World
The answer is 42
### Conclusion
You should now have a basic idea about how to use D:YAML. To learn more,
look at the [API documentation](https://dyaml.dpldocs.info/dyaml.html) and other tutorials.
You can find code for this example in the `example/getting_started`
directory in the package.

View file

@ -0,0 +1,241 @@
# YAML syntax
This is an introduction to the most common YAML constructs. For more detailed
information, see [PyYAML documentation](http://pyyaml.org/wiki/PyYAMLDocumentation),
which this article is based on,
[Chapter 2 of the YAML specification](http://yaml.org/spec/1.1/#id857168)
or the [Wikipedia page](http://en.wikipedia.org/wiki/YAML).
YAML is a data serialization format designed for human readability. YAML is a
recursive acronym for "YAML Ain't Markup Language".
YAML is similar to JSON, and in fact, JSON is a subset of YAML 1.2; but YAML has
some more advanced features and is easier to read. However, it is also more
difficult to parse (and probably somewhat slower). Data is stored in mappings
(associative arrays), sequences (lists) and scalars (single values). Data
structure hierarchy depends either on indentation (block context, similar to
Python code), or nesting of brackets and braces (flow context, similar to JSON).
YAML comments begin with `#` and continue until the end of line.
## Documents
A YAML stream consists of one or more documents starting with `---` and
optionally ending with `...` . `---` can be left out for the first document.
Single document with no explicit start or end:
```
- Red
- Green
- Blue
```
Same document with explicit start and end:
```
---
- Red
- Green
- Blue
...
```
A stream containing multiple documents:
```
---
- Red
- Green
- Blue
---
- Linux
- BSD
---
answer : 42
```
## Sequences
Sequences are arrays of nodes of any type, similar e.g. to Python lists.
In block context, each item begins with hyphen+space "- ". In flow context,
sequences have syntax similar to D arrays.
```
#Block context
- Red
- Green
- Blue
```
```
#Flow context
[Red, Green, Blue]
```
```
#Nested
-
- Red
- Green
- Blue
-
- Linux
- BSD
```
```
#Nested flow
[[Red, Green, Blue], [Linux, BSD]]
```
```
#Nested in a mapping
Colors:
- Red
- Green
- Blue
Operating systems:
- Linux
- BSD
```
## Mappings
Mappings are associative arrays where each key and value can be of any type,
similar e.g. to Python dictionaries. In block context, keys and values are
separated by colon+space ": ". In flow context, mappings have syntax similar
to D associative arrays, but with braces instead of brackets:
```
#Block context
CPU: Athlon
GPU: Radeon
OS: Linux
```
```
#Flow context
{CPU: Athlon, GPU: Radeon, OS: Linux}
```
```
#Nested
PC:
CPU: Athlon
GPU: Radeon
OS: Debian
Phone:
CPU: Cortex
GPU: PowerVR
OS: Android
```
```
#Nested flow
{PC: {CPU: Athlon, GPU: Radeon, OS: Debian},
Phone: {CPU: Cortex, GPU: PowerVR, OS: Android}}
```
```
#Nested in a sequence
- CPU: Athlon
GPU: Radeon
OS: Debian
- CPU: Cortex
GPU: PowerVR
OS: Android
```
Complex keys start with question mark+space "? ".
```
#Nested in a sequence
? [CPU, GPU]: [Athlon, Radeon]
OS: Debian
```
## Scalars
Scalars are simple values such as integers, strings, timestamps and so on.
There are multiple scalar styles.
Plain scalars use no quotes, start with the first non-space and end with the
last non-space character:
```
scalar: Plain scalar
```
Single quoted scalars start and end with single quotes. A single quote is
represented by a pair of single quotes ''.
```
scalar: 'Single quoted scalar ending with some spaces '
```
Double quoted scalars support C-style escape sequences.
```
scalar: "Double quoted scalar \n with some \\ escape sequences"
```
Block scalars are convenient for multi-line values. They start either with
`|` or with `>`. With `|`, the newlines in the scalar are preserved.
With `>`, the newlines between two non-empty lines are removed.
```
scalar: |
Newlines are preserved
First line
Second line
```
```
scalar: >
Newlines are folded
This is still the first paragraph
This is the second
paragraph
```
## Anchors and aliases
Anchors and aliases can reduce size of YAML code by allowing you to define a
value once, assign an anchor to it and use alias referring to that anchor
anywhere else you need that value. It is possible to use this to create
recursive data structures and some parsers support this; however, D:YAML does
not (this might change in the future, but it is unlikely).
```
Person: &AD
gender: male
name: Arthur Dent
Clone: *AD
```
## Tags
Tags are identifiers that specify data types of YAML nodes. Most default YAML
tags are resolved implicitly, so there is no need to specify them. D:YAML also
supports implicit resolution for custom, user specified tags.
Explicitly specified tags:
```
answer: !!int "42"
name: !!str "Arthur Dent"
```
Implicit tags:
```
answer: 42 #int
name: Arthur Dent #string
```
This table shows D types stored in *yaml.Node* default YAML tags are converted to.
Some of these might change in the future (especially !!map and !!set).
|YAML tag |D type |
|-----------------------|---------------------|
|!!null |yaml.YAMLNull |
|!!bool |bool |
|!!int |long |
|!!float |real |
|!!binary |ubyte[] |
|!!timestamp |std.datetime.SysTime |
|!!map, !!omap, !!pairs |yaml.Node.Pair[] |
|!!seq, !!set |yaml.Node[] |
|!!str |string |