Merge pull request #102 from Herringway/unittest-examples
Convert tests to doc'd examples and some minor doc param fixes
This commit is contained in:
commit
c682d1940b
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -56,3 +56,6 @@ Thumbs.db
|
||||||
perf.data
|
perf.data
|
||||||
perf.data.old
|
perf.data.old
|
||||||
callgrind.out.*
|
callgrind.out.*
|
||||||
|
|
||||||
|
# Test outputs #
|
||||||
|
example.yaml
|
||||||
|
|
|
@ -137,47 +137,6 @@ 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.
|
||||||
*
|
|
||||||
* 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)
|
void addConstructorScalar(T)(const string tag, T function(ref Node) ctor)
|
||||||
{
|
{
|
||||||
|
@ -185,49 +144,44 @@ final class Constructor
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
(*delegates!string)[t] = deleg;
|
(*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.
|
/** Add a constructor function from sequence.
|
||||||
*
|
*
|
||||||
* See_Also: addConstructorScalar
|
* 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)
|
void addConstructorSequence(T)(const string tag, T function(ref Node) ctor)
|
||||||
{
|
{
|
||||||
|
@ -235,49 +189,40 @@ final class Constructor
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
(*delegates!(Node[]))[t] = deleg;
|
(*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.
|
/** Add a constructor function from a mapping.
|
||||||
*
|
*
|
||||||
* See_Also: addConstructorScalar
|
* 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)
|
void addConstructorMapping(T)(const string tag, T function(ref Node) ctor)
|
||||||
{
|
{
|
||||||
|
@ -285,6 +230,36 @@ final class Constructor
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
(*delegates!(Node.Pair[]))[t] = deleg;
|
(*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:
|
package:
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -31,52 +31,10 @@ import dyaml.tagdirective;
|
||||||
/**
|
/**
|
||||||
* Dumps YAML documents to files or streams.
|
* 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.
|
* tags / data types.
|
||||||
*
|
*
|
||||||
* Setters are provided to affect output details (style, encoding, etc.).
|
* 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
|
struct Dumper
|
||||||
{
|
{
|
||||||
|
@ -271,21 +229,10 @@ struct Dumper
|
||||||
*
|
*
|
||||||
* Each prefix MUST not be empty.
|
* 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.
|
* "tag:yaml.org,2002:". This can be overridden.
|
||||||
*
|
*
|
||||||
* Params: tags = Tag directives (keys are handles, values are prefixes).
|
* 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
|
@property void tagDirectives(string[string] tags) pure @safe
|
||||||
{
|
{
|
||||||
|
@ -300,6 +247,17 @@ struct Dumper
|
||||||
}
|
}
|
||||||
tags_ = t;
|
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.
|
* 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);
|
||||||
|
}
|
||||||
|
|
|
@ -123,6 +123,7 @@ Event event(EventID id)(const Mark start, const Mark end, const string anchor =
|
||||||
* anchor = Anchor of the sequence, if any.
|
* anchor = Anchor of the sequence, if any.
|
||||||
* tag = Tag of the sequence, if specified.
|
* tag = Tag of the sequence, if specified.
|
||||||
* implicit = Should the tag be implicitly resolved?
|
* implicit = Should the tag be implicitly resolved?
|
||||||
|
* style = Style to use when outputting document.
|
||||||
*/
|
*/
|
||||||
Event collectionStartEvent(EventID id)
|
Event collectionStartEvent(EventID id)
|
||||||
(const Mark start, const Mark end, const string anchor, const string tag,
|
(const Mark start, const Mark end, const string anchor, const string tag,
|
||||||
|
|
|
@ -17,20 +17,6 @@ package:
|
||||||
* Struct holding multiple named boolean values in a single byte.
|
* Struct holding multiple named boolean values in a single byte.
|
||||||
*
|
*
|
||||||
* Can hold at most 8 values.
|
* 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)
|
struct Flags(names ...) if(names.length <= 8)
|
||||||
{
|
{
|
||||||
|
@ -72,6 +58,7 @@ struct Flags(names ...) if(names.length <= 8)
|
||||||
///Flag accessors.
|
///Flag accessors.
|
||||||
mixin(flags(names));
|
mixin(flags(names));
|
||||||
}
|
}
|
||||||
|
///
|
||||||
@safe unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
|
|
@ -23,22 +23,22 @@ import dyaml.style;
|
||||||
* However, determining style may be useful in some cases, e.g. YAML utilities.
|
* 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).
|
* 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
|
ScalarStyle scalarStyleHack(ref const(Node) node) @safe nothrow
|
||||||
{
|
{
|
||||||
assert(node.isScalar, "Trying to get scalar style of a non-scalar node");
|
assert(node.isScalar, "Trying to get scalar style of a non-scalar node");
|
||||||
return node.scalarStyle;
|
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
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML scalarStyleHack getter unittest");
|
writeln("D:YAML scalarStyleHack getter unittest");
|
||||||
|
|
|
@ -28,74 +28,6 @@ import dyaml.token;
|
||||||
*
|
*
|
||||||
* User specified Constructor and/or Resolver can be used to support new
|
* User specified Constructor and/or Resolver can be used to support new
|
||||||
* tags / data types.
|
* 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
|
struct Loader
|
||||||
{
|
{
|
||||||
|
@ -375,7 +307,48 @@ struct Loader
|
||||||
if(constructor_ is null) { constructor_ = new Constructor(); }
|
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
|
@safe unittest
|
||||||
{
|
{
|
||||||
char[] yaml_input = ("red: '#ff0000'\n" ~
|
char[] yaml_input = ("red: '#ff0000'\n" ~
|
||||||
|
@ -390,3 +363,50 @@ struct Loader
|
||||||
writeln(color, " is ", value, " in HTML/CSS");
|
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();
|
||||||
|
}
|
||||||
|
|
|
@ -311,13 +311,6 @@ struct Node
|
||||||
* must be in full form, e.g. "tag:yaml.org,2002:set",
|
* must be in full form, e.g. "tag:yaml.org,2002:set",
|
||||||
* not a shortcut, like "!!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
|
this(T)(T[] array, const string tag = null) @trusted
|
||||||
if (!isSomeString!(T[]))
|
if (!isSomeString!(T[]))
|
||||||
|
@ -341,6 +334,14 @@ struct Node
|
||||||
value_ = Value(nodes);
|
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
|
@safe unittest
|
||||||
{
|
{
|
||||||
with(Node([1, 2, 3]))
|
with(Node([1, 2, 3]))
|
||||||
|
@ -350,10 +351,6 @@ struct Node
|
||||||
assert(opIndex(2).as!int == 3);
|
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.
|
/** 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
|
* in full form, e.g. "tag:yaml.org,2002:omap", not a
|
||||||
* shortcut, like "!!omap".
|
* 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
|
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);}
|
foreach(key, ref value; array){pairs ~= Pair(key, value);}
|
||||||
value_ = Value(pairs);
|
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
|
@safe unittest
|
||||||
{
|
{
|
||||||
int[string] aa;
|
int[string] aa;
|
||||||
|
@ -403,12 +401,6 @@ struct Node
|
||||||
assert(opIndex("2").as!int == 2);
|
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.
|
/** 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
|
* in full form, e.g. "tag:yaml.org,2002:omap", not a
|
||||||
* shortcut, like "!!omap".
|
* 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
|
this(K, V)(K[] keys, V[] values, const string tag = null) @trusted
|
||||||
if(!(isSomeString!(K[]) || isSomeString!(V[])))
|
if(!(isSomeString!(K[]) || isSomeString!(V[])))
|
||||||
|
@ -463,6 +446,16 @@ struct Node
|
||||||
foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);}
|
foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);}
|
||||||
value_ = Value(pairs);
|
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
|
@safe unittest
|
||||||
{
|
{
|
||||||
with(Node(["1", "2"], [1, 2]))
|
with(Node(["1", "2"], [1, 2]))
|
||||||
|
@ -472,12 +465,6 @@ struct Node
|
||||||
assert(opIndex("2").as!int == 2);
|
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)?
|
/// 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.
|
* 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.
|
* Returns: Value of the node as specified type.
|
||||||
*
|
*
|
||||||
* Throws: NodeException if unable to convert to specified type, or if
|
* 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");
|
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
|
@safe unittest
|
||||||
{
|
{
|
||||||
assertThrown!NodeException(Node("42").get!int);
|
assertThrown!NodeException(Node("42").get!int);
|
||||||
|
@ -968,7 +953,9 @@ struct Node
|
||||||
*
|
*
|
||||||
* To set element at a null index, use YAMLNull for index.
|
* 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
|
* 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.
|
* of range or if a non-integral index is used on a sequence node.
|
||||||
|
|
|
@ -363,17 +363,7 @@ auto decodeUTF8NoGC(Flag!"validated" validated)(const(char[]) str, ref size_t in
|
||||||
else { return invalidUTF; }
|
else { return invalidUTF; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nogc version of std.utf.decode() for char[], but assumes str is valid UTF-8.
|
/// ditto
|
||||||
///
|
|
||||||
/// 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.
|
|
||||||
alias decodeValidUTF8NoGC = decodeUTF8NoGC!(Yes.validated);
|
alias decodeValidUTF8NoGC = decodeUTF8NoGC!(Yes.validated);
|
||||||
|
|
||||||
/// @nogc version of std.utf.encode() for char[].
|
/// @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.
|
/// ditto
|
||||||
///
|
|
||||||
/// 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.
|
|
||||||
alias encodeValidCharNoGC = encodeCharNoGC!(Yes.validated);
|
alias encodeValidCharNoGC = encodeCharNoGC!(Yes.validated);
|
||||||
|
|
||||||
/// @nogc version of std.utf.isValidDchar
|
/// @nogc version of std.utf.isValidDchar
|
||||||
|
|
|
@ -108,7 +108,8 @@ final class Representer
|
||||||
* throw a $(D RepresenterException). See the example for more information.
|
* 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
|
* types already have representer functions unless disabled in the
|
||||||
* $(D Representer) constructor.
|
* $(D Representer) constructor.
|
||||||
*
|
*
|
||||||
|
@ -121,106 +122,6 @@ final class Representer
|
||||||
* values - it is not const for compatibility reasons.
|
* values - it is not const for compatibility reasons.
|
||||||
*
|
*
|
||||||
* Params: representer = Representer function to add.
|
* 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)
|
void addRepresenter(T)(Node function(ref Node, Representer) @safe representer)
|
||||||
@safe pure
|
@safe pure
|
||||||
|
@ -230,6 +131,96 @@ final class Representer
|
||||||
" already specified. Can't specify another one");
|
" already specified. Can't specify another one");
|
||||||
representers_[typeid(T)] = representer;
|
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,
|
//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
|
//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.
|
* If the node was loaded before, previous _style will always be used.
|
||||||
*
|
*
|
||||||
* Returns: The represented node.
|
* 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,
|
Node representScalar(string tag, string scalar,
|
||||||
ScalarStyle style = ScalarStyle.Invalid) @trusted
|
ScalarStyle style = ScalarStyle.Invalid) @trusted
|
||||||
|
@ -279,6 +245,37 @@ final class Representer
|
||||||
return Node.rawNode(Node.Value(scalar), Mark(), tag, style,
|
return Node.rawNode(Node.Value(scalar), Mark(), tag, style,
|
||||||
CollectionStyle.Invalid);
|
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.
|
* Represent a _sequence with specified _tag, representing children first.
|
||||||
|
@ -293,33 +290,6 @@ final class Representer
|
||||||
* Returns: The represented node.
|
* Returns: The represented node.
|
||||||
*
|
*
|
||||||
* Throws: $(D RepresenterException) if a child could not be represented.
|
* 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,
|
Node representSequence(string tag, Node[] sequence,
|
||||||
CollectionStyle style = CollectionStyle.Invalid) @trusted
|
CollectionStyle style = CollectionStyle.Invalid) @trusted
|
||||||
|
@ -341,14 +311,46 @@ final class Representer
|
||||||
|
|
||||||
if(style == CollectionStyle.Invalid)
|
if(style == CollectionStyle.Invalid)
|
||||||
{
|
{
|
||||||
style = defaultCollectionStyle_ != CollectionStyle.Invalid
|
style = defaultCollectionStyle_ != CollectionStyle.Invalid
|
||||||
? defaultCollectionStyle_
|
? defaultCollectionStyle_
|
||||||
: bestStyle;
|
: bestStyle;
|
||||||
}
|
}
|
||||||
return Node.rawNode(Node.Value(value), Mark(), tag,
|
return Node.rawNode(Node.Value(value), Mark(), tag,
|
||||||
ScalarStyle.Invalid, style);
|
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.
|
* Represent a mapping with specified _tag, representing children first.
|
||||||
*
|
*
|
||||||
|
@ -362,33 +364,6 @@ final class Representer
|
||||||
* Returns: The represented node.
|
* Returns: The represented node.
|
||||||
*
|
*
|
||||||
* Throws: $(D RepresenterException) if a child could not be represented.
|
* 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,
|
Node representMapping(string tag, Node.Pair[] pairs,
|
||||||
CollectionStyle style = CollectionStyle.Invalid) @trusted
|
CollectionStyle style = CollectionStyle.Invalid) @trusted
|
||||||
|
@ -425,6 +400,39 @@ final class Representer
|
||||||
return Node.rawNode(Node.Value(value), Mark(), tag,
|
return Node.rawNode(Node.Value(value), Mark(), tag,
|
||||||
ScalarStyle.Invalid, style);
|
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:
|
package:
|
||||||
//Represent a node based on its type, and return the represented result.
|
//Represent a node based on its type, and return the represented result.
|
||||||
|
|
|
@ -92,28 +92,6 @@ final class Resolver
|
||||||
* regexp = Regular expression the scalar must match to have this _tag.
|
* regexp = Regular expression the scalar must match to have this _tag.
|
||||||
* first = String of possible starting characters of the scalar.
|
* 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)
|
void addImplicitResolver(string tag, Regex!char regexp, string first)
|
||||||
pure @safe
|
pure @safe
|
||||||
|
@ -127,6 +105,26 @@ final class Resolver
|
||||||
yamlImplicitResolvers_[c] ~= tuple(tag, regexp);
|
yamlImplicitResolvers_[c] ~= tuple(tag, regexp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Resolve scalars starting with 'A' to !_tag
|
||||||
|
unittest {
|
||||||
|
import std.file : write;
|
||||||
|
import std.regex;
|
||||||
|
|
||||||
|
import dyaml;
|
||||||
|
|
||||||
|
write("example.yaml", "A");
|
||||||
|
|
||||||
|
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:
|
package:
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -103,6 +103,7 @@ static assert(Token.sizeof <= 32, "Token has unexpected size");
|
||||||
/// end = End position of the token.
|
/// end = End position of the token.
|
||||||
/// value = Value of the token.
|
/// value = Value of the token.
|
||||||
/// directive = Directive type (YAML or TAG in YAML 1.1).
|
/// 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,
|
Token directiveToken(const Mark start, const Mark end, char[] value,
|
||||||
DirectiveType directive, const uint nameEnd) @safe pure nothrow @nogc
|
DirectiveType directive, const uint nameEnd) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue