convert examples to doc'd unittests, fix some parameter errors, remove some redundancy

This commit is contained in:
Cameron Ross 2018-04-07 17:36:38 -03:00
parent 7b316fdffb
commit 9d35b773b4
No known key found for this signature in database
GPG key ID: 777897D98DC91C54
11 changed files with 492 additions and 545 deletions

View file

@ -137,47 +137,6 @@ final class Constructor
*
* Params: tag = Tag for the function to handle.
* ctor = Constructor function.
*
* Example:
*
* --------------------
* import std.string;
*
* import dyaml.all;
*
* struct MyStruct
* {
* int x, y, z;
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* const int opCmp(ref const MyStruct s)
* {
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
* }
*
* MyStruct constructMyStructScalar(ref Node node)
* {
* //Guaranteed to be string as we construct from scalar.
* //!mystruct x:y:z
* auto parts = node.as!string().split(":");
* // 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]));
* }
*
* void main()
* {
* auto loader = Loader("file.yaml");
* auto constructor = new Constructor;
* constructor.addConstructorScalar("!mystruct", &constructMyStructScalar);
* loader.constructor = constructor;
* Node node = loader.load();
* }
* --------------------
*/
void addConstructorScalar(T)(const string tag, T function(ref Node) ctor)
{
@ -185,49 +144,44 @@ final class Constructor
auto deleg = addConstructor!T(t, ctor);
(*delegates!string)[t] = deleg;
}
///
@safe unittest
{
static struct MyStruct
{
int x, y, z;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
const int opCmp(ref const MyStruct s)
{
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
}
static MyStruct constructMyStructScalar(ref Node node) @safe
{
//Guaranteed to be string as we construct from scalar.
//!mystruct x:y:z
auto parts = node.as!string().split(":");
// 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]));
}
auto loader = Loader.fromString("!mystruct 12:34:56".dup);
auto constructor = new Constructor;
constructor.addConstructorScalar("!mystruct", &constructMyStructScalar);
loader.constructor = constructor;
Node node = loader.load();
assert(node.get!MyStruct == MyStruct(12, 34, 56));
}
/** Add a constructor function from sequence.
*
* See_Also: addConstructorScalar
*
* Example:
*
* --------------------
* import std.string;
*
* import dyaml.all;
*
* struct MyStruct
* {
* int x, y, z;
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* const int opCmp(ref const MyStruct s)
* {
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
* }
*
* MyStruct constructMyStructSequence(ref Node node)
* {
* //node is guaranteed to be sequence.
* //!mystruct [x, y, z]
* return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
* }
*
* void main()
* {
* auto loader = Loader("file.yaml");
* auto constructor = new Constructor;
* constructor.addConstructorSequence("!mystruct", &constructMyStructSequence);
* loader.constructor = constructor;
* Node node = loader.load();
* }
* --------------------
*/
void addConstructorSequence(T)(const string tag, T function(ref Node) ctor)
{
@ -235,49 +189,40 @@ final class Constructor
auto deleg = addConstructor!T(t, ctor);
(*delegates!(Node[]))[t] = deleg;
}
///
@safe unittest {
static struct MyStruct
{
int x, y, z;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
const int opCmp(ref const MyStruct s)
{
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
}
static MyStruct constructMyStructSequence(ref Node node) @safe
{
//node is guaranteed to be sequence.
//!mystruct [x, y, z]
return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
}
auto loader = Loader.fromString("!mystruct [1,2,3]".dup);
auto constructor = new Constructor;
constructor.addConstructorSequence("!mystruct", &constructMyStructSequence);
loader.constructor = constructor;
Node node = loader.load();
assert(node.get!MyStruct == MyStruct(1, 2, 3));
}
/** Add a constructor function from a mapping.
*
* See_Also: addConstructorScalar
*
* Example:
*
* --------------------
* import std.string;
*
* import dyaml.all;
*
* struct MyStruct
* {
* int x, y, z;
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* const int opCmp(ref const MyStruct s)
* {
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
* }
*
* MyStruct constructMyStructMapping(ref Node node)
* {
* //node is guaranteed to be mapping.
* //!mystruct {"x": x, "y": y, "z": z}
* return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
* }
*
* void main()
* {
* auto loader = Loader("file.yaml");
* auto constructor = new Constructor;
* constructor.addConstructorMapping("!mystruct", &constructMyStructMapping);
* loader.constructor = constructor;
* Node node = loader.load();
* }
* --------------------
*/
void addConstructorMapping(T)(const string tag, T function(ref Node) ctor)
{
@ -285,6 +230,36 @@ final class Constructor
auto deleg = addConstructor!T(t, ctor);
(*delegates!(Node.Pair[]))[t] = deleg;
}
///
@safe unittest {
static struct MyStruct
{
int x, y, z;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
const int opCmp(ref const MyStruct s)
{
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
}
static MyStruct constructMyStructMapping(ref Node node) @safe
{
//node is guaranteed to be mapping.
//!mystruct {"x": x, "y": y, "z": z}
return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
}
auto loader = Loader.fromString(`!mystruct {"x": 11, "y": 22, "z": 33}`.dup);
auto constructor = new Constructor;
constructor.addConstructorMapping("!mystruct", &constructMyStructMapping);
loader.constructor = constructor;
Node node = loader.load();
assert(node.get!MyStruct == MyStruct(11, 22, 33));
}
package:
/*

View file

@ -31,52 +31,10 @@ import dyaml.tagdirective;
/**
* Dumps YAML documents to files or streams.
*
* User specified Representer and/or Resolver can be used to support new
* User specified Representer and/or Resolver can be used to support new
* tags / data types.
*
* Setters are provided to affect output details (style, encoding, etc.).
*
* Examples:
*
* Write to a file:
* --------------------
* auto node = Node([1, 2, 3, 4, 5]);
* Dumper("file.yaml").dump(node);
* --------------------
*
* Write multiple YAML documents to a file:
* --------------------
* auto node1 = Node([1, 2, 3, 4, 5]);
* auto node2 = Node("This document contains only one string");
* Dumper("file.yaml").dump(node1, node2);
*
* //Or with an array:
* //Dumper("file.yaml").dump([node1, node2]);
*
*
* --------------------
*
* Write to memory:
* --------------------
* import std.stream;
* auto stream = new YMemoryStream();
* auto node = Node([1, 2, 3, 4, 5]);
* Dumper(stream).dump(node);
* --------------------
*
* Use a custom representer/resolver to support custom data types and/or implicit tags:
* --------------------
* auto node = Node([1, 2, 3, 4, 5]);
* auto representer = new Representer();
* auto resolver = new Resolver();
*
* //Add representer functions / resolver expressions here...
*
* auto dumper = Dumper("file.yaml");
* dumper.representer = representer;
* dumper.resolver = resolver;
* dumper.dump(node);
* --------------------
*/
struct Dumper
{
@ -271,21 +229,10 @@ struct Dumper
*
* Each prefix MUST not be empty.
*
* The "!!" handle is used for default YAML _tags with prefix
* The "!!" handle is used for default YAML _tags with prefix
* "tag:yaml.org,2002:". This can be overridden.
*
* Params: tags = Tag directives (keys are handles, values are prefixes).
*
* Example:
* --------------------
* Dumper dumper = Dumper("file.yaml");
* string[string] directives;
* directives["!short!"] = "tag:long.org,2011:";
* //This will emit tags starting with "tag:long.org,2011"
* //with a "!short!" prefix instead.
* dumper.tagDirectives(directives);
* dumper.dump(Node("foo"));
* --------------------
*/
@property void tagDirectives(string[string] tags) pure @safe
{
@ -300,6 +247,17 @@ struct Dumper
}
tags_ = t;
}
///
@safe unittest
{
Dumper dumper = Dumper("example.yaml");
string[string] directives;
directives["!short!"] = "tag:long.org,2011:";
//This will emit tags starting with "tag:long.org,2011"
//with a "!short!" prefix instead.
dumper.tagDirectives(directives);
dumper.dump(Node("foo"));
}
/**
* Dump one or more YAML _documents to the file/stream.
@ -357,3 +315,38 @@ struct Dumper
}
}
}
///Write to a file
@safe unittest
{
auto node = Node([1, 2, 3, 4, 5]);
Dumper("example.yaml").dump(node);
}
///Write multiple YAML documents to a file
@safe unittest
{
auto node1 = Node([1, 2, 3, 4, 5]);
auto node2 = Node("This document contains only one string");
Dumper("example.yaml").dump(node1, node2);
//Or with an array:
Dumper("example.yaml").dump([node1, node2]);
}
///Write to memory
@safe unittest
{
import dyaml.stream;
auto stream = new YMemoryStream();
auto node = Node([1, 2, 3, 4, 5]);
Dumper(stream).dump(node);
}
///Use a custom representer/resolver to support custom data types and/or implicit tags
@safe unittest
{
auto node = Node([1, 2, 3, 4, 5]);
auto representer = new Representer();
auto resolver = new Resolver();
//Add representer functions / resolver expressions here...
auto dumper = Dumper("example.yaml");
dumper.representer = representer;
dumper.resolver = resolver;
dumper.dump(node);
}

View file

@ -123,6 +123,7 @@ Event event(EventID id)(const Mark start, const Mark end, const string anchor =
* anchor = Anchor of the sequence, if any.
* tag = Tag of the sequence, if specified.
* implicit = Should the tag be implicitly resolved?
* style = Style to use when outputting document.
*/
Event collectionStartEvent(EventID id)
(const Mark start, const Mark end, const string anchor, const string tag,

View file

@ -17,20 +17,6 @@ package:
* Struct holding multiple named boolean values in a single byte.
*
* Can hold at most 8 values.
*
* Example:
* --------------------
* Flags!("empty", "multiline") flags;
* assert(flags.empty == false && flags.multiline == false);
* flags.multiline = true;
* assert(flags.empty == false && flags.multiline == true);
* flags.empty = true;
* assert(flags.empty == true && flags.multiline == true);
* flags.multiline = false;
* assert(flags.empty == true && flags.multiline == false);
* flags.empty = false;
* assert(flags.empty == false && flags.multiline == false);
* --------------------
*/
struct Flags(names ...) if(names.length <= 8)
{
@ -72,6 +58,7 @@ struct Flags(names ...) if(names.length <= 8)
///Flag accessors.
mixin(flags(names));
}
///
@safe unittest
{
import std.stdio;

View file

@ -23,22 +23,22 @@ import dyaml.style;
* However, determining style may be useful in some cases, e.g. YAML utilities.
*
* May only be called on scalar nodes (nodes where node.isScalar() == true).
*
* Example:
* --------------------
* // Node node // loaded from a file
* if(node.isScalar)
* {
* import std.stdio;
* writeln(node.scalarStyleHack());
* }
* --------------------
*/
ScalarStyle scalarStyleHack(ref const(Node) node) @safe nothrow
{
assert(node.isScalar, "Trying to get scalar style of a non-scalar node");
return node.scalarStyle;
}
///
@safe unittest
{
import dyaml;
Node node = Loader.fromString(`"42"`.dup).load(); // loaded from a file
if(node.isScalar)
{
assert(node.scalarStyleHack() == ScalarStyle.DoubleQuoted);
}
}
@safe unittest
{
writeln("D:YAML scalarStyleHack getter unittest");

View file

@ -28,74 +28,6 @@ import dyaml.token;
*
* User specified Constructor and/or Resolver can be used to support new
* tags / data types.
*
* Examples:
*
* Load single YAML document from a file:
* --------------------
* auto rootNode = Loader("file.yaml").load();
* ...
* --------------------
*
* Load all YAML documents from a file:
* --------------------
* auto nodes = Loader("file.yaml").loadAll();
* ...
* --------------------
*
* Iterate over YAML documents in a file, lazily loading them:
* --------------------
* auto loader = Loader("file.yaml");
*
* foreach(ref node; loader)
* {
* ...
* }
* --------------------
*
* Load YAML from a string:
* --------------------
* char[] yaml_input = "red: '#ff0000'\n"
* "green: '#00ff00'\n"
* "blue: '#0000ff'".dup;
*
* auto colors = Loader.fromString(yaml_input).load();
*
* foreach(string color, string value; colors)
* {
* import std.stdio;
* writeln(color, " is ", value, " in HTML/CSS");
* }
* --------------------
*
* Load a file into a buffer in memory and then load YAML from that buffer:
* --------------------
* try
* {
* import std.file;
* void[] buffer = std.file.read("file.yaml");
* auto yamlNode = Loader(buffer);
*
* // Read data from yamlNode here...
* }
* catch(FileException e)
* {
* writeln("Failed to read file 'file.yaml'");
* }
* --------------------
*
* Use a custom constructor/resolver to support custom data types and/or implicit tags:
* --------------------
* auto constructor = new Constructor();
* auto resolver = new Resolver();
*
* // Add constructor functions / resolver expressions here...
*
* auto loader = Loader("file.yaml");
* loader.constructor = constructor;
* loader.resolver = resolver;
* auto rootNode = loader.load(node);
* --------------------
*/
struct Loader
{
@ -375,7 +307,48 @@ struct Loader
if(constructor_ is null) { constructor_ = new Constructor(); }
}
}
/// Load single YAML document from a file:
@safe unittest
{
write("example.yaml", "Hello world!");
auto rootNode = Loader("example.yaml").load();
assert(rootNode == "Hello world!");
}
/// Load all YAML documents from a file:
@safe unittest
{
import std.file : write;
write("example.yaml",
"---\n"~
"Hello world!\n"~
"...\n"~
"---\n"~
"Hello world 2!\n"~
"...\n"
);
auto nodes = Loader("example.yaml").loadAll();
assert(nodes.length == 2);
}
/// Iterate over YAML documents in a file, lazily loading them:
@safe unittest
{
import std.file : write;
write("example.yaml",
"---\n"~
"Hello world!\n"~
"...\n"~
"---\n"~
"Hello world 2!\n"~
"...\n"
);
auto loader = Loader("example.yaml");
foreach(ref node; loader)
{
//Do something
}
}
/// Load YAML from a string:
@safe unittest
{
char[] yaml_input = ("red: '#ff0000'\n" ~
@ -390,3 +363,50 @@ struct Loader
writeln(color, " is ", value, " in HTML/CSS");
}
}
/// Load a file into a buffer in memory and then load YAML from that buffer:
@safe unittest
{
import std.file : read, write;
import std.stdio : writeln;
// Create a yaml document
write("example.yaml",
"---\n"~
"Hello world!\n"~
"...\n"~
"---\n"~
"Hello world 2!\n"~
"...\n"
);
try
{
void[] buffer = read("example.yaml");
auto yamlNode = Loader(buffer);
// Read data from yamlNode here...
}
catch(FileException e)
{
writeln("Failed to read file 'example.yaml'");
}
}
/// Use a custom constructor/resolver to support custom data types and/or implicit tags:
@safe unittest
{
import std.file : write;
// Create a yaml document
write("example.yaml",
"---\n"~
"Hello world!\n"~
"...\n"
);
auto constructor = new Constructor();
auto resolver = new Resolver();
// Add constructor functions / resolver expressions here...
auto loader = Loader("example.yaml");
loader.constructor = constructor;
loader.resolver = resolver;
auto rootNode = loader.load();
}

View file

@ -311,13 +311,6 @@ struct Node
* must be in full form, e.g. "tag:yaml.org,2002:set",
* not a shortcut, like "!!set".
*
* Examples:
* --------------------
* // Will be emitted as a sequence (default for arrays)
* auto seq = Node([1, 2, 3, 4, 5]);
* // Will be emitted as a set (overriden tag)
* auto set = Node([1, 2, 3, 4, 5], "tag:yaml.org,2002:set");
* --------------------
*/
this(T)(T[] array, const string tag = null) @trusted
if (!isSomeString!(T[]))
@ -341,6 +334,14 @@ struct Node
value_ = Value(nodes);
}
}
///
@safe unittest
{
// Will be emitted as a sequence (default for arrays)
auto seq = Node([1, 2, 3, 4, 5]);
// Will be emitted as a set (overriden tag)
auto set = Node([1, 2, 3, 4, 5], "tag:yaml.org,2002:set");
}
@safe unittest
{
with(Node([1, 2, 3]))
@ -350,10 +351,6 @@ struct Node
assert(opIndex(2).as!int == 3);
}
// Will be emitted as a sequence (default for arrays)
auto seq = Node([1, 2, 3, 4, 5]);
// Will be emitted as a set (overriden tag)
auto set = Node([1, 2, 3, 4, 5], "tag:yaml.org,2002:set");
}
/** Construct a node from an associative _array.
@ -373,15 +370,6 @@ struct Node
* in full form, e.g. "tag:yaml.org,2002:omap", not a
* shortcut, like "!!omap".
*
* Examples:
* --------------------
* // Will be emitted as an unordered mapping (default for mappings)
* auto map = Node([1 : "a", 2 : "b"]);
* // Will be emitted as an ordered map (overriden tag)
* auto omap = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:omap");
* // Will be emitted as pairs (overriden tag)
* auto pairs = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:pairs");
* --------------------
*/
this(K, V)(V[K] array, const string tag = null) @trusted
{
@ -391,6 +379,16 @@ struct Node
foreach(key, ref value; array){pairs ~= Pair(key, value);}
value_ = Value(pairs);
}
///
@safe unittest
{
// Will be emitted as an unordered mapping (default for mappings)
auto map = Node([1 : "a", 2 : "b"]);
// Will be emitted as an ordered map (overriden tag)
auto omap = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:omap");
// Will be emitted as pairs (overriden tag)
auto pairs = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:pairs");
}
@safe unittest
{
int[string] aa;
@ -403,12 +401,6 @@ struct Node
assert(opIndex("2").as!int == 2);
}
// Will be emitted as an unordered mapping (default for mappings)
auto map = Node([1 : "a", 2 : "b"]);
// Will be emitted as an ordered map (overriden tag)
auto omap = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:omap");
// Will be emitted as pairs (overriden tag)
auto pairs = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:pairs");
}
/** Construct a node from arrays of _keys and _values.
@ -437,15 +429,6 @@ struct Node
* in full form, e.g. "tag:yaml.org,2002:omap", not a
* shortcut, like "!!omap".
*
* Examples:
* --------------------
* // Will be emitted as an unordered mapping (default for mappings)
* auto map = Node([1, 2], ["a", "b"]);
* // Will be emitted as an ordered map (overriden tag)
* auto omap = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:omap");
* // Will be emitted as pairs (overriden tag)
* auto pairs = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:pairs");
* --------------------
*/
this(K, V)(K[] keys, V[] values, const string tag = null) @trusted
if(!(isSomeString!(K[]) || isSomeString!(V[])))
@ -463,6 +446,16 @@ struct Node
foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);}
value_ = Value(pairs);
}
///
@safe unittest
{
// Will be emitted as an unordered mapping (default for mappings)
auto map = Node([1, 2], ["a", "b"]);
// Will be emitted as an ordered map (overridden tag)
auto omap = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:omap");
// Will be emitted as pairs (overriden tag)
auto pairs = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:pairs");
}
@safe unittest
{
with(Node(["1", "2"], [1, 2]))
@ -472,12 +465,6 @@ struct Node
assert(opIndex("2").as!int == 2);
}
// Will be emitted as an unordered mapping (default for mappings)
auto map = Node([1, 2], ["a", "b"]);
// Will be emitted as an ordered map (overriden tag)
auto omap = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:omap");
// Will be emitted as pairs (overriden tag)
auto pairs = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:pairs");
}
/// Is this node valid (initialized)?
@ -580,17 +567,6 @@ struct Node
* by old versions of the program, which expect the node to be a scalar.
* )
*
* Examples:
*
* Automatic type conversion:
* --------------------
* auto node = Node(42);
*
* assert(node.as!int == 42);
* assert(node.as!string == "42");
* assert(node.as!double == 42.0);
* --------------------
*
* Returns: Value of the node as specified type.
*
* Throws: NodeException if unable to convert to specified type, or if
@ -669,6 +645,15 @@ struct Node
}
assert(false, "This code should never be reached");
}
/// Automatic type conversion
@safe unittest
{
auto node = Node(42);
assert(node.get!int == 42);
assert(node.get!string == "42");
assert(node.get!double == 42.0);
}
@safe unittest
{
assertThrown!NodeException(Node("42").get!int);
@ -968,7 +953,9 @@ struct Node
*
* To set element at a null index, use YAMLNull for index.
*
* Params: index = Index of the value to set.
* Params:
* value = Value to assign.
* index = Index of the value to set.
*
* Throws: NodeException if the node is not a collection, index is out
* of range or if a non-integral index is used on a sequence node.

View file

@ -363,17 +363,7 @@ auto decodeUTF8NoGC(Flag!"validated" validated)(const(char[]) str, ref size_t in
else { return invalidUTF; }
}
/// @nogc version of std.utf.decode() for char[], but assumes str is valid UTF-8.
///
/// The caller $(B must) handle ASCII (< 0x80) characters manually; this is asserted to
/// force code using this function to be efficient.
///
/// Params:
///
/// str = Will decode the first code point from this string. Must be valid UTF-8,
/// otherwise undefined behavior WILL occur.
/// index = Index in str where the code point starts. Will be updated to point to the
/// next code point.
/// ditto
alias decodeValidUTF8NoGC = decodeUTF8NoGC!(Yes.validated);
/// @nogc version of std.utf.encode() for char[].
@ -451,18 +441,7 @@ auto encodeCharNoGC(Flag!"validated" validated)(ref char[4] buf, dchar c)
}
}
/// @nogc version of std.utf.encode() for char[], but assumes c is a valid UTF-32 char.
///
/// The caller $(B must) handle ASCII (< 0x80) characters manually; this is asserted to
/// force code using this function to be efficient.
///
/// Params:
///
/// buf = Buffer to write the encoded result to.
/// c = Character to encode. Must be valid UTF-32, otherwise undefined behavior
/// $(D will) occur.
///
/// Returns: Number of bytes the encoded character takes up in buf.
/// ditto
alias encodeValidCharNoGC = encodeCharNoGC!(Yes.validated);
/// @nogc version of std.utf.isValidDchar

