Nodes now remember their scalar and collection style, although

these are not accessible by the user (as the spec says).
This allows D:YAML to remember styles between loading and
dumping.
This commit is contained in:
Ferdinand Majerech 2011-10-27 23:13:14 +02:00
parent c787531497
commit 5d35f44416
23 changed files with 218 additions and 68 deletions

View file

@ -29,7 +29,7 @@ links = ../index.html Documentation home
# Source files or patterns to ignore. Supports regexp syntax.
# E.g; To ignore main.d and all source files in the test/ directory,
# you would use: "main.d test/*"
ignore = test/*, examples/*, docsrc/*, autoddoc/*, yaml.d, unittest.d, cdc.d, dyaml/composer.d, dyaml/event.d, dyaml/parser.d, dyaml/reader.d, dyaml/scanner.d, dyaml/token.d, dyaml/util.d, dyaml/anchor.d, dyaml/emitter.d, dyaml/flags.d, dyaml/serializer.d, dyaml/sharedobject.d, dyaml/tag.d, dyaml/tagdirectives.d, dyaml/queue.d, dyaml/escapes.d, dyaml/fastcharsearch.d
ignore = test/*, examples/*, docsrc/*, autoddoc/*, yaml.d, unittest.d, cdc.d, dyaml/composer.d, dyaml/event.d, dyaml/parser.d, dyaml/reader.d, dyaml/scanner.d, dyaml/token.d, dyaml/util.d, dyaml/anchor.d, dyaml/emitter.d, dyaml/flags.d, dyaml/serializer.d, dyaml/sharedobject.d, dyaml/tag.d, dyaml/tagdirectives.d, dyaml/queue.d, dyaml/escapes.d, dyaml/fastcharsearch.d, dyaml/style.d
[DDOC]
# Command to use to generate the documentation.

Binary file not shown.

View file

@ -112,7 +112,7 @@
<dd><p>Construct a Loader to load YAML from a stream.
</p>
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>Stream <b>stream</b></td>
<td valign=top>Stream to read from. Must be readable.</td></tr>
<td valign=top>Stream to read from. Must be readable and seekable.</td></tr>
</table></div>
<b>Throws:</b><div class="pbr">YAMLException if <b>stream</b> could not be read.</div>

View file

@ -85,6 +85,16 @@
</dd>
</dl>
</dd>
<dt class="d_decl">package ScalarStyle <a name="scalarStyle"></a><span class="ddoc_psymbol">scalarStyle</span>;
</dt>
<dd><p>Node scalar style. Used to remember style this node was loaded with.</p>
</dd>
<dt class="d_decl">package CollectionStyle <a name="collectionStyle"></a><span class="ddoc_psymbol">collectionStyle</span>;
</dt>
<dd><p>Node collection style. Used to remember style this node was loaded with.</p>
</dd>
<dt class="d_decl">auto this(T)(T <b>value</b>, in string <b>tag</b> = null);
</dt>

View file

@ -51,7 +51,12 @@
</dd>
<dt class="d_decl">class <a name="Representer"></a><span class="ddoc_psymbol">Representer</span>;
</dt>
<dd><p>Used to represent YAML nodes various data types into scalar, sequence and mapping nodes ready for output.</p>
<dd><p>Represents YAML nodes of various data types as scalar, sequence and mapping nodes ready for output.
</p>
<p>This class is used to add support for dumping of custom data types.
<br>
It can also override default node formatting styles for output.</p>
<dl><dt class="d_decl">this(bool <b>useDefaultRepresenters</b> = true);
</dt>
@ -64,6 +69,16 @@
functions for default types.</td></tr>
</table></div>
</dd>
<dt class="d_decl">@property void <a name="defaultScalarStyle"></a><span class="ddoc_psymbol">defaultScalarStyle</span>(ScalarStyle <b>style</b>);
</dt>
<dd><p>Set default <b>style</b> for scalars. Invalid means the <b>style</b> is chosen automatically.</p>
</dd>
<dt class="d_decl">@property void <a name="defaultCollectionStyle"></a><span class="ddoc_psymbol">defaultCollectionStyle</span>(CollectionStyle <b>style</b>);
</dt>
<dd><p>Set default <b>style</b> for collections. Invalid means the <b>style</b> is chosen automatically. </p>
</dd>
<dt class="d_decl">void <a name="addRepresenter"></a><span class="ddoc_psymbol">addRepresenter</span>(T)(Node function(ref Node, Representer) <b>representer</b>);
</dt>
@ -166,7 +181,7 @@
</div>
</dd>
<dt class="d_decl">Node <a name="representScalar"></a><span class="ddoc_psymbol">representScalar</span>(in string <b>tag</b>, string <b>scalar</b>);
<dt class="d_decl">Node <a name="representScalar"></a><span class="ddoc_psymbol">representScalar</span>(in string <b>tag</b>, string <b>scalar</b>, ScalarStyle <b>style</b> = (ScalarStyle).Invalid);
</dt>
<dd><p>Represent a scalar with specified tag.
</p>
@ -177,6 +192,8 @@
<td valign=top>Tag of the scalar.</td></tr>
<tr><td valign=top>string <b>scalar</b></td>
<td valign=top>Scalar value.</td></tr>
<tr><td valign=top>ScalarStyle <b>style</b></td>
<td valign=top>Style of the <b>scalar</b> (will be default if invalid).</td></tr>
</table></div>
<b>Returns:</b><div class="pbr">The represented node.
@ -197,7 +214,7 @@
</p>
</dd>
<dt class="d_decl">Node <a name="representSequence"></a><span class="ddoc_psymbol">representSequence</span>(in string <b>tag</b>, Node[] <b>sequence</b>);
<dt class="d_decl">Node <a name="representSequence"></a><span class="ddoc_psymbol">representSequence</span>(in string <b>tag</b>, Node[] <b>sequence</b>, CollectionStyle <b>style</b> = (CollectionStyle).Invalid);
</dt>
<dd><p>Represent a sequence with specified tag, representing children first.
</p>
@ -208,6 +225,8 @@
<td valign=top>Tag of the <b>sequence</b>.</td></tr>
<tr><td valign=top>Node[] <b>sequence</b></td>
<td valign=top>Sequence of nodes.</td></tr>
<tr><td valign=top>CollectionStyle <b>style</b></td>
<td valign=top>Style of the <b>sequence</b> (will be default if invalid).</td></tr>
</table></div>
<b>Returns:</b><div class="pbr">The represented node.
@ -231,7 +250,7 @@
</p>
</dd>
<dt class="d_decl">Node <a name="representMapping"></a><span class="ddoc_psymbol">representMapping</span>(in string <b>tag</b>, Pair[] <b>pairs</b>);
<dt class="d_decl">Node <a name="representMapping"></a><span class="ddoc_psymbol">representMapping</span>(in string <b>tag</b>, Pair[] <b>pairs</b>, CollectionStyle <b>style</b> = (CollectionStyle).Invalid);
</dt>
<dd><p>Represent a mapping with specified tag, representing children first.
</p>
@ -242,6 +261,8 @@
<td valign=top>Tag of the mapping.</td></tr>
<tr><td valign=top>Pair[] <b>pairs</b></td>
<td valign=top>Key-value pairs of the mapping.</td></tr>
<tr><td valign=top>CollectionStyle <b>style</b></td>
<td valign=top>Style of the mapping (will be default if invalid).</td></tr>
</table></div>
<b>Returns:</b><div class="pbr">The represented node.

View file

@ -138,7 +138,7 @@ struct appears in Phobos.</p>
</div>
<div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 22, 2011.
Last updated on Oct 27, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div>
</body>

View file

@ -104,7 +104,7 @@
</div>
<div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 22, 2011.
Last updated on Oct 27, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div>
</body>

View file

@ -87,7 +87,7 @@
</div>
<div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 22, 2011.
Last updated on Oct 27, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div>
</body>

View file

@ -369,7 +369,7 @@ directory of the D:YAML package.</p>
</div>
<div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 22, 2011.
Last updated on Oct 27, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div>
</body>

View file

@ -237,7 +237,7 @@ example in the <tt class="docutils literal"><span class="pre">example/getting_st
</div>
<div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 22, 2011.
Last updated on Oct 27, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div>
</body>

View file

@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).</p>
</div>
<div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 22, 2011.
Last updated on Oct 27, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div>
</body>

View file

@ -207,7 +207,7 @@ final class Composer
event.implicit);
Node node = constructor_.node(event.startMark, event.endMark, tag,
event.value);
event.value, event.scalarStyle);
return node;
}
@ -226,7 +226,7 @@ final class Composer
}
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
tag, children);
tag, children, startEvent.collectionStyle);
return node;
}
@ -315,7 +315,7 @@ final class Composer
}
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
tag, children);
tag, children, startEvent.collectionStyle);
return node;
}

View file

@ -26,7 +26,7 @@ import std.utf;
import dyaml.node;
import dyaml.exception;
import dyaml.tag;
import dyaml.token;
import dyaml.style;
/**
@ -284,16 +284,28 @@ final class Constructor
* end = End position of the node.
* tag = Tag (data type) of the node.
* value = Value to construct node from (string, nodes or pairs).
* style = Style of the node (scalar or collection style).
*
* Returns: Constructed node.
*/
Node node(T)(in Mark start, in Mark end, in Tag tag, T value)
if(is(T : string) || is(T == Node[]) || is(T == Node.Pair[]))
Node node(T, U)(in Mark start, in Mark end, in Tag tag, T value, U style)
if((is(T : string) || is(T == Node[]) || is(T == Node.Pair[])) &&
(is(U : CollectionStyle) || is(U : ScalarStyle)))
{
enforce((tag in *delegates!T) !is null,
new Error("No constructor function for tag " ~ tag.get(), start, end));
Node node = Node(value);
return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag);
static if(is(U : ScalarStyle))
{
return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag,
style, CollectionStyle.Invalid);
}
else static if(is(U : CollectionStyle))
{
return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag,
ScalarStyle.Invalid, style);
}
else static assert(false);
}
private:

