Skip to content

Commit

Permalink
Merge branch 'feature/TypedMetadata'
Browse files Browse the repository at this point in the history
Closes #2

* feature/TypedMetadata:
  More README
  CodeFactor yelled at me
  Update README
  Use ReferenceEquals instead of ==
  Bump version
  New class SimpleMetadata
  Visual studio keeps changing this XML back
  Clean CodeFactor recommendations
  Add CodeFactor badge to README
  • Loading branch information
bcronce committed Oct 6, 2019
2 parents b7ec3be + a7b2b82 commit 86c1674
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 9 deletions.
4 changes: 2 additions & 2 deletions BoringHelpers/BoringHelpers.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard1.3;net46</TargetFrameworks>
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
<Authors>Benjamin Cronce</Authors>
<Version>0.1.2.0</Version>
<Version>0.1.3.0</Version>
<Copyright>Copyright ©2019 Benjamin Cronce</Copyright>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageProjectUrl>https://github.com/bcronce/BoringHelpers</PackageProjectUrl>
Expand Down
4 changes: 1 addition & 3 deletions BoringHelpers/Collections/Empty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace BoringHelpers.Collections
{
public static class Empty
{
public struct VoidStruct { };
public struct VoidStruct { }

public static IList<T> List<T>() => EmptyCollection<T, VoidStruct>.Singleton();

Expand Down Expand Up @@ -121,7 +121,6 @@ public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { } //no-

private class EmptyEnumerator<T> : IEnumerator<T>
{

public static EmptyEnumerator<T> Singleton { get; protected set; } = new EmptyEnumerator<T>();
protected EmptyEnumerator() { }

Expand All @@ -134,7 +133,6 @@ protected EmptyEnumerator() { }
public void Reset() { }

public void Dispose() { }

}
}
}
4 changes: 1 addition & 3 deletions BoringHelpers/Collections/Individual.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ public bool MoveNext()
public void Reset() => throw new NotSupportedException();

public void Dispose()
{

}
{ }
}

private class SingleCollection<T> : ICollection<T>, IReadOnlyCollection<T>
Expand Down
14 changes: 14 additions & 0 deletions BoringHelpers/Types/CaseInsensitiveMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;

namespace BoringHelpers.Types
{
public abstract class CaseInsensitiveMetadata : SimpleMetadata<string>
{
protected override IEqualityComparer<string> EqualityComparer { get { return StringComparer.OrdinalIgnoreCase; } }
protected override IComparer<string> Comparer { get { return StringComparer.OrdinalIgnoreCase; } }

protected CaseInsensitiveMetadata(string value)
: base(value) { }
}
}
83 changes: 83 additions & 0 deletions BoringHelpers/Types/SimpleMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace BoringHelpers.Types
{
public abstract class SimpleMetadata<T> : IComparable<SimpleMetadata<T>>, IEquatable<SimpleMetadata<T>>, IComparable where T : IComparable<T>, IComparable
{
private const int CompareIsEqual = 0;
public readonly T Value;

protected SimpleMetadata(T value)
{
this.Value = value;
}

protected virtual IEqualityComparer<T> EqualityComparer { get { return EqualityComparer<T>.Default; } }
protected virtual IComparer<T> Comparer { get { return Comparer<T>.Default; } }

public override bool Equals(object obj) => this.Equals(obj as SimpleMetadata<T>);

public bool Equals(SimpleMetadata<T> other)
{
if (object.ReferenceEquals(other, null)) return false;
if (this.GetType() != other.GetType()) return false;
return this.CompareTo(other) == CompareIsEqual;
}

public bool Equals(T other) => Comparer.Compare(this.Value, other) == CompareIsEqual;

public virtual int CompareTo(object obj)
{
if (this.GetType() != obj.GetType()) throw new ArgumentException($"{nameof(obj)} not the same type as this instance");
return this.CompareTo(obj as SimpleMetadata<T>);
}

public virtual int CompareTo(SimpleMetadata<T> other) => Comparer.Compare(this.Value, other.Value);

public override int GetHashCode() => EqualityComparer.GetHashCode(this.Value);

public override string ToString() => this.Value.ToString();

public static bool operator ==(SimpleMetadata<T> obj1, SimpleMetadata<T> obj2)
{
if (object.ReferenceEquals(obj1, null))
{
return object.ReferenceEquals(obj2, null);
}

return obj1.Equals(obj2);
}

public static bool operator ==(SimpleMetadata<T> obj1, T obj2)
{
if (object.ReferenceEquals(obj1, null))
{
return object.ReferenceEquals(obj2, null);
}

return obj1.Equals(obj2);
}

public static bool operator !=(SimpleMetadata<T> obj1, SimpleMetadata<T> obj2)
{
if (object.ReferenceEquals(obj1, null))
{
return !object.ReferenceEquals(obj2, null);
}

return !obj1.Equals(obj2);
}

public static bool operator !=(SimpleMetadata<T> obj1, T obj2)
{
if (object.ReferenceEquals(obj1, null))
{
return !object.ReferenceEquals(obj2, null);
}

return !obj1.Equals(obj2);
}
}
}
1 change: 0 additions & 1 deletion BoringHelpersTests/Collections/KeyThrowingDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using BoringHelpers.Collections;
using System;


