Skip to content

Commit a09ddf0

Browse files
committed
1.0.1 Option.TryGet, Option.ToString
1 parent 539296f commit a09ddf0

15 files changed

+254
-89
lines changed

.github/workflows/build.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ jobs:
2020
dotnet-version: ${{ matrix.dotnet-version }}
2121

2222
- name: Install dependencies
23-
run: dotnet restore test/Danom.Mvc.Tests
24-
23+
run: dotnet restore
24+
2525
- name: Build Core
2626
run: dotnet build src/Danom -c Release
2727

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
## [1.0.1] - 2024-12-01
6+
7+
### Added
8+
9+
- `Option<T>.TryGet(out T result)` to safely provide the internal value. A return value indicates whether or not the Option was Some(x) or None.
10+
- `Option<T>.ToString(string defaultValue, string? format = null, IFormatProvider? provider = null)` to minimize code required to execute ToString against the inner value safely (i.e., replaces Map -> ToString -> DefaultValue chain).
11+
12+
## [1.0.0] - 2024-11-29
13+
14+
> Hello world!

Danom.sln

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{606C9E49-7696-48B1-A799-B456E680C9F0}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom", "src\Danom\Danom.csproj", "{2E1327A1-9244-49BA-BC31-9CCE3CE2335C}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{624FD20E-2393-4198-8DC9-AB02DCC12338}"
11+
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom.Tests", "test\Danom.Tests\Danom.Tests.csproj", "{C364C599-3120-44EF-9D7C-81EF68072FB7}"
13+
EndProject
14+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom.Validation", "src\Danom.Validation\Danom.Validation.csproj", "{6D32D457-228C-46BA-B94A-9FB4206BE460}"
15+
EndProject
16+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom.Validation.Tests", "test\Danom.Validation.Tests\Danom.Validation.Tests.csproj", "{A30031C7-1B82-4DFF-BEE7-31BE90BAC74A}"
17+
EndProject
18+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom.Mvc", "src\Danom.Mvc\Danom.Mvc.csproj", "{C34292FD-E8B7-4214-9844-A653746C1AFF}"
19+
EndProject
20+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom.Mvc.Tests", "test\Danom.Mvc.Tests\Danom.Mvc.Tests.csproj", "{EF188F59-5C11-4BAA-A965-56C08C370C84}"
21+
EndProject
22+
Global
23+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
24+
Debug|Any CPU = Debug|Any CPU
25+
Release|Any CPU = Release|Any CPU
26+
EndGlobalSection
27+
GlobalSection(SolutionProperties) = preSolution
28+
HideSolutionNode = FALSE
29+
EndGlobalSection
30+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
31+
{2E1327A1-9244-49BA-BC31-9CCE3CE2335C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32+
{2E1327A1-9244-49BA-BC31-9CCE3CE2335C}.Debug|Any CPU.Build.0 = Debug|Any CPU
33+
{2E1327A1-9244-49BA-BC31-9CCE3CE2335C}.Release|Any CPU.ActiveCfg = Release|Any CPU
34+
{2E1327A1-9244-49BA-BC31-9CCE3CE2335C}.Release|Any CPU.Build.0 = Release|Any CPU
35+
{C364C599-3120-44EF-9D7C-81EF68072FB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36+
{C364C599-3120-44EF-9D7C-81EF68072FB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
37+
{C364C599-3120-44EF-9D7C-81EF68072FB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
38+
{C364C599-3120-44EF-9D7C-81EF68072FB7}.Release|Any CPU.Build.0 = Release|Any CPU
39+
{6D32D457-228C-46BA-B94A-9FB4206BE460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40+
{6D32D457-228C-46BA-B94A-9FB4206BE460}.Debug|Any CPU.Build.0 = Debug|Any CPU
41+
{6D32D457-228C-46BA-B94A-9FB4206BE460}.Release|Any CPU.ActiveCfg = Release|Any CPU
42+
{6D32D457-228C-46BA-B94A-9FB4206BE460}.Release|Any CPU.Build.0 = Release|Any CPU
43+
{A30031C7-1B82-4DFF-BEE7-31BE90BAC74A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44+
{A30031C7-1B82-4DFF-BEE7-31BE90BAC74A}.Debug|Any CPU.Build.0 = Debug|Any CPU
45+
{A30031C7-1B82-4DFF-BEE7-31BE90BAC74A}.Release|Any CPU.ActiveCfg = Release|Any CPU
46+
{A30031C7-1B82-4DFF-BEE7-31BE90BAC74A}.Release|Any CPU.Build.0 = Release|Any CPU
47+
{C34292FD-E8B7-4214-9844-A653746C1AFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48+
{C34292FD-E8B7-4214-9844-A653746C1AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
49+
{C34292FD-E8B7-4214-9844-A653746C1AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
50+
{C34292FD-E8B7-4214-9844-A653746C1AFF}.Release|Any CPU.Build.0 = Release|Any CPU
51+
{EF188F59-5C11-4BAA-A965-56C08C370C84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52+
{EF188F59-5C11-4BAA-A965-56C08C370C84}.Debug|Any CPU.Build.0 = Debug|Any CPU
53+
{EF188F59-5C11-4BAA-A965-56C08C370C84}.Release|Any CPU.ActiveCfg = Release|Any CPU
54+
{EF188F59-5C11-4BAA-A965-56C08C370C84}.Release|Any CPU.Build.0 = Release|Any CPU
55+
EndGlobalSection
56+
GlobalSection(NestedProjects) = preSolution
57+
{2E1327A1-9244-49BA-BC31-9CCE3CE2335C} = {606C9E49-7696-48B1-A799-B456E680C9F0}
58+
{C364C599-3120-44EF-9D7C-81EF68072FB7} = {624FD20E-2393-4198-8DC9-AB02DCC12338}
59+
{6D32D457-228C-46BA-B94A-9FB4206BE460} = {606C9E49-7696-48B1-A799-B456E680C9F0}
60+
{A30031C7-1B82-4DFF-BEE7-31BE90BAC74A} = {624FD20E-2393-4198-8DC9-AB02DCC12338}
61+
{C34292FD-E8B7-4214-9844-A653746C1AFF} = {606C9E49-7696-48B1-A799-B456E680C9F0}
62+
{EF188F59-5C11-4BAA-A965-56C08C370C84} = {624FD20E-2393-4198-8DC9-AB02DCC12338}
63+
EndGlobalSection
64+
EndGlobal

src/Danom/Danom.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<AssemblyName>Danom</AssemblyName>
5-
<Version>1.0.0</Version>
5+
<Version>1.0.1</Version>
66

77
<!-- General info -->
88
<Description>Monadic structures to simplify functional programming patterns in C#.</Description>

src/Danom/Option/Option.cs

+42-3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,22 @@ public Option<T> OrElseWith(
115115
Func<Option<T>> ifNoneWith) =>
116116
Match(Option<T>.Some, ifNoneWith);
117117

118+
/// <summary>
119+
/// Safely retrieve the value using procedural code.
120+
/// </summary>
121+
/// <param name="result"></param>
122+
/// <returns></returns>
123+
public bool TryGet(out T result)
124+
{
125+
var success = true;
126+
result = DefaultWith(() =>
127+
{
128+
success = false;
129+
// we return this only to satisfy the compiler
130+
return default!;
131+
});
132+
return success;
133+
}
118134

119135
/// <summary>
120136
/// Creates a new <see cref="Option{T}"/> with the specified value.
@@ -214,6 +230,28 @@ public override string ToString() =>
214230
Match(
215231
some: x => $"Some({x})",
216232
none: () => "None");
233+
234+
/// <summary>
235+
/// Returns the string representation of the <see cref="Option{T}"/> or the
236+
/// provided default value.
237+
///
238+
/// If format string and/or provider are provided, they are passed into
239+
/// the objects `ToString` method.
240+
/// </summary>
241+
/// <param name="defaultValue"></param>
242+
/// <param name="format"></param>
243+
/// <param name="provider"></param>
244+
/// <returns></returns>
245+
public string ToString(
246+
string defaultValue,
247+
string? format = null,
248+
IFormatProvider? provider = null) =>
249+
Match(
250+
some: x =>
251+
x is IFormattable f ?
252+
f!.ToString(format, provider) :
253+
x!.ToString(),
254+
none: () => defaultValue) ?? string.Empty;
217255
}
218256

219257
/// <summary>
@@ -222,7 +260,8 @@ public override string ToString() =>
222260
public static class Option
223261
{
224262
/// <summary>
225-
/// Creates a new <see cref="Option{T}"/> with the specified value.
263+
/// Creates a new <see cref="Option{T}"/> with the specified value, with its
264+
/// type provided via method invocation. Enables `Option.Some(1)` syntax.
226265
/// </summary>
227266
/// <param name="value"></param>
228267
/// <returns></returns>
@@ -235,13 +274,13 @@ public static Option<T> Some<T>(T value) =>
235274
/// <param name="value"></param>
236275
/// <returns></returns>
237276
public static Task<Option<T>> SomeAsync<T>(T value) =>
238-
Task.FromResult(Some(value));
277+
Task.FromResult(Option<T>.Some(value));
239278

240279
/// <summary>
241280
/// Creates a new <see cref="Option{T}"/> with the value of the awaited Task.
242281
/// </summary>
243282
/// <param name="value"></param>
244283
/// <returns></returns>
245284
public static async Task<Option<T>> SomeAsync<T>(Task<T> value) =>
246-
Some(await value);
285+
Option<T>.Some(await value);
247286
}

test/Danom.Mvc.Tests/ModelStateDictionaryExtensionsTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal static void AddResultErrors(
2323
public sealed class ModelStateDictionaryExtensionsTests
2424
{
2525
[Fact]
26-
public void AddResultErrorsShouldWork()
26+
public void AddResultErrors()
2727
{
2828
var modelState = new ModelStateDictionary();
2929
var errors = new ResultErrors("Key1", "Error1");

test/Danom.Tests/Option/OptionNullableTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Danom.Tests;
66
public sealed class OptionNullableExtensionsTests
77
{
88
[Fact]
9-
public void ConversionsShouldWork()
9+
public void Conversions()
1010
{
1111
char? nullableChar = null;
1212
bool? nullableBool = null;

test/Danom.Tests/Option/OptionTaskTests.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Danom.Tests;
66
public sealed class OptionAsyncTests
77
{
88
[Fact]
9-
public async Task MatchShouldWork()
9+
public async Task Match()
1010
{
1111
var optionSome = await Option<int>.SomeAsync(1).MatchAsync(x => x, () => -1);
1212
Assert.Equal(1, optionSome);
@@ -16,7 +16,7 @@ public async Task MatchShouldWork()
1616
}
1717

1818
[Fact]
19-
public async Task BindShouldWork()
19+
public async Task Bind()
2020
{
2121
AssertOption.IsSome(2, await Option<int>.SomeAsync(1).BindAsync(x => Option<int>.Some(x + 1)));
2222
AssertOption.IsSome(2, await Option<int>.SomeAsync(1).BindAsync(x => Option<int>.SomeAsync(x + 1)));
@@ -25,7 +25,7 @@ public async Task BindShouldWork()
2525
}
2626

2727
[Fact]
28-
public async Task MapShouldWork()
28+
public async Task Map()
2929
{
3030
AssertOption.IsSome(2, await Option<int>.SomeAsync(1).MapAsync(x => x + 1));
3131
AssertOption.IsSome(2, await Option<int>.SomeAsync(1).MapAsync(x => Task.FromResult(x + 1)));
@@ -34,7 +34,7 @@ public async Task MapShouldWork()
3434
}
3535

3636
[Fact]
37-
public async Task DefaultValueShouldWork()
37+
public async Task DefaultValue()
3838
{
3939
Assert.Equal(1, await Option<int>.NoneAsync().DefaultValueAsync(1));
4040
Assert.Equal(1, await Option<int>.NoneAsync().DefaultValueAsync(Task.FromResult(1)));
@@ -43,7 +43,7 @@ public async Task DefaultValueShouldWork()
4343
}
4444

4545
[Fact]
46-
public async Task DefaultWithShouldWork()
46+
public async Task DefaultWith()
4747
{
4848
Assert.Equal(1, await Option<int>.NoneAsync().DefaultWithAsync(() => 1));
4949
Assert.Equal(1, await Option<int>.NoneAsync().DefaultWithAsync(() => Task.FromResult(1)));
@@ -52,7 +52,7 @@ public async Task DefaultWithShouldWork()
5252
}
5353

5454
[Fact]
55-
public async Task OrElseShouldWork()
55+
public async Task OrElse()
5656
{
5757
AssertOption.IsSome(1, await Option<int>.NoneAsync().OrElseAsync(Option<int>.Some(1)));
5858
AssertOption.IsSome(1, await Option<int>.NoneAsync().OrElseAsync(Option<int>.SomeAsync(1)));
@@ -61,7 +61,7 @@ public async Task OrElseShouldWork()
6161
}
6262

6363
[Fact]
64-
public async Task OrElseWithShouldWork()
64+
public async Task OrElseWith()
6565
{
6666
AssertOption.IsSome(1, await Option<int>.NoneAsync().OrElseWithAsync(() => Option<int>.Some(1)));
6767
AssertOption.IsSome(1, await Option<int>.NoneAsync().OrElseWithAsync(() => Option<int>.SomeAsync(1)));

0 commit comments

Comments
 (0)