Skip to content

Commit

Permalink
Merge pull request #475 from gregsdennis/yaml/add-serializer
Browse files Browse the repository at this point in the history
add yaml serializer to mimic json serializer (somewhat)
  • Loading branch information
gregsdennis committed Jun 13, 2023
2 parents cf823ac + 6f87cbd commit ffcd188
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 2 deletions.
15 changes: 15 additions & 0 deletions Yaml2JsonNode.Tests/Files/expected-serialized.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
StringProp: string
IntProp: 42
DecimalProp: 42.5
DoubleProp: 42.9
BoolProp: true
ListOfInts:
- 1
- 2
- 3
- 4
MapOfStrings:
string1: found
string2: lost
NestedObject:
OtherString: yep
143 changes: 143 additions & 0 deletions Yaml2JsonNode.Tests/SerializerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using NUnit.Framework;
// ReSharper disable NonReadonlyMemberInGetHashCode
#pragma warning disable NUnit2005
#pragma warning disable CS8618

namespace Yaml2JsonNode.Tests;

public class SerializerTests
{
private class Bar
{
public string OtherString { get; set; }

protected bool Equals(Bar other)
{
return OtherString == other.OtherString;
}

public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Bar)obj);
}

public override int GetHashCode()
{
return OtherString.GetHashCode();
}
}

private class Foo
{
public string StringProp { get; set; }
public int IntProp { get; set; }
public decimal DecimalProp { get; set; }
public double DoubleProp { get; set; }
public bool BoolProp { get; set; }
public List<int> ListOfInts { get; set; }
public Dictionary<string, string> MapOfStrings { get; set; }
public Bar NestedObject { get; set; }

protected bool Equals(Foo other)
{
var listEqual = ListOfInts.Zip(other.ListOfInts)
.All(x => x.First == x.Second);
var joinedMap = MapOfStrings.Join(other.MapOfStrings,
x => x.Key,
y => y.Key,
(x, y) => x.Value == y.Value)
.ToList();
var mapEqual = joinedMap.Count == MapOfStrings.Count && joinedMap.All(x => x);

return StringProp == other.StringProp &&
IntProp == other.IntProp &&
DecimalProp == other.DecimalProp &&
DoubleProp.Equals(other.DoubleProp) &&
BoolProp == other.BoolProp &&
listEqual &&
mapEqual &&
NestedObject.Equals(other.NestedObject);
}

public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Foo)obj);
}

public override int GetHashCode()
{
return HashCode.Combine(StringProp, IntProp, DecimalProp, DoubleProp, BoolProp, ListOfInts, MapOfStrings, NestedObject);
}
}

[Test]
public void SerializeObject()
{
var foo = new Foo
{
StringProp = "string",
IntProp = 42,
DecimalProp = 42.5m,
DoubleProp = 42.9,
BoolProp = true,
ListOfInts = new List<int> { 1, 2, 3, 4 },
MapOfStrings = new Dictionary<string, string>
{
["string1"] = "found",
["string2"] = "lost"
},
NestedObject = new Bar
{
OtherString = "yep"
}
};

var path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Files", "expected-serialized.yaml")
.AdjustForPlatform();

var expected = File.ReadAllText(path);

var actual = YamlSerializer.Serialize(foo);

Assert.AreEqual(expected, actual);
}

[Test]
public void DeserializeObject()
{
var path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Files", "expected-serialized.yaml")
.AdjustForPlatform();

var text = File.ReadAllText(path);

var expected = new Foo
{
StringProp = "string",
IntProp = 42,
DecimalProp = 42.5m,
DoubleProp = 42.9,
BoolProp = true,
ListOfInts = new List<int> { 1, 2, 3, 4 },
MapOfStrings = new Dictionary<string, string>
{
["string1"] = "found",
["string2"] = "lost"
},
NestedObject = new Bar
{
OtherString = "yep"
}
};


var actual = YamlSerializer.Deserialize<Foo>(text);

Assert.AreEqual(expected, actual);
}
}
3 changes: 3 additions & 0 deletions Yaml2JsonNode.Tests/Yaml2JsonNode.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
</ItemGroup>