namespace BoringHelpersTests.Collections
{
public class KeyThrowingDictionary
Expand Down
74 changes: 74 additions & 0 deletions BoringHelpersTests/Types/SimpleMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Xunit;
using System.Collections.Generic;
using BoringHelpers.Types;
using System;
using System.Linq;

namespace BoringHelpersTests.Types
{
public class SimpleMetadata
{
[Fact]
public void Simple_Equal()
{
var value = "foobar";
var item1 = new SimpleString(value);
var item2 = new SimpleString(value);
Assert.Equal(item1, item2);
}

[Fact]
public void Simple_Equal_Direct()
{
var value = "foobar";
var item1 = new SimpleString("foobar");
Assert.True(item1 == value);
}

[Fact]
public void Simple_NotEqual()
{
var value = "foobar";
var item1 = new SimpleString(value.ToLower());
var item2 = new SimpleString(value.ToUpper());
Assert.NotEqual(item1, item2);
}

[Fact]
public void Simple_NotEqual_Direct()
{
var value = "foobar";
var item1 = new SimpleString(value.ToLower());
Assert.False(item1 == value.ToUpper());
}

[Fact]
public void CaseInsentive_Equal()
{
var value = "foobar";
var item1 = new SimpleStringIgnoreCase(value.ToLower());
var item2 = new SimpleStringIgnoreCase(value.ToUpper());
Assert.Equal(item1, item2);
}

[Fact]
public void CaseInsentive_NotEqual()
{
var value = "foobar";
var item1 = new SimpleStringIgnoreCase(value);
var item2 = new SimpleStringIgnoreCase(value+"_");
Assert.NotEqual(item1, item2);
}

[Fact]
public void SortedSame()
{
var orignal = Enumerable.Range(0,5).Select(i => i.ToString());
var metadata = orignal.Select(s => new SimpleString(s));

Assert.Equal(orignal.OrderBy(s => s), metadata.OrderBy(m => m).Select(m => m.Value));
Assert.Equal(orignal.OrderByDescending(s => s), metadata.OrderByDescending(m => m).Select(m => m.Value));
Assert.NotEqual(orignal.OrderBy(s => s), metadata.OrderByDescending(m => m).Select(m => m.Value));
}
}
}
12 changes: 12 additions & 0 deletions BoringHelpersTests/Types/SimpleString.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using BoringHelpers.Types;
using System;
using System.Collections.Generic;

namespace BoringHelpersTests.Types
{
public class SimpleString : SimpleMetadata<string>
{
public SimpleString(string value)
: base(value) { }
}
}
12 changes: 12 additions & 0 deletions BoringHelpersTests/Types/SimpleStringIgnoreCase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using BoringHelpers.Types;
using System;
using System.Collections.Generic;

namespace BoringHelpersTests.Types
{
public class SimpleStringIgnoreCase : CaseInsensitiveMetadata
{
public SimpleStringIgnoreCase(string value)
: base(value) { }
}
}
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
[![Licence](https://img.shields.io/github/license/bcronce/BoringHelpers.svg)](LICENSE)
[![Build Status](https://travis-ci.org/bcronce/BoringHelpers.svg?branch=master)](https://travis-ci.org/bcronce/BoringHelpers)
[![NuGet](https://img.shields.io/nuget/v/BoringHelpers.svg)](https://www.nuget.org/packages/BoringHelpers/)
[![CodeFactor](https://www.codefactor.io/repository/github/bcronce/boringhelpers/badge)](https://www.codefactor.io/repository/github/bcronce/boringhelpers)


General use library inspired by common patterns seen in production code.

Expand Down Expand Up @@ -30,3 +32,54 @@ Also in my expereience, many of these single element collections tend to be allo
Admit it. You've had it where some quickly slapped together project throws a `KeyNotFound` exception and you get driven crazy that you have no idea what `key` caused the exception.

I was originally going to create a new class that wrapped a `Dictionary`, but that would cause more code paths to have to be tested and meant two objects would be created. I played around with just inheriting from `Dictionary` and it worked well. It allowed for a minimal class that only changed the few methods that I cared to change with the additional benefit that this can be downcasted into a `Dictionary` for those times someone didn't give an `IDictionary` signature.

# Types
For now, it's just `SimpleMetadata`
## SimpleMetadata
Some times you have coode that looks like
```csharp
void SomeMethod(Guid id, string typeId)
```
And it's just `Guid` this and `string` that. So you want to make proper types so you code can look like
```csharp
void SomeMethod(EntityId id, EntityTypeId typeId)
```
But can be a lot of yak shaving if you want to have something like `Dictionary<EntityId, value>`. You can instead do something like
```csharp
public class EntityId : SimpleMetadata<Guid>
{
public EntityId(string value)
: base(value) { }
}
```
Now you have `EntityId` without all of the setup.

And if you have some special situation, you can easily override the behavior, like case insensitive.
```csharp
public abstract class EntityTypeId : SimpleMetadata<string>
{
protected override IEqualityComparer<string> EqualityComparer { get { return StringComparer.OrdinalIgnoreCase; } }
protected override IComparer<string> Comparer { get { return StringComparer.OrdinalIgnoreCase; } }

protected EntityTypeId(string value)
: base(value) { }
}
```

And since case insensetive is such a common thing, I already included a class `CaseInsensitiveMetadata` that is implemented like the above `EntityTypeId` example.

And yes, `==` is overriden. So you get this out of the box.
```csharp
public class EntityId : SimpleMetadata<Guid>
{
public EntityId(string value)
: base(value) { }
}

Guid value = Guid.NewGuid();
EntityId id = new EntityId(value);
EntityId id2 = new EntityId(value);

Assert.True(id == id2);
Assert.True(id == value);
```

0 comments on commit 86c1674

Please sign in to comment.