From 8dfea1a8eca438426ebf98a56a2232b8d60d8157 Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Wed, 15 Jun 2016 17:56:00 +0100 Subject: [PATCH 1/7] Make the IYamlSerializable interface obsolete. It has been superseded by IYamlConvertible. Add the missing bits that made IYamlSerializable impossible to use. --- YamlDotNet/Serialization/Deserializer.cs | 4 ++ YamlDotNet/Serialization/IYamlConvertible.cs | 42 +++++++++++++++ YamlDotNet/Serialization/IYamlSerializable.cs | 2 + .../CollectionNodeDeserializer.cs | 2 +- .../YamlConvertibleNodeDeserializer.cs | 50 ++++++++++++++++++ .../YamlSerializableNodeDeserializer.cs | 52 +++++++++++++++++++ .../YamlConvertibleTypeResolver.cs | 34 ++++++++++++ .../YamlSerializableTypeResolver.cs | 36 +++++++++++++ .../CustomSerializationObjectGraphVisitor.cs | 11 +++- YamlDotNet/YamlDotNet.csproj | 5 ++ 10 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 YamlDotNet/Serialization/IYamlConvertible.cs create mode 100644 YamlDotNet/Serialization/NodeDeserializers/YamlConvertibleNodeDeserializer.cs create mode 100644 YamlDotNet/Serialization/NodeDeserializers/YamlSerializableNodeDeserializer.cs create mode 100644 YamlDotNet/Serialization/NodeTypeResolvers/YamlConvertibleTypeResolver.cs create mode 100644 YamlDotNet/Serialization/NodeTypeResolvers/YamlSerializableTypeResolver.cs diff --git a/YamlDotNet/Serialization/Deserializer.cs b/YamlDotNet/Serialization/Deserializer.cs index cf6857d31..90bdc0f1c 100644 --- a/YamlDotNet/Serialization/Deserializer.cs +++ b/YamlDotNet/Serialization/Deserializer.cs @@ -106,6 +106,8 @@ public Deserializer( } NodeDeserializers = new List(); + NodeDeserializers.Add(new YamlConvertibleNodeDeserializer(objectFactory)); + NodeDeserializers.Add(new YamlSerializableNodeDeserializer(objectFactory)); NodeDeserializers.Add(new TypeConverterNodeDeserializer(converters)); NodeDeserializers.Add(new NullNodeDeserializer()); NodeDeserializers.Add(new ScalarNodeDeserializer()); @@ -117,6 +119,8 @@ public Deserializer( tagMappings = new Dictionary(predefinedTagMappings); TypeResolvers = new List(); + TypeResolvers.Add(new YamlConvertibleTypeResolver()); + TypeResolvers.Add(new YamlSerializableTypeResolver()); TypeResolvers.Add(new TagNodeTypeResolver(tagMappings)); TypeResolvers.Add(new TypeNameInTagNodeTypeResolver()); TypeResolvers.Add(new DefaultContainersNodeTypeResolver()); diff --git a/YamlDotNet/Serialization/IYamlConvertible.cs b/YamlDotNet/Serialization/IYamlConvertible.cs new file mode 100644 index 000000000..40ec3b412 --- /dev/null +++ b/YamlDotNet/Serialization/IYamlConvertible.cs @@ -0,0 +1,42 @@ +// This file is part of YamlDotNet - A .NET library for YAML. +// Copyright (c) Antoine Aubry and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using YamlDotNet.Core; + +namespace YamlDotNet.Serialization +{ + /// + /// Allows an object to customize how it is serialized and deserialized. + /// + public interface IYamlConvertible + { + /// + /// Reads this object's state from a YAML parser. + /// + void Read(EventReader reader, Type expectedType, Func nestedObjectDeserializer); + + /// + /// Writes this object's state to a YAML emitter. + /// + void Write(IEmitter emitter); + } +} \ No newline at end of file diff --git a/YamlDotNet/Serialization/IYamlSerializable.cs b/YamlDotNet/Serialization/IYamlSerializable.cs index f83b46650..e6c7c45a2 100644 --- a/YamlDotNet/Serialization/IYamlSerializable.cs +++ b/YamlDotNet/Serialization/IYamlSerializable.cs @@ -19,6 +19,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System; using YamlDotNet.Core; namespace YamlDotNet.Serialization @@ -26,6 +27,7 @@ namespace YamlDotNet.Serialization /// /// Allows an object to customize how it is serialized and deserialized. /// + [Obsolete("Please use IYamlConvertible instead")] public interface IYamlSerializable { /// diff --git a/YamlDotNet/Serialization/NodeDeserializers/CollectionNodeDeserializer.cs b/YamlDotNet/Serialization/NodeDeserializers/CollectionNodeDeserializer.cs index 9745fed90..5ce0234d9 100644 --- a/YamlDotNet/Serialization/NodeDeserializers/CollectionNodeDeserializer.cs +++ b/YamlDotNet/Serialization/NodeDeserializers/CollectionNodeDeserializer.cs @@ -67,7 +67,7 @@ bool INodeDeserializer.Deserialize(EventReader reader, Type expectedType, Func nestedObjectDeserializer, out object value) + { + if (typeof(IYamlConvertible).IsAssignableFrom(expectedType)) + { + var convertible = (IYamlConvertible)objectFactory.Create(expectedType); + convertible.Read(reader, expectedType, nestedObjectDeserializer); + value = convertible; + return true; + } + + value = null; + return false; + } + } +} diff --git a/YamlDotNet/Serialization/NodeDeserializers/YamlSerializableNodeDeserializer.cs b/YamlDotNet/Serialization/NodeDeserializers/YamlSerializableNodeDeserializer.cs new file mode 100644 index 000000000..e5222d01b --- /dev/null +++ b/YamlDotNet/Serialization/NodeDeserializers/YamlSerializableNodeDeserializer.cs @@ -0,0 +1,52 @@ +// This file is part of YamlDotNet - A .NET library for YAML. +// Copyright (c) Antoine Aubry +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using YamlDotNet.Core; + +namespace YamlDotNet.Serialization.NodeDeserializers +{ + public sealed class YamlSerializableNodeDeserializer : INodeDeserializer + { + private readonly IObjectFactory objectFactory; + + public YamlSerializableNodeDeserializer(IObjectFactory objectFactory) + { + this.objectFactory = objectFactory; + } + + public bool Deserialize(EventReader reader, Type expectedType, Func nestedObjectDeserializer, out object value) + { +#pragma warning disable 0618 // IYamlSerializable is obsolete + if (typeof(IYamlSerializable).IsAssignableFrom(expectedType)) + { + var serializable = (IYamlSerializable)objectFactory.Create(expectedType); + serializable.ReadYaml(reader.Parser); + value = serializable; + return true; + } +#pragma warning restore + + value = null; + return false; + } + } +} diff --git a/YamlDotNet/Serialization/NodeTypeResolvers/YamlConvertibleTypeResolver.cs b/YamlDotNet/Serialization/NodeTypeResolvers/YamlConvertibleTypeResolver.cs new file mode 100644 index 000000000..f9f1f99e0 --- /dev/null +++ b/YamlDotNet/Serialization/NodeTypeResolvers/YamlConvertibleTypeResolver.cs @@ -0,0 +1,34 @@ +// This file is part of YamlDotNet - A .NET library for YAML. +// Copyright (c) Antoine Aubry +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using YamlDotNet.Core.Events; + +namespace YamlDotNet.Serialization.NodeTypeResolvers +{ + public sealed class YamlConvertibleTypeResolver : INodeTypeResolver + { + public bool Resolve(NodeEvent nodeEvent, ref Type currentType) + { + return typeof(IYamlConvertible).IsAssignableFrom(currentType); + } + } +} diff --git a/YamlDotNet/Serialization/NodeTypeResolvers/YamlSerializableTypeResolver.cs b/YamlDotNet/Serialization/NodeTypeResolvers/YamlSerializableTypeResolver.cs new file mode 100644 index 000000000..4ee2fbab4 --- /dev/null +++ b/YamlDotNet/Serialization/NodeTypeResolvers/YamlSerializableTypeResolver.cs @@ -0,0 +1,36 @@ +// This file is part of YamlDotNet - A .NET library for YAML. +// Copyright (c) Antoine Aubry +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using YamlDotNet.Core.Events; + +namespace YamlDotNet.Serialization.NodeTypeResolvers +{ + public sealed class YamlSerializableTypeResolver : INodeTypeResolver + { + public bool Resolve(NodeEvent nodeEvent, ref Type currentType) + { +#pragma warning disable 0618 // IYamlSerializable is obsolete + return typeof(IYamlSerializable).IsAssignableFrom(currentType); +#pragma warning restore 0618 + } + } +} diff --git a/YamlDotNet/Serialization/ObjectGraphVisitors/CustomSerializationObjectGraphVisitor.cs b/YamlDotNet/Serialization/ObjectGraphVisitors/CustomSerializationObjectGraphVisitor.cs index 4c8ee7b19..86456cad8 100644 --- a/YamlDotNet/Serialization/ObjectGraphVisitors/CustomSerializationObjectGraphVisitor.cs +++ b/YamlDotNet/Serialization/ObjectGraphVisitors/CustomSerializationObjectGraphVisitor.cs @@ -48,12 +48,21 @@ public override bool Enter(IObjectDescriptor value) return false; } - var serializable = value as IYamlSerializable; + var convertible = value.Value as IYamlConvertible; + if (convertible != null) + { + convertible.Write(emitter); + return false; + } + +#pragma warning disable 0618 // IYamlSerializable is obsolete + var serializable = value.Value as IYamlSerializable; if (serializable != null) { serializable.WriteYaml(emitter); return false; } +#pragma warning restore return base.Enter(value); } diff --git a/YamlDotNet/YamlDotNet.csproj b/YamlDotNet/YamlDotNet.csproj index 803a7c7e3..6eefca24f 100644 --- a/YamlDotNet/YamlDotNet.csproj +++ b/YamlDotNet/YamlDotNet.csproj @@ -251,6 +251,7 @@ + @@ -259,6 +260,7 @@ + @@ -268,9 +270,12 @@ + + + From 2b3b398fcab54bab5cd489dda8012f87ccd716db Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Wed, 15 Jun 2016 17:58:11 +0100 Subject: [PATCH 2/7] Make YamlMappingNode, YamlSequenceNode and YamlScalarNode compatible with the serializar and deserializer. --- .../RepresentationModel/YamlMappingNode.cs | 20 +++++++++++++++-- .../RepresentationModel/YamlScalarNode.cs | 22 ++++++++++++++++--- .../RepresentationModel/YamlSequenceNode.cs | 20 +++++++++++++++-- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/YamlDotNet/RepresentationModel/YamlMappingNode.cs b/YamlDotNet/RepresentationModel/YamlMappingNode.cs index a980e30da..36d47d4ca 100644 --- a/YamlDotNet/RepresentationModel/YamlMappingNode.cs +++ b/YamlDotNet/RepresentationModel/YamlMappingNode.cs @@ -25,6 +25,7 @@ using System.Text; using YamlDotNet.Core; using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; namespace YamlDotNet.RepresentationModel { @@ -32,7 +33,7 @@ namespace YamlDotNet.RepresentationModel /// Represents a mapping node in the YAML document. /// [Serializable] - public class YamlMappingNode : YamlNode, IEnumerable> + public class YamlMappingNode : YamlNode, IEnumerable>, IYamlConvertible { private readonly IDictionary children = new Dictionary(); @@ -60,9 +61,14 @@ public IDictionary Children /// The events. /// The state. internal YamlMappingNode(EventReader events, DocumentLoadingState state) + { + Load(events, state); + } + + private void Load(EventReader events, DocumentLoadingState state) { MappingStart mapping = events.Expect(); - Load(mapping, state); + base.Load(mapping, state); bool hasUnresolvedAliases = false; while (!events.Accept()) @@ -385,5 +391,15 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() } #endregion + + void IYamlConvertible.Read(EventReader reader, Type expectedType, Func nestedObjectDeserializer) + { + Load(reader, new DocumentLoadingState()); + } + + void IYamlConvertible.Write(IEmitter emitter) + { + Emit(emitter, new EmitterState()); + } } } \ No newline at end of file diff --git a/YamlDotNet/RepresentationModel/YamlScalarNode.cs b/YamlDotNet/RepresentationModel/YamlScalarNode.cs index eacfa54fe..fe2b9972b 100644 --- a/YamlDotNet/RepresentationModel/YamlScalarNode.cs +++ b/YamlDotNet/RepresentationModel/YamlScalarNode.cs @@ -25,6 +25,7 @@ using System.Diagnostics; using YamlDotNet.Core; using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; namespace YamlDotNet.RepresentationModel { @@ -33,7 +34,7 @@ namespace YamlDotNet.RepresentationModel /// [DebuggerDisplay("{Value}")] [Serializable] - public class YamlScalarNode : YamlNode + public class YamlScalarNode : YamlNode, IYamlConvertible { /// /// Gets or sets the value of the node. @@ -53,9 +54,14 @@ public class YamlScalarNode : YamlNode /// The events. /// The state. internal YamlScalarNode(EventReader events, DocumentLoadingState state) + { + Load(events, state); + } + + private void Load(EventReader events, DocumentLoadingState state) { Scalar scalar = events.Expect(); - Load(scalar, state); + base.Load(scalar, state); Value = scalar.Value; Style = scalar.Style; } @@ -92,7 +98,7 @@ internal override void ResolveAliases(DocumentLoadingState state) /// The state. internal override void Emit(IEmitter emitter, EmitterState state) { - emitter.Emit(new Scalar(Anchor, Tag, Value, Style, true, false)); + emitter.Emit(new Scalar(Anchor, Tag, Value, Style, Tag == null, false)); } /// @@ -172,5 +178,15 @@ public override YamlNodeType NodeType { get { return YamlNodeType.Scalar; } } + + void IYamlConvertible.Read(EventReader reader, Type expectedType, Func nestedObjectDeserializer) + { + Load(reader, new DocumentLoadingState()); + } + + void IYamlConvertible.Write(IEmitter emitter) + { + Emit(emitter, new EmitterState()); + } } } \ No newline at end of file diff --git a/YamlDotNet/RepresentationModel/YamlSequenceNode.cs b/YamlDotNet/RepresentationModel/YamlSequenceNode.cs index f21e139fa..89b564de1 100644 --- a/YamlDotNet/RepresentationModel/YamlSequenceNode.cs +++ b/YamlDotNet/RepresentationModel/YamlSequenceNode.cs @@ -26,6 +26,7 @@ using YamlDotNet.Core; using YamlDotNet.Core.Events; using System.Text; +using YamlDotNet.Serialization; namespace YamlDotNet.RepresentationModel { @@ -34,7 +35,7 @@ namespace YamlDotNet.RepresentationModel /// [DebuggerDisplay("Count = {children.Count}")] [Serializable] - public class YamlSequenceNode : YamlNode, IEnumerable + public class YamlSequenceNode : YamlNode, IEnumerable, IYamlConvertible { private readonly IList children = new List(); @@ -63,9 +64,14 @@ public IList Children /// The events. /// The state. internal YamlSequenceNode(EventReader events, DocumentLoadingState state) + { + Load(events, state); + } + + private void Load(EventReader events, DocumentLoadingState state) { SequenceStart sequence = events.Expect(); - Load(sequence, state); + base.Load(sequence, state); bool hasUnresolvedAliases = false; while (!events.Accept()) @@ -285,5 +291,15 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() } #endregion + + void IYamlConvertible.Read(EventReader reader, Type expectedType, Func nestedObjectDeserializer) + { + Load(reader, new DocumentLoadingState()); + } + + void IYamlConvertible.Write(IEmitter emitter) + { + Emit(emitter, new EmitterState()); + } } } \ No newline at end of file From 711a76b7de042c55b13e375013b15c9b107f0649 Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Wed, 15 Jun 2016 17:58:50 +0100 Subject: [PATCH 3/7] Move the conversion operator of string to YamlScalarNode from YamlScalarNode to YamlNode. --- YamlDotNet/RepresentationModel/YamlNode.cs | 10 ++++++++++ YamlDotNet/RepresentationModel/YamlScalarNode.cs | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/YamlDotNet/RepresentationModel/YamlNode.cs b/YamlDotNet/RepresentationModel/YamlNode.cs index fae32940f..f6fd0f65c 100644 --- a/YamlDotNet/RepresentationModel/YamlNode.cs +++ b/YamlDotNet/RepresentationModel/YamlNode.cs @@ -212,5 +212,15 @@ public abstract YamlNodeType NodeType { get; } + + /// + /// Performs an implicit conversion from to . + /// + /// The value. + /// The result of the conversion. + public static implicit operator YamlNode(string value) + { + return new YamlScalarNode(value); + } } } \ No newline at end of file diff --git a/YamlDotNet/RepresentationModel/YamlScalarNode.cs b/YamlDotNet/RepresentationModel/YamlScalarNode.cs index fe2b9972b..6c9904317 100644 --- a/YamlDotNet/RepresentationModel/YamlScalarNode.cs +++ b/YamlDotNet/RepresentationModel/YamlScalarNode.cs @@ -132,16 +132,6 @@ public override int GetHashCode() ); } - /// - /// Performs an implicit conversion from to . - /// - /// The value. - /// The result of the conversion. - public static implicit operator YamlScalarNode(string value) - { - return new YamlScalarNode(value); - } - /// /// Performs an explicit conversion from to . /// From 6fd8e9a4b81817dfc8c6caa13a4a1ae52c8b61ec Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Fri, 17 Jun 2016 16:00:53 +0100 Subject: [PATCH 4/7] Add conversion operators and indexers for easier parsing and construction of YamlNodes. --- .../RepresentationModel/YamlMappingNode.cs | 24 ++++++++++ YamlDotNet/RepresentationModel/YamlNode.cs | 47 +++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/YamlDotNet/RepresentationModel/YamlMappingNode.cs b/YamlDotNet/RepresentationModel/YamlMappingNode.cs index 36d47d4ca..c6909e1b3 100644 --- a/YamlDotNet/RepresentationModel/YamlMappingNode.cs +++ b/YamlDotNet/RepresentationModel/YamlMappingNode.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Text; using YamlDotNet.Core; using YamlDotNet.Core.Events; @@ -401,5 +402,28 @@ void IYamlConvertible.Write(IEmitter emitter) { Emit(emitter, new EmitterState()); } + + /// + /// Creates a containing a key-value pair for each property of the specified object. + /// + public static YamlMappingNode FromObject(object mapping) + { + if (mapping == null) + { + throw new ArgumentNullException("mapping"); + } + + var result = new YamlMappingNode(); + foreach (var property in mapping.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) + { + if (property.CanRead && property.GetGetMethod().GetParameters().Length == 0) + { + var value = property.GetValue(mapping, null); + var valueNode = (value as YamlNode) ?? (Convert.ToString(value)); + result.Add(property.Name, valueNode); + } + } + return result; + } } } \ No newline at end of file diff --git a/YamlDotNet/RepresentationModel/YamlNode.cs b/YamlDotNet/RepresentationModel/YamlNode.cs index f6fd0f65c..dcf87b9b8 100644 --- a/YamlDotNet/RepresentationModel/YamlNode.cs +++ b/YamlDotNet/RepresentationModel/YamlNode.cs @@ -1,16 +1,16 @@ // This file is part of YamlDotNet - A .NET library for YAML. // Copyright (c) Antoine Aubry and contributors - + // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: - + // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. - + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -20,6 +20,7 @@ // SOFTWARE. using System; +using System.Linq; using YamlDotNet.Core; using YamlDotNet.Core.Events; using System.Collections.Generic; @@ -222,5 +223,45 @@ public static implicit operator YamlNode(string value) { return new YamlScalarNode(value); } + + /// + /// Performs an implicit conversion from string[] to . + /// + /// The value. + /// The result of the conversion. + public static implicit operator YamlNode(string[] sequence) + { + return new YamlSequenceNode(sequence.Select(i => (YamlNode)i)); + } + + /// + /// Converts a to a string by returning its value. + /// + public static explicit operator string(YamlNode scalar) + { + return ((YamlScalarNode)scalar).Value; + } + + /// + /// Gets the nth element in a . + /// + public YamlNode this[int index] + { + get + { + return ((YamlSequenceNode)this).Children[index]; + } + } + + /// + /// Gets the value associated with a key in a . + /// + public YamlNode this[YamlNode key] + { + get + { + return ((YamlMappingNode)this).Children[key]; + } + } } } \ No newline at end of file From 3e7073d94bfb2edea09cfae8f0b7577473db7b73 Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Wed, 15 Jun 2016 17:58:56 +0100 Subject: [PATCH 5/7] Add unit tests and fix bugs. --- .../RepresentationModelSerializationTests.cs | 108 ++++++++++++++++++ YamlDotNet.Test/YamlDotNet.Test.csproj | 1 + .../RepresentationModel/YamlMappingNode.cs | 1 + .../RepresentationModel/YamlSequenceNode.cs | 1 + 4 files changed, 111 insertions(+) create mode 100644 YamlDotNet.Test/Serialization/RepresentationModelSerializationTests.cs diff --git a/YamlDotNet.Test/Serialization/RepresentationModelSerializationTests.cs b/YamlDotNet.Test/Serialization/RepresentationModelSerializationTests.cs new file mode 100644 index 000000000..9382d3091 --- /dev/null +++ b/YamlDotNet.Test/Serialization/RepresentationModelSerializationTests.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; +using YamlDotNet.Core; +using YamlDotNet.RepresentationModel; +using YamlDotNet.Serialization; + +namespace YamlDotNet.Test.Serialization +{ + public class RepresentationModelSerializationTests + { + [Theory] + [InlineData("hello", "hello")] + [InlineData("'hello'", "hello")] + [InlineData("\"hello\"", "hello")] + [InlineData("!!int 123", "123")] + public void ScalarIsSerializable(string yaml, string expectedValue) + { + var deserializer = new Deserializer(); + var node = deserializer.Deserialize(Yaml.ReaderForText(yaml)); + + Assert.NotNull(node); + Assert.Equal(expectedValue, node.Value); + + var serializer = new Serializer(); + var buffer = new StringWriter(); + serializer.Serialize(buffer, node); + Assert.Equal(yaml, buffer.ToString().TrimEnd('\r', '\n', '.')); + } + + [Theory] + [InlineData("[a]", new[] { "a" })] + [InlineData("['a']", new[] { "a" })] + [InlineData("- a\r\n- b", new[] { "a", "b" })] + public void SequenceIsSerializable(string yaml, string[] expectedValues) + { + var deserializer = new Deserializer(); + var node = deserializer.Deserialize(Yaml.ReaderForText(yaml)); + + Assert.NotNull(node); + Assert.Equal(expectedValues.Length, node.Children.Count); + for (int i = 0; i < expectedValues.Length; i++) + { + Assert.Equal(expectedValues[i], ((YamlScalarNode)node.Children[i]).Value); + } + + var serializer = new Serializer(); + var buffer = new StringWriter(); + serializer.Serialize(buffer, node); + Assert.Equal(yaml, buffer.ToString().TrimEnd('\r', '\n', '.')); + } + + [Theory] + [InlineData("{a: b}", new[] { "a", "b" })] + [InlineData("{'a': \"b\"}", new[] { "a", "b" })] + [InlineData("a: b\r\nc: d", new[] { "a", "b", "c", "d" })] + public void MappingIsSerializable(string yaml, string[] expectedKeysAndValues) + { + var deserializer = new Deserializer(); + var node = deserializer.Deserialize(Yaml.ReaderForText(yaml)); + + Assert.NotNull(node); + Assert.Equal(expectedKeysAndValues.Length / 2, node.Children.Count); + for (int i = 0; i < expectedKeysAndValues.Length; i += 2) + { + Assert.Equal(expectedKeysAndValues[i + 1], ((YamlScalarNode)node.Children[expectedKeysAndValues[i]]).Value); + } + + var serializer = new Serializer(); + var buffer = new StringWriter(); + serializer.Serialize(buffer, node); + Assert.Equal(yaml, buffer.ToString().TrimEnd('\r', '\n', '.')); + } + } + + public class ByteArrayConverter : IYamlTypeConverter + { + public bool Accepts(Type type) + { + return type == typeof(byte[]); + } + + public object ReadYaml(IParser parser, Type type) + { + var scalar = (YamlDotNet.Core.Events.Scalar)parser.Current; + var bytes = Convert.FromBase64String(scalar.Value); + parser.MoveNext(); + return bytes; + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var bytes = (byte[])value; + emitter.Emit(new YamlDotNet.Core.Events.Scalar( + null, + "tag:yaml.org,2002:binary", + Convert.ToBase64String(bytes), + ScalarStyle.Plain, + false, + false + )); + } + } +} diff --git a/YamlDotNet.Test/YamlDotNet.Test.csproj b/YamlDotNet.Test/YamlDotNet.Test.csproj index b0ea8f9e9..ee0222b35 100644 --- a/YamlDotNet.Test/YamlDotNet.Test.csproj +++ b/YamlDotNet.Test/YamlDotNet.Test.csproj @@ -102,6 +102,7 @@ + diff --git a/YamlDotNet/RepresentationModel/YamlMappingNode.cs b/YamlDotNet/RepresentationModel/YamlMappingNode.cs index c6909e1b3..a7fbae6bf 100644 --- a/YamlDotNet/RepresentationModel/YamlMappingNode.cs +++ b/YamlDotNet/RepresentationModel/YamlMappingNode.cs @@ -70,6 +70,7 @@ private void Load(EventReader events, DocumentLoadingState state) { MappingStart mapping = events.Expect(); base.Load(mapping, state); + Style = mapping.Style; bool hasUnresolvedAliases = false; while (!events.Accept()) diff --git a/YamlDotNet/RepresentationModel/YamlSequenceNode.cs b/YamlDotNet/RepresentationModel/YamlSequenceNode.cs index 89b564de1..222571af2 100644 --- a/YamlDotNet/RepresentationModel/YamlSequenceNode.cs +++ b/YamlDotNet/RepresentationModel/YamlSequenceNode.cs @@ -72,6 +72,7 @@ private void Load(EventReader events, DocumentLoadingState state) { SequenceStart sequence = events.Expect(); base.Load(sequence, state); + Style = sequence.Style; bool hasUnresolvedAliases = false; while (!events.Accept()) From 46f296db469ad80870222277d4c4e428a2343feb Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Fri, 17 Jun 2016 16:05:17 +0100 Subject: [PATCH 6/7] Do not assign anchors to scalars when saving a YamlDocument. --- YamlDotNet/RepresentationModel/YamlDocument.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YamlDotNet/RepresentationModel/YamlDocument.cs b/YamlDotNet/RepresentationModel/YamlDocument.cs index 2c7b192c7..cac4fd99f 100644 --- a/YamlDotNet/RepresentationModel/YamlDocument.cs +++ b/YamlDotNet/RepresentationModel/YamlDocument.cs @@ -149,7 +149,7 @@ private void VisitNode(YamlNode node) protected override void Visit(YamlScalarNode scalar) { - VisitNode(scalar); + // Do not assign anchors to scalars } protected override void Visit(YamlMappingNode mapping) From 01b0679e56c7ff534820699ccb7065893868c288 Mon Sep 17 00:00:00 2001 From: Antoine Aubry Date: Fri, 17 Jun 2016 16:59:20 +0100 Subject: [PATCH 7/7] Fix compilation error on portable target. --- YamlDotNet/RepresentationModel/YamlMappingNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YamlDotNet/RepresentationModel/YamlMappingNode.cs b/YamlDotNet/RepresentationModel/YamlMappingNode.cs index a7fbae6bf..29171c3db 100644 --- a/YamlDotNet/RepresentationModel/YamlMappingNode.cs +++ b/YamlDotNet/RepresentationModel/YamlMappingNode.cs @@ -415,7 +415,7 @@ public static YamlMappingNode FromObject(object mapping) } var result = new YamlMappingNode(); - foreach (var property in mapping.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) + foreach (var property in mapping.GetType().GetPublicProperties()) { if (property.CanRead && property.GetGetMethod().GetParameters().Length == 0) {