<ItemGroup>
<None Update="Files\expected-serialized.yaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Files\yaml-content.yaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down
4 changes: 2 additions & 2 deletions Yaml2JsonNode/Yaml2JsonNode.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Yaml2JsonNode</PackageId>
<Authors>Greg Dennis</Authors>
<Version>1.1.1</Version>
<Version>1.2.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.1.1.0</FileVersion>
<FileVersion>1.2.0.0</FileVersion>
<Description>Allows conversion of YamlDotNet's YAML models to JsonNodes.</Description>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageProjectUrl>https://github.com/gregsdennis/json-everything</PackageProjectUrl>
Expand Down
104 changes: 104 additions & 0 deletions Yaml2JsonNode/YamlSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;

namespace Yaml2JsonNode;

/// <summary>
/// Provides common serializer functionality.
/// </summary>
public static class YamlSerializer
{
/// <summary>
/// Serializes an object to a YAML string
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="obj">The object.</param>
/// <param name="options">(optional) JSON serializer options.</param>
/// <param name="configure">(optional) YAML serializer configuration method.</param>
/// <returns>The YAML string.</returns>
public static string Serialize<T>(T obj, JsonSerializerOptions? options = null, Action<SerializerBuilder>? configure = null)
{
var json = JsonSerializer.SerializeToNode(obj, options);
var yaml = json!.ToYamlNode();

return Serialize(yaml, configure);
}

/// <summary>
/// Serializes a YAML stream (a collection of documents) to a string.
/// </summary>
/// <param name="yaml">The stream.</param>
/// <param name="configure">(optional) YAML serializer configuration method.</param>
/// <returns>The YAML string.</returns>
public static string Serialize(YamlStream yaml, Action<SerializerBuilder>? configure = null)
{
var builder = new SerializerBuilder();

configure?.Invoke(builder);

var serializer = builder.Build();

using var writer = new StringWriter();

foreach (var document in yaml.Documents)
{
serializer.Serialize(writer, document.RootNode);
}

return writer.ToString();
}

/// <summary>
/// Serializes a YAML document to a string.
/// </summary>
/// <param name="yaml">The document.</param>
/// <param name="configure">(optional) YAML serializer configuration method.</param>
/// <returns>The YAML string.</returns>
public static string Serialize(YamlDocument yaml, Action<SerializerBuilder>? configure = null)
{
return Serialize(new YamlStream(yaml), configure);
}

/// <summary>
/// Serializes a YAML node to a string
/// </summary>
/// <param name="yaml">The node.</param>
/// <param name="configure">(optional) YAML serializer configuration method.</param>
/// <returns>The YAML string.</returns>
public static string Serialize(YamlNode yaml, Action<SerializerBuilder>? configure = null)
{
return Serialize(new YamlDocument(yaml), configure);
}

/// <summary>
/// Deserializes the first YAML document found in text to an object.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="yamlText">The YAML text.</param>
/// <param name="options"></param>
/// <returns>The object or null.</returns>
public static T? Deserialize<T>(string yamlText, JsonSerializerOptions? options = null)
{
var yaml = Parse(yamlText).First();
var json = yaml.ToJsonNode();

return json.Deserialize<T>(options);
}

/// <summary>
/// Parses YAML text into a stream (collection of documents).
/// </summary>
/// <param name="yamlText">The YAML text.</param>
/// <returns>A YAML stream representing the content of the text.</returns>
public static YamlStream Parse(string yamlText)
{
using var reader = new StringReader(yamlText);
var yamlStream = new YamlStream();
yamlStream.Load(reader);
return yamlStream;
}
}
4 changes: 4 additions & 0 deletions tools/ApiDocsGenerator/release-notes/rn-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ title: Yaml2JsonNode
icon: fas fa-tag
order: "8.12"
---
# [1.2.0](https://github.com/gregsdennis/json-everything/pull/475) {#release-yaml-1.2.0}

Add `YamlSerializer` static class to provide more natural serializer methods.

# 1.1.1 (No PR) {#release-yaml-1.1.1}

Fixes issue with converting strings from JSON to YAML. Previously, quotes were included.
Expand Down

0 comments on commit ffcd188

Please sign in to comment.