View file

@ -34,8 +34,8 @@ import dyaml.fastcharsearch;
import dyaml.flags;
import dyaml.linebreak;
import dyaml.queue;
import dyaml.style;
import dyaml.tag;
import dyaml.token;
package:

View file

@ -20,7 +20,7 @@ import dyaml.exception;
import dyaml.reader;
import dyaml.tag;
import dyaml.tagdirectives;
import dyaml.token;
import dyaml.style;
package:
@ -79,10 +79,7 @@ struct Event
CollectionStyle collectionStyle;
///Is this a null (uninitialized) event?
@property bool isNull() const
{
return id == EventID.Invalid;
}
@property bool isNull() const {return id == EventID.Invalid;}
///Get string representation of the token ID.
@property string idString() const {return to!string(id);}

View file

@ -24,6 +24,7 @@ import std.variant;
import dyaml.event;
import dyaml.exception;
import dyaml.style;
import dyaml.tag;
@ -170,8 +171,12 @@ struct Node
Mark startMark_;
package:
//Tag of the node. Is package as it is both written to and read all over D:YAML.
//Tag of the node.
Tag tag_;
///Node scalar style. Used to remember style this node was loaded with.
ScalarStyle scalarStyle = ScalarStyle.Invalid;
///Node collection style. Used to remember style this node was loaded with.
CollectionStyle collectionStyle = CollectionStyle.Invalid;
public:
/**
@ -1102,22 +1107,34 @@ struct Node
/*
* Construct a node from raw data.
*
* Params: value = Value of the node.
* startMark = Start position of the node in file.
* tag = Tag of the node.
* Params: value = Value of the node.
* startMark = Start position of the node in file.
* tag = Tag of the node.
* scalarStyle = Scalar style of the node.
* collectionStyle = Collection style of the node.
*
* Returns: Constructed node.
*/
static Node rawNode(Value value, in Mark startMark = Mark(), in Tag tag = Tag("DUMMY_TAG"))
static Node rawNode(Value value, in Mark startMark, in Tag tag,
in ScalarStyle scalarStyle,
in CollectionStyle collectionStyle)
{
Node node;
node.value_ = value;
node.startMark_ = startMark;
node.tag_ = tag;
node.scalarStyle = scalarStyle;
node.collectionStyle = collectionStyle;
return node;
}
//Construct Node.Value from user defined type.
static Value userValue(T)(T value)
{
return Value(cast(YAMLObject)new YAMLContainer!T(value));
}
/*
* Equality test with any value.
*
@ -1236,12 +1253,6 @@ struct Node
assert(false);
}
//Construct Node.Value from user defined type.
static Value userValue(T)(T value)
{
return Value(cast(YAMLObject)new YAMLContainer!T(value));
}
//Get type of the node value (YAMLObject for user types).
@property TypeInfo type() const {return value_.type;}

View file

@ -21,6 +21,7 @@ import dyaml.anchor;
import dyaml.event;
import dyaml.exception;
import dyaml.scanner;
import dyaml.style;
import dyaml.token;
import dyaml.tag;
import dyaml.tagdirectives;

View file

@ -26,6 +26,7 @@ import std.stream;
import dyaml.exception;
import dyaml.node;
import dyaml.serializer;
import dyaml.style;
import dyaml.tag;
@ -35,11 +36,22 @@ class RepresenterException : YAMLException
mixin ExceptionCtors;
}
///Used to represent YAML nodes various data types into scalar, sequence and mapping nodes ready for output.
/**
* Represents YAML nodes of various data types as scalar, sequence and mapping nodes ready for output.
*
* This class is used to add support for dumping of custom data types.
*
* It can also override default node formatting styles for output.
*/
final class Representer
{
private:
///Representer functions indexed by types.
Node function(ref Node, Representer)[TypeInfo] representers_;
///Default style for scalar nodes.
ScalarStyle defaultScalarStyle_ = ScalarStyle.Invalid;
///Default style for collection nodes.
CollectionStyle defaultCollectionStyle_ = CollectionStyle.Invalid;
public:
/**
@ -70,6 +82,18 @@ final class Representer
representers_ = null;
}
///Set default style for scalars. Invalid means the style is chosen automatically.
@property void defaultScalarStyle(ScalarStyle style)
{
defaultScalarStyle_ = style;
}
///Set default style for collections. Invalid means the style is chosen automatically.
@property void defaultCollectionStyle(CollectionStyle style)
{
defaultCollectionStyle_ = style;
}
/**
* Add a function to represent nodes with a specific data type.
*
@ -188,6 +212,7 @@ final class Representer
*
* Params: tag = Tag of the _scalar.
* scalar = Scalar value.
* style = Style of the scalar (will be default if invalid).
*
* Returns: The represented node.
*
@ -206,9 +231,12 @@ final class Representer
* }
* --------------------
*/
Node representScalar(in string tag, string scalar)
Node representScalar(in string tag, string scalar,
ScalarStyle style = ScalarStyle.Invalid)
{
return Node.rawNode(Node.Value(scalar), Mark(), Tag(tag));
if(style == ScalarStyle.Invalid){style = defaultScalarStyle_;}
return Node.rawNode(Node.Value(scalar), Mark(), Tag(tag), style,
CollectionStyle.Invalid);
}
/**
@ -218,6 +246,7 @@ final class Representer
*
* Params: tag = Tag of the sequence.
* sequence = Sequence of nodes.
* style = Style of the sequence (will be default if invalid).
*
* Returns: The represented node.
*
@ -238,15 +267,32 @@ final class Representer
* }
* --------------------
*/
Node representSequence(in string tag, Node[] sequence)
Node representSequence(in string tag, Node[] sequence,
CollectionStyle style = CollectionStyle.Invalid)
{
Node[] value;
value.length = sequence.length;
auto bestStyle = CollectionStyle.Flow;
foreach(idx, ref item; sequence)
{
value[idx] = representData(item);
const isScalar = value[idx].isScalar;
const s = value[idx].scalarStyle;
if(!isScalar || (s != ScalarStyle.Invalid && s != ScalarStyle.Plain))
{
bestStyle = CollectionStyle.Block;
}
}
return Node.rawNode(Node.Value(value), Mark(), Tag(tag));
if(style == CollectionStyle.Invalid)
{
style = defaultCollectionStyle_ != CollectionStyle.Invalid
? defaultCollectionStyle_
: bestStyle;
}
return Node.rawNode(Node.Value(value), Mark(), Tag(tag),
ScalarStyle.Invalid, style);
}
/**
@ -256,6 +302,7 @@ final class Representer
*
* Params: tag = Tag of the mapping.
* pairs = Key-value _pairs of the mapping.
* style = Style of the mapping (will be default if invalid).
*
* Returns: The represented node.
*
@ -278,15 +325,40 @@ final class Representer
* }
* --------------------
*/
Node representMapping(in string tag, Node.Pair[] pairs)
Node representMapping(in string tag, Node.Pair[] pairs,
CollectionStyle style = CollectionStyle.Invalid)
{
Node.Pair[] value;
value.length = pairs.length;
auto bestStyle = CollectionStyle.Flow;
foreach(idx, ref pair; pairs)
{
value[idx] = Node.Pair(representData(pair.key), representData(pair.value));
const keyScalar = value[idx].key.isScalar;
const valScalar = value[idx].value.isScalar;
const keyStyle = value[idx].key.scalarStyle;
const valStyle = value[idx].value.scalarStyle;
if(!keyScalar ||
(keyStyle != ScalarStyle.Invalid && keyStyle != ScalarStyle.Plain)))
{
bestStyle = CollectionStyle.Block;
}
if(!valScalar ||
(valStyle != ScalarStyle.Invalid && valStyle != ScalarStyle.Plain)))
{
bestStyle = CollectionStyle.Block;
}
}
return Node.rawNode(Node.Value(value), Mark(), Tag(tag));
if(style == CollectionStyle.Invalid)
{
style = defaultCollectionStyle_ != CollectionStyle.Invalid
? defaultCollectionStyle_
: bestStyle;
}
return Node.rawNode(Node.Value(value), Mark(), Tag(tag),
ScalarStyle.Invalid, style);
}
package:
@ -300,7 +372,19 @@ final class Representer
new RepresenterException("No representer function for type "
~ type.toString() ~ " , cannot represent."));
Node result = representers_[type](data, this);
//Override tag if specified.
if(!data.tag_.isNull()){result.tag_ = data.tag_;}
//Remember style if this was loaded before.
if(data.scalarStyle != ScalarStyle.Invalid)
{
result.scalarStyle = data.scalarStyle;
}
if(data.collectionStyle != CollectionStyle.Invalid)
{
result.collectionStyle = data.collectionStyle;
}
return result;
}
@ -323,8 +407,9 @@ Node representNull(ref Node node, Representer representer)
Node representString(ref Node node, Representer representer)
{
string value = node.as!string;
return value is null ? representNull(node, representer)
: representer.representScalar("tag:yaml.org,2002:str", value);
return value is null
? representNull(node, representer)
: representer.representScalar("tag:yaml.org,2002:str", value);
}
///Represent a bytes _node as a binary scalar.
@ -333,7 +418,8 @@ Node representBytes(ref Node node, Representer representer)
const ubyte[] value = node.as!(ubyte[]);
if(value is null){return representNull(node, representer);}
return representer.representScalar("tag:yaml.org,2002:binary",
cast(string)Base64.encode(value));
cast(string)Base64.encode(value),
ScalarStyle.Literal);
}
///Represent a bool _node as a bool scalar.

