From 5d35f44416344b63f12f202e820874336c3830f9 Mon Sep 17 00:00:00 2001 From: Ferdinand Majerech Date: Thu, 27 Oct 2011 23:13:14 +0200 Subject: [PATCH] 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. --- autoddoc.cfg | 2 +- doc/doctrees/environment.pickle | Bin 12705 -> 12705 bytes doc/html/api/dyaml.loader.html | 2 +- doc/html/api/dyaml.node.html | 10 +++ doc/html/api/dyaml.representer.html | 29 ++++++- doc/html/articles/spec_differences.html | 2 +- doc/html/index.html | 2 +- doc/html/search.html | 2 +- doc/html/tutorials/custom_types.html | 2 +- doc/html/tutorials/getting_started.html | 2 +- doc/html/tutorials/yaml_syntax.html | 2 +- dyaml/composer.d | 6 +- dyaml/constructor.d | 20 ++++- dyaml/emitter.d | 2 +- dyaml/event.d | 7 +- dyaml/node.d | 33 +++++--- dyaml/parser.d | 1 + dyaml/representer.d | 106 +++++++++++++++++++++--- dyaml/scanner.d | 1 + dyaml/serializer.d | 6 +- dyaml/style.d | 28 +++++++ dyaml/token.d | 20 +---- yaml.d | 1 + 23 files changed, 218 insertions(+), 68 deletions(-) create mode 100644 dyaml/style.d diff --git a/autoddoc.cfg b/autoddoc.cfg index 15aea1f..741fd31 100644 --- a/autoddoc.cfg +++ b/autoddoc.cfg @@ -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. diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle index ecb58beed1a56d66ba151f19a3f3b1d6ec8e357a..2c074b70c6f55ccd41e8bdc8d4e253cb349f7902 100644 GIT binary patch delta 63 zcmZ3OyfAq~tG>~yBH0;{%QKYS9WMi!-AQjVbRf*Bg)1^lA~SZ5KG^7H25CJ6>L~?fkzxw=;CW%nK|ppJkXrm`sKrGVCA<{+~13 Jyj}klBLE=vA)5dI diff --git a/doc/html/api/dyaml.loader.html b/doc/html/api/dyaml.loader.html index 1223a95..f3f3e8f 100644 --- a/doc/html/api/dyaml.loader.html +++ b/doc/html/api/dyaml.loader.html @@ -112,7 +112,7 @@

Construct a Loader to load YAML from a stream.

Parameters:
- +
Stream streamStream to read from. Must be readable.
Stream to read from. Must be readable and seekable.
Throws:
YAMLException if stream could not be read.
diff --git a/doc/html/api/dyaml.node.html b/doc/html/api/dyaml.node.html index 825532d..5e58e4d 100644 --- a/doc/html/api/dyaml.node.html +++ b/doc/html/api/dyaml.node.html @@ -85,6 +85,16 @@
+ +
package ScalarStyle scalarStyle; +
+

Node scalar style. Used to remember style this node was loaded with.

+ +
+
package CollectionStyle collectionStyle; +
+

Node collection style. Used to remember style this node was loaded with.

+
auto this(T)(T value, in string tag = null);
diff --git a/doc/html/api/dyaml.representer.html b/doc/html/api/dyaml.representer.html index 4326e3f..8f8f002 100644 --- a/doc/html/api/dyaml.representer.html +++ b/doc/html/api/dyaml.representer.html @@ -51,7 +51,12 @@
class Representer;
-

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.

this(bool useDefaultRepresenters = true);
@@ -64,6 +69,16 @@ functions for default types. +
+
@property void defaultScalarStyle(ScalarStyle style); +
+

Set default style for scalars. Invalid means the style is chosen automatically.

+ +
+
@property void defaultCollectionStyle(CollectionStyle style); +
+

Set default style for collections. Invalid means the style is chosen automatically.

+
void addRepresenter(T)(Node function(ref Node, Representer) representer);
@@ -166,7 +181,7 @@ -
Node representScalar(in string tag, string scalar); +
Node representScalar(in string tag, string scalar, ScalarStyle style = (ScalarStyle).Invalid);

Represent a scalar with specified tag.

@@ -177,6 +192,8 @@ Tag of the scalar. string scalar Scalar value. +ScalarStyle style +Style of the scalar (will be default if invalid). Returns:
The represented node. @@ -197,7 +214,7 @@

-
Node representSequence(in string tag, Node[] sequence); +
Node representSequence(in string tag, Node[] sequence, CollectionStyle style = (CollectionStyle).Invalid);

Represent a sequence with specified tag, representing children first.

@@ -208,6 +225,8 @@ Tag of the sequence. Node[] sequence Sequence of nodes. +CollectionStyle style +Style of the sequence (will be default if invalid). Returns:
The represented node. @@ -231,7 +250,7 @@

-
Node representMapping(in string tag, Pair[] pairs); +
Node representMapping(in string tag, Pair[] pairs, CollectionStyle style = (CollectionStyle).Invalid);

Represent a mapping with specified tag, representing children first.

@@ -242,6 +261,8 @@ Tag of the mapping. Pair[] pairs Key-value pairs of the mapping. +CollectionStyle style +Style of the mapping (will be default if invalid). Returns:
The represented node. diff --git a/doc/html/articles/spec_differences.html b/doc/html/articles/spec_differences.html index 549aac8..aa571a2 100644 --- a/doc/html/articles/spec_differences.html +++ b/doc/html/articles/spec_differences.html @@ -138,7 +138,7 @@ struct appears in Phobos.

diff --git a/doc/html/index.html b/doc/html/index.html index 55c97b9..a2a4b45 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -104,7 +104,7 @@ diff --git a/doc/html/search.html b/doc/html/search.html index 71354f8..b78b597 100644 --- a/doc/html/search.html +++ b/doc/html/search.html @@ -87,7 +87,7 @@ diff --git a/doc/html/tutorials/custom_types.html b/doc/html/tutorials/custom_types.html index 5e92567..61113c9 100644 --- a/doc/html/tutorials/custom_types.html +++ b/doc/html/tutorials/custom_types.html @@ -369,7 +369,7 @@ directory of the D:YAML package.

diff --git a/doc/html/tutorials/getting_started.html b/doc/html/tutorials/getting_started.html index 1646e53..097e38d 100644 --- a/doc/html/tutorials/getting_started.html +++ b/doc/html/tutorials/getting_started.html @@ -237,7 +237,7 @@ example in the example/getting_st diff --git a/doc/html/tutorials/yaml_syntax.html b/doc/html/tutorials/yaml_syntax.html index 54f8742..fd99d4d 100644 --- a/doc/html/tutorials/yaml_syntax.html +++ b/doc/html/tutorials/yaml_syntax.html @@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).

diff --git a/dyaml/composer.d b/dyaml/composer.d index ce06730..bdd375c 100644 --- a/dyaml/composer.d +++ b/dyaml/composer.d @@ -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; } diff --git a/dyaml/constructor.d b/dyaml/constructor.d index 5ff3055..e0d883e 100644 --- a/dyaml/constructor.d +++ b/dyaml/constructor.d @@ -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: diff --git a/dyaml/emitter.d b/dyaml/emitter.d index d3027c9..1f87e0f 100644 --- a/dyaml/emitter.d +++ b/dyaml/emitter.d @@ -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: diff --git a/dyaml/event.d b/dyaml/event.d index e855cb4..2103386 100644 --- a/dyaml/event.d +++ b/dyaml/event.d @@ -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);} diff --git a/dyaml/node.d b/dyaml/node.d index dd90442..5798a61 100644 --- a/dyaml/node.d +++ b/dyaml/node.d @@ -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;} diff --git a/dyaml/parser.d b/dyaml/parser.d index 7b32a79..7c30895 100644 --- a/dyaml/parser.d +++ b/dyaml/parser.d @@ -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; diff --git a/dyaml/representer.d b/dyaml/representer.d index 6d9050a..95050f2 100644 --- a/dyaml/representer.d +++ b/dyaml/representer.d @@ -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. diff --git a/dyaml/scanner.d b/dyaml/scanner.d index e19ed65..7c05e87 100644 --- a/dyaml/scanner.d +++ b/dyaml/scanner.d @@ -27,6 +27,7 @@ import dyaml.escapes; import dyaml.exception; import dyaml.queue; import dyaml.reader; +import dyaml.style; import dyaml.token; diff --git a/dyaml/serializer.d b/dyaml/serializer.d index 600a853..4bf6c5a 100644 --- a/dyaml/serializer.d +++ b/dyaml/serializer.d @@ -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); diff --git a/dyaml/style.d b/dyaml/style.d new file mode 100644 index 0000000..3e4fe24 --- /dev/null +++ b/dyaml/style.d @@ -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. +} diff --git a/dyaml/token.d b/dyaml/token.d index 4a9a740..e4f0d98 100644 --- a/dyaml/token.d +++ b/dyaml/token.d @@ -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. * diff --git a/yaml.d b/yaml.d index 23ad18c..3551353 100644 --- a/yaml.d +++ b/yaml.d @@ -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;