From ea38efb238081c4596567785391201ae07d55989 Mon Sep 17 00:00:00 2001 From: David Retzlaff Date: Fri, 31 Jan 2025 09:17:39 +0100 Subject: [PATCH] Add or else methods to option closes #31 --- Source/FunicularSwitch/Option.cs | 37 +++++++++++++++++-- .../Tests/FunicularSwitch.Test/OptionSpecs.cs | 17 +++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Source/FunicularSwitch/Option.cs b/Source/FunicularSwitch/Option.cs index 3773294..9a42308 100644 --- a/Source/FunicularSwitch/Option.cs +++ b/Source/FunicularSwitch/Option.cs @@ -59,6 +59,11 @@ public Task> Map(Func> map) => Match( public Option Bind(Func> map) => Match(map, Option.None); public Task> Bind(Func>> bind) => Match(bind, () => Option.None); + + public Option OrElse(Option other) => _isSome ? this : other; + public Option OrElse(Func> other) => _isSome ? this : other(); + public Task> OrElse(Task> other) => OrElse(() => other); + public async Task> OrElse(Func>> other) => _isSome ? this : await other().ConfigureAwait(false); public void Match(Action some, Action? none = null) { @@ -90,6 +95,8 @@ public async Task Match(Func> some, Func Match(Func> some, Func none) { @@ -202,15 +209,39 @@ public static async Task> Bind(this Task> bind, var result = await bind.ConfigureAwait(false); return await result.Bind(convert).ConfigureAwait(false); } + + public static async Task> OrElse(this Task> option, Option other) + { + var result = await option.ConfigureAwait(false); + return result.OrElse(other); + } + + public static async Task> OrElse(this Task> option, Func> other) + { + var result = await option.ConfigureAwait(false); + return result.OrElse(other); + } + + public static async Task> OrElse(this Task> option, Task> other) + { + var result = await option.ConfigureAwait(false); + return await result.OrElse(other).ConfigureAwait(false); + } + + public static async Task> OrElse(this Task> option, Func>> other) + { + var result = await option.ConfigureAwait(false); + return await result.OrElse(other).ConfigureAwait(false); + } public static IEnumerable Choose(this IEnumerable items, Func> choose) => - items.SelectMany(i => choose(i)); + items.SelectMany(i => choose(i)); public static Option ToOption(this Result result) => result.ToOption(logError: null); public static Option ToOption(this Result result, Action? logError) => result.Match( - ok => Option.Some(ok), + Option.Some, error => { logError?.Invoke(error); @@ -218,7 +249,7 @@ public static Option ToOption(this Result result, Action? logEr }); public static Result ToResult(this Option option, Func errorIfNone) => - option.Match(s => Result.Ok(s), () => Result.Error(errorIfNone())); + option.Match(Result.Ok, () => Result.Error(errorIfNone())); public static Option NoneIfEmpty(this string? text) => text.ToOption(x => !string.IsNullOrEmpty(x)); diff --git a/Source/Tests/FunicularSwitch.Test/OptionSpecs.cs b/Source/Tests/FunicularSwitch.Test/OptionSpecs.cs index e752569..ea16c0d 100644 --- a/Source/Tests/FunicularSwitch.Test/OptionSpecs.cs +++ b/Source/Tests/FunicularSwitch.Test/OptionSpecs.cs @@ -828,6 +828,23 @@ public void NoneIfEmpty_Text_Some() string? target = "Hi"; var result = target.NoneIfEmpty(); result.Should().BeSome().Which.Should().Be("Hi"); + } + + [TestMethod] + public async Task OrElse() + { + var none = None(); + none.OrElse(Option.None).Should().BeNone(); + ShouldBeSome42(none.OrElse(42)); + + var some = Some(42); + ShouldBeSome42(some.OrElse(Option.None)); + ShouldBeSome42(some.OrElse(2)); + + ShouldBeSome42(await none.OrElse(() => Task.FromResult(Some(42)))); + return; + + void ShouldBeSome42(Option option) => option.Should().BeSome().Which.Should().Be(42); } class MyClass;