View file

@ -27,6 +27,7 @@ import dyaml.escapes;
import dyaml.exception;
import dyaml.queue;
import dyaml.reader;
import dyaml.style;
import dyaml.token;

View file

@ -194,7 +194,7 @@ struct Serializer
bool isDefault = node.tag_ == defaultTag;
emitter_.emit(scalarEvent(Mark(), Mark(), aliased, node.tag_,
tuple(isDetected, isDefault), value, ScalarStyle.Invalid));
tuple(isDetected, isDefault), value, node.scalarStyle));
return;
}
if(node.isSequence)
@ -202,7 +202,7 @@ struct Serializer
const defaultTag = resolver_.defaultSequenceTag;
bool implicit = node.tag_ == defaultTag;
emitter_.emit(sequenceStartEvent(Mark(), Mark(), aliased, node.tag_,
implicit, CollectionStyle.Invalid));
implicit, node.collectionStyle));
foreach(ref Node item; node)
{
serializeNode(item);
@ -215,7 +215,7 @@ struct Serializer
auto defaultTag = resolver_.defaultMappingTag;
bool implicit = node.tag_ == defaultTag;
emitter_.emit(mappingStartEvent(Mark(), Mark(), aliased, node.tag_,
implicit, CollectionStyle.Invalid));
implicit, node.collectionStyle));
foreach(ref Node key, ref Node value; node)
{
serializeNode(key);

28
dyaml/style.d Normal file
View file

@ -0,0 +1,28 @@
// Copyright Ferdinand Majerech 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
///YAML node formatting styles.
module dyaml.style;
///Scalar styles.
enum ScalarStyle : ubyte
{
Invalid = 0, /// Invalid (uninitialized) style
Literal, /// | (Literal block style)
Folded, /// > (Folded block style)
Plain, /// Plain scalar
SingleQuoted, /// Single quoted scalar
DoubleQuoted /// Double quoted scalar
}
///Collection styles.
enum CollectionStyle : ubyte
{
Invalid = 0, /// Invalid (uninitialized) style
Block, /// Block style.
Flow /// Flow style.
}

View file

@ -16,6 +16,7 @@ import std.conv;
import dyaml.encoding;
import dyaml.exception;
import dyaml.reader;
import dyaml.style;
package:
@ -45,25 +46,6 @@ enum TokenID : ubyte
Scalar /// SCALAR
}
///Scalar styles.
enum ScalarStyle : ubyte
{
Invalid = 0, /// Invalid (uninitialized) style
Literal, /// | (Literal block style)
Folded, /// > (Folded block style)
Plain, /// Plain scalar
SingleQuoted, /// Single quoted scalar
DoubleQuoted /// Double quoted scalar
}
///Collection styles.
enum CollectionStyle : ubyte
{
Invalid = 0, /// Invalid (uninitialized) style
Block, /// Block style.
Flow /// Flow style.
}
/**
* Token produced by scanner.
*

1
yaml.d
View file

@ -14,4 +14,5 @@ public import dyaml.linebreak;
public import dyaml.loader;
public import dyaml.representer;
public import dyaml.resolver;
public import dyaml.style;
public import dyaml.node;