Skip to content

Commit

Permalink
Merge pull request #75 from oliverzick/#74
Browse files Browse the repository at this point in the history
Resolve #74: Enable Transform match
  • Loading branch information
oliverzick committed Dec 15, 2020
2 parents 834dd91 + 0f7cb6e commit ec0e694
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] - 2020-12-16
### Added
- `Transform` match [[#74](https://github.com/oliverzick/Delizious-Toolkit/issues/74)]

## [1.0.0] - 2020-12-11
### Added
- `LessThanOrEqualTo` match for comparable types [[#54](https://github.com/oliverzick/Delizious-Toolkit/issues/54)]
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Match | What
`None` | Matches when a value matches none of the given matches
`Except` | (**obsolete**) Matches when a value matches none of the given matches
`Custom` | Matches when a value matches the given custom match
`Transform` | Transforms a current value into a transformed value first and then matches the transformed value with a given match

### Sample
The following sample shows the use of composition to combine different matches:
Expand Down
36 changes: 36 additions & 0 deletions src/Delizious.Toolkit.Test/MatchSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace Delizious
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Xunit;

public sealed class MatchSpec
Expand Down Expand Up @@ -916,6 +917,41 @@ public static IEnumerable<object[]> MatchesTheories()
}
}

public sealed class Transform
{
[Fact]
public void Throws_exception_when_transformation_is_null()
{
Assert.Throws<ArgumentNullException>(() => Match.Transform<int, string>(null!, Match.Always<string>()));
}

[Fact]
public void Throws_exception_when_match_is_null()
{
Assert.Throws<ArgumentNullException>(() => Match.Transform<int, string>(Transformation, null!));
}

[Theory]
[MemberData(nameof(MatchesTheories))]
public void Matches(bool expected, int value, Match<int> subject)
{
var actual = subject.Matches(value);

Assert.Equal(expected, actual);
}

public static IEnumerable<object[]> MatchesTheories()
{
yield return DataTheory(true, 123, Match.Transform<int, string>(value => (string)null!, Match.Null<string>()));
yield return DataTheory(false, 123, Match.Transform<int, string>(value => (string)null!, Match.NotNull<string>()));
yield return DataTheory(true, 123, Match.Transform<int, string>(Transformation, Match.Equal("123")));
yield return DataTheory(false, 123, Match.Transform<int, string>(Transformation, Match.NotEqual("123")));
}

private static string Transformation(int value)
=> value.ToString(CultureInfo.InvariantCulture);
}

private static object[] DataTheory(params object[] values)
=> values;

Expand Down
5 changes: 3 additions & 2 deletions src/Delizious.Toolkit/Delizious.Toolkit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
<Nullable>enable</Nullable>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Company />
<AssemblyVersion>1.0.0</AssemblyVersion>
<FileVersion>1.0.0.1</FileVersion>
<AssemblyVersion>1.1.0</AssemblyVersion>
<FileVersion>1.1.0.2</FileVersion>
<PackageId>Delizious-Toolkit</PackageId>
<Product>Delizious Toolkit</Product>
<PackageTags>.net dotnet csharp delizious match matching filtering immutable immutability object-oriented object-functional</PackageTags>
<Description>An easy to use .NET libary that provides matching of values.</Description>
<Version>1.1.0</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
68 changes: 68 additions & 0 deletions src/Delizious.Toolkit/Match.cs
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,71 @@ public bool Matches(TValue value)
=> this.customMatch.Matches(value);
}

/// <summary>
/// Creates a <see cref="Match{T}"/> instance that transforms a current value into a transformed value first
/// using the given <paramref name="transformation"/>
/// and then matches the transformed value with the given <paramref name="match"/>.
/// </summary>
/// <typeparam name="TCurrent">
/// The type of the current value to match.
/// </typeparam>
/// <typeparam name="TTransformed">
/// The type of the transformed value to match.
/// </typeparam>
/// <param name="transformation">
/// A transformation function that transforms a current value to match into a transformed value to match.
/// This function can return <c>null</c>.
/// </param>
/// <param name="match">
/// The match a transformed value is matched with.
/// </param>
/// <returns>
/// A new <see cref="Match{T}"/> instance that transforms a current value into a transformed value first
/// using the given <paramref name="transformation"/>
/// and then matches the transformed value with the given <paramref name="match"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="transformation"/> is <c>null</c>.</para>
/// <para>- or -</para>
/// <para><paramref name="match"/> is <c>null</c>.</para>
/// </exception>
public static Match<TCurrent> Transform<TCurrent, TTransformed>([NotNull] Func<TCurrent, TTransformed> transformation, [NotNull] Match<TTransformed> match)
{
if (ReferenceEquals(transformation, null!))
{
throw new ArgumentNullException(nameof(transformation));
}

if (ReferenceEquals(match, null!))
{
throw new ArgumentNullException(nameof(match));
}

return Match<TCurrent>.Transform(transformation, match);
}

internal static IMatch<TCurrent> Transform<TCurrent, TTransformed>(Func<TCurrent, TTransformed> transformation, IMatch<TTransformed> match)
=> TransformMatch<TCurrent, TTransformed>.Create(transformation, match);

private sealed class TransformMatch<TCurrent, TTransformed> : IMatch<TCurrent>
{
private readonly Func<TCurrent, TTransformed> transformation;

private readonly IMatch<TTransformed> match;

private TransformMatch(Func<TCurrent, TTransformed> transformation, IMatch<TTransformed> match)
{
this.transformation = transformation;
this.match = match;
}

public static TransformMatch<TCurrent, TTransformed> Create(Func<TCurrent, TTransformed> transformation, IMatch<TTransformed> match)
=> new TransformMatch<TCurrent, TTransformed>(transformation, match);

public bool Matches(TCurrent value)
=> this.match.Matches(this.transformation(value));
}

private sealed class NotMatch<T> : IMatch<T>
{
private readonly IMatch<T> match;
Expand Down Expand Up @@ -1010,6 +1075,9 @@ internal static Match<T> Any(IEnumerable<Match<T>> matches)
internal static Match<T> None(IEnumerable<Match<T>> matches)
=> Create(Match.None(matches.Select(item => item.match).ToArray()));

internal static Match<T> Transform<TTransformed>(Func<T, TTransformed> transformation, Match<TTransformed> match)
=> Create(Match.Transform(transformation, match.match));

/// <summary>
/// Determines whether the specified <paramref name="value"/> matches successfully according to this match.
/// </summary>
Expand Down

0 comments on commit ec0e694

Please sign in to comment.