View file

@ -108,7 +108,8 @@ final class Representer
* throw a $(D RepresenterException). See the example for more information.
*
*
* Only one function may be specified for one data type. Default data
*
* Only one function may be specified for one data type. Default data
* types already have representer functions unless disabled in the
* $(D Representer) constructor.
*
@ -121,106 +122,6 @@ final class Representer
* values - it is not const for compatibility reasons.
*
* Params: representer = Representer function to add.
*
* Examples:
*
* Representing a simple struct:
* --------------------
* import std.string;
*
* import dyaml.all;
*
* struct MyStruct
* {
* int x, y, z;
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* const int opCmp(ref const MyStruct s)
* {
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
* }
*
* Node representMyStruct(ref Node node, Representer representer)
* {
* //The node is guaranteed to be MyStruct as we add representer for MyStruct.
* auto value = node.as!MyStruct;
* //Using custom scalar format, x:y:z.
* auto scalar = format("%s:%s:%s", value.x, value.y, value.z);
* //Representing as a scalar, with custom tag to specify this data type.
* return representer.representScalar("!mystruct.tag", scalar);
* }
*
* void main()
* {
* auto dumper = Dumper("file.yaml");
* auto representer = new Representer;
* representer.addRepresenter!MyStruct(&representMyStruct);
* dumper.representer = representer;
* dumper.dump(Node(MyStruct(1,2,3)));
* }
* --------------------
*
* Representing a class:
* --------------------
* import std.string;
*
* import dyaml.all;
*
* class MyClass
* {
* int x, y, z;
*
* this(int x, int y, int z)
* {
* this.x = x;
* this.y = y;
* this.z = z;
* }
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* override int opCmp(Object o)
* {
* MyClass s = cast(MyClass)o;
* if(s is null){return -1;}
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
*
* ///Useful for Node.as!string .
* override string toString()
* {
* return format("MyClass(%s, %s, %s)", x, y, z);
* }
* }
*
* //Same as representMyStruct.
* Node representMyClass(ref Node node, Representer representer)
* {
* //The node is guaranteed to be MyClass as we add representer for MyClass.
* auto value = node.as!MyClass;
* //Using custom scalar format, x:y:z.
* auto scalar = format("%s:%s:%s", value.x, value.y, value.z);
* //Representing as a scalar, with custom tag to specify this data type.
* return representer.representScalar("!myclass.tag", scalar);
* }
*
* void main()
* {
* auto dumper = Dumper("file.yaml");
* auto representer = new Representer;
* representer.addRepresenter!MyClass(&representMyClass);
* dumper.representer = representer;
* dumper.dump(Node(new MyClass(1,2,3)));
* }
* --------------------
*/
void addRepresenter(T)(Node function(ref Node, Representer) @safe representer)
@safe pure
@ -230,6 +131,96 @@ final class Representer
" already specified. Can't specify another one");
representers_[typeid(T)] = representer;
}
/// Representing a simple struct:
unittest {
import std.string;
import dyaml;
struct MyStruct
{
int x, y, z;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
const int opCmp(ref const MyStruct s)
{
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
}
static Node representMyStruct(ref Node node, Representer representer) @safe
{
//The node is guaranteed to be MyStruct as we add representer for MyStruct.
auto value = node.as!MyStruct;
//Using custom scalar format, x:y:z.
auto scalar = format("%s:%s:%s", value.x, value.y, value.z);
//Representing as a scalar, with custom tag to specify this data type.
return representer.representScalar("!mystruct.tag", scalar);
}
auto dumper = Dumper("example.yaml");
auto representer = new Representer;
representer.addRepresenter!MyStruct(&representMyStruct);
dumper.representer = representer;
dumper.dump(Node(MyStruct(1,2,3)));
}
/// Representing a class:
unittest {
import std.string;
import dyaml;
class MyClass
{
int x, y, z;
this(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
override int opCmp(Object o)
{
MyClass s = cast(MyClass)o;
if(s is null){return -1;}
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
///Useful for Node.as!string .
override string toString()
{
return format("MyClass(%s, %s, %s)", x, y, z);
}
}
//Same as representMyStruct.
static Node representMyClass(ref Node node, Representer representer) @safe
{
//The node is guaranteed to be MyClass as we add representer for MyClass.
auto value = node.as!MyClass;
//Using custom scalar format, x:y:z.
auto scalar = format("%s:%s:%s", value.x, value.y, value.z);
//Representing as a scalar, with custom tag to specify this data type.
return representer.representScalar("!myclass.tag", scalar);
}
auto dumper = Dumper("example.yaml");
auto representer = new Representer;
representer.addRepresenter!MyClass(&representMyClass);
dumper.representer = representer;
dumper.dump(Node(new MyClass(1,2,3)));
}
//If profiling shows a bottleneck on tag construction in these 3 methods,
//we'll need to take Tag directly and have string based wrappers for
@ -246,31 +237,6 @@ final class Representer
* If the node was loaded before, previous _style will always be used.
*
* Returns: The represented node.
*
* Example:
* --------------------
* struct MyStruct
* {
* int x, y, z;
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* const int opCmp(ref const MyStruct s)
* {
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
* }
*
* Node representMyStruct(ref Node node, Representer representer)
* {
* auto value = node.as!MyStruct;
* auto scalar = format("%s:%s:%s", value.x, value.y, value.z);
* return representer.representScalar("!mystruct.tag", scalar);
* }
* --------------------
*/
Node representScalar(string tag, string scalar,
ScalarStyle style = ScalarStyle.Invalid) @trusted
@ -279,6 +245,37 @@ final class Representer
return Node.rawNode(Node.Value(scalar), Mark(), tag, style,
CollectionStyle.Invalid);
}
///
@safe unittest
{
struct MyStruct
{
int x, y, z;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
const int opCmp(ref const MyStruct s)
{
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
}
static Node representMyStruct(ref Node node, Representer representer)
{
auto value = node.as!MyStruct;
auto scalar = format("%s:%s:%s", value.x, value.y, value.z);
return representer.representScalar("!mystruct.tag", scalar);
}
auto dumper = Dumper("example.yaml");
auto representer = new Representer;
representer.addRepresenter!MyStruct(&representMyStruct);
dumper.representer = representer;
dumper.dump(Node(MyStruct(1,2,3)));
}
/**
* Represent a _sequence with specified _tag, representing children first.
@ -293,33 +290,6 @@ final class Representer
* Returns: The represented node.
*
* Throws: $(D RepresenterException) if a child could not be represented.
*
* Example:
* --------------------
* struct MyStruct
* {
* int x, y, z;
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* const int opCmp(ref const MyStruct s)
* {
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
* }
*
* Node representMyStruct(ref Node node, Representer representer)
* {
* auto value = node.as!MyStruct;
* auto nodes = [Node(value.x), Node(value.y), Node(value.z)];
* //use flow style
* return representer.representSequence("!mystruct.tag", nodes,
* CollectionStyle.Flow);
* }
* --------------------
*/
Node representSequence(string tag, Node[] sequence,
CollectionStyle style = CollectionStyle.Invalid) @trusted
@ -341,14 +311,46 @@ final class Representer
if(style == CollectionStyle.Invalid)
{
style = defaultCollectionStyle_ != CollectionStyle.Invalid
style = defaultCollectionStyle_ != CollectionStyle.Invalid
? defaultCollectionStyle_
: bestStyle;
}
return Node.rawNode(Node.Value(value), Mark(), tag,
ScalarStyle.Invalid, style);
}
///
@safe unittest
{
struct MyStruct
{
int x, y, z;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
const int opCmp(ref const MyStruct s)
{
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
}
static Node representMyStruct(ref Node node, Representer representer)
{
auto value = node.as!MyStruct;
auto nodes = [Node(value.x), Node(value.y), Node(value.z)];
//use flow style
return representer.representSequence("!mystruct.tag", nodes,
CollectionStyle.Flow);
}
auto dumper = Dumper("example.yaml");
auto representer = new Representer;
representer.addRepresenter!MyStruct(&representMyStruct);
dumper.representer = representer;
dumper.dump(Node(MyStruct(1,2,3)));
}
/**
* Represent a mapping with specified _tag, representing children first.
*
@ -362,33 +364,6 @@ final class Representer
* Returns: The represented node.
*
* Throws: $(D RepresenterException) if a child could not be represented.
*
* Example:
* --------------------
* struct MyStruct
* {
* int x, y, z;
*
* //Any D:YAML type must have a custom opCmp operator.
* //This is used for ordering in mappings.
* const int opCmp(ref const MyStruct s)
* {
* if(x != s.x){return x - s.x;}
* if(y != s.y){return y - s.y;}
* if(z != s.z){return z - s.z;}
* return 0;
* }
* }
*
* Node representMyStruct(ref Node node, Representer representer)
* {
* auto value = node.as!MyStruct;
* auto pairs = [Node.Pair("x", value.x),
* Node.Pair("y", value.y),
* Node.Pair("z", value.z)];
* return representer.representMapping("!mystruct.tag", pairs);
* }
* --------------------
*/
Node representMapping(string tag, Node.Pair[] pairs,
CollectionStyle style = CollectionStyle.Invalid) @trusted
@ -425,6 +400,39 @@ final class Representer
return Node.rawNode(Node.Value(value), Mark(), tag,
ScalarStyle.Invalid, style);
}
///
@safe unittest
{
struct MyStruct
{
int x, y, z;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
const int opCmp(ref const MyStruct s)
{
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
}
}
static Node representMyStruct(ref Node node, Representer representer)
{
auto value = node.as!MyStruct;
auto pairs = [Node.Pair("x", value.x),
Node.Pair("y", value.y),
Node.Pair("z", value.z)];
return representer.representMapping("!mystruct.tag", pairs);
}
auto dumper = Dumper("example.yaml");
auto representer = new Representer;
representer.addRepresenter!MyStruct(&representMyStruct);
dumper.representer = representer;
dumper.dump(Node(MyStruct(1,2,3)));
}
package:
//Represent a node based on its type, and return the represented result.

View file

@ -92,28 +92,6 @@ final class Resolver
* regexp = Regular expression the scalar must match to have this _tag.
* first = String of possible starting characters of the scalar.
*
* Examples:
*
* Resolve scalars starting with 'A' to !_tag :
* --------------------
* import std.regex;
*
* import dyaml.all;
*
* void main()
* {
* auto loader = Loader("file.txt");
* auto resolver = new Resolver();
* resolver.addImplicitResolver("!tag", std.regex.regex("A.*"), "A");
* loader.resolver = resolver;
*
* //Note that we have no constructor from tag "!tag", so we can't
* //actually load anything that resolves to this tag.
* //See Constructor API documentation and tutorial for more information.
*
* auto node = loader.load();
* }
* --------------------
*/
void addImplicitResolver(string tag, Regex!char regexp, string first)
pure @safe
@ -127,6 +105,24 @@ final class Resolver
yamlImplicitResolvers_[c] ~= tuple(tag, regexp);
}
}
/// Resolve scalars starting with 'A' to !_tag
unittest {
import std.regex;
import dyaml;
auto loader = Loader("example.yaml");
auto resolver = new Resolver();
resolver.addImplicitResolver("!tag", regex("A.*"), "A");
loader.resolver = resolver;
//Note that we have no constructor from tag "!tag", so we can't
//actually load anything that resolves to this tag.
//See Constructor API documentation and tutorial for more information.
//auto node = loader.load();
}
package:
/*

View file

@ -103,6 +103,7 @@ static assert(Token.sizeof <= 32, "Token has unexpected size");
/// end = End position of the token.
/// value = Value of the token.
/// directive = Directive type (YAML or TAG in YAML 1.1).
/// nameEnd = Position of the end of the name
Token directiveToken(const Mark start, const Mark end, char[] value,
DirectiveType directive, const uint nameEnd) @safe pure nothrow @nogc
{