Skip to content

Commit 4949349

Browse files
authored
Merge pull request #20 from astar-development/features/extend-docs
Extend documentation and run cleanup
2 parents 33d0867 + 82649ab commit 4949349

File tree

14 files changed

+349
-169
lines changed

14 files changed

+349
-169
lines changed

.github/workflows/dotnet.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
shell: powershell
5252
run: |
5353
dotnet tool install --global dotnet-coverage
54-
.\.sonar\scanner\dotnet-sonarscanner begin /k:"astar-development_astar-dev-functional-extensions" /o:"astar-development" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
54+
.\.sonar\scanner\dotnet-sonarscanner begin /k:"astar-development_astar-dev-functional-extensions" /o:"astar-development" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.scanner.scanAll=false
5555
dotnet build
5656
dotnet-coverage collect 'dotnet test --filter "FullyQualifiedName!~Tests.EndToEnd"' -f xml -o 'coverage.xml'
5757
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"

samples/AStar.Dev.ConsoleSample/AStar.Dev.ConsoleSample.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<ProjectReference Include="..\..\src\AStar.Dev.Functional.Extensions\AStar.Dev.Functional.Extensions.csproj" />
12+
<ProjectReference Include="..\..\src\AStar.Dev.Functional.Extensions\AStar.Dev.Functional.Extensions.csproj"/>
1313
</ItemGroup>
1414

1515
</Project>

samples/AStar.Dev.SampleApi/AStar.Dev.SampleApi.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</ItemGroup>
1313

1414
<ItemGroup>
15-
<ProjectReference Include="..\..\src\AStar.Dev.Functional.Extensions\AStar.Dev.Functional.Extensions.csproj" />
15+
<ProjectReference Include="..\..\src\AStar.Dev.Functional.Extensions\AStar.Dev.Functional.Extensions.csproj"/>
1616
</ItemGroup>
1717

1818
</Project>

samples/AStar.Dev.SampleBlazor/AStar.Dev.SampleBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<ProjectReference Include="..\..\src\AStar.Dev.Functional.Extensions\AStar.Dev.Functional.Extensions.csproj" />
11+
<ProjectReference Include="..\..\src\AStar.Dev.Functional.Extensions\AStar.Dev.Functional.Extensions.csproj"/>
1212
</ItemGroup>
1313

1414
</Project>

src/AStar.Dev.Functional.Extensions/AStar.Dev.Functional.Extensions.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<IncludeSymbols>true</IncludeSymbols>
1010
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
1111
<PackageId>AStar.Dev.Functional.Extensions</PackageId>
12-
<Version>0.2.1-alpha</Version>
12+
<Version>0.2.2-alpha</Version>
1313
<PackageReadmeFile>Readme.md</PackageReadmeFile>
1414
<Authors>Jason</Authors>
1515
<Company>AStar Development</Company>
@@ -25,6 +25,7 @@
2525
<IsPackable>true</IsPackable>
2626
<Title>AStar.Dev.Functional.Extensions</Title>
2727
<Copyright>AStar Development 2025</Copyright>
28+
<PackageReleaseNotes>No changes in this version, just extending the documentation</PackageReleaseNotes>
2829
</PropertyGroup>
2930

3031
<ItemGroup>
@@ -33,6 +34,8 @@
3334

3435
<ItemGroup>
3536
<None Include="Readme.md" Pack="true" PackagePath="\"/>
37+
<None Include="Readme-result.md" Pack="true" PackagePath="\"/>
38+
<None Include="Readme-option.md" Pack="true" PackagePath="\"/>
3639
</ItemGroup>
3740

3841
</Project>

src/AStar.Dev.Functional.Extensions/Option{T}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public Some(T value)
8181
public sealed class None : Option<T>
8282
{
8383
/// <summary>
84-
/// A helper method to create an instance of <see cref="None"/>
84+
/// A helper method to create an instance of <see cref="None" />
8585
/// </summary>
8686
public static readonly None Instance = new ();
8787

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# 🎯 Option<T> Functional Cheat Sheet
2+
3+
## 🧩 Option Overview
4+
5+
Represents a value that might exist (`Some`) or not (`None`), avoiding nulls and enabling functional composition.
6+
7+
```csharp
8+
Option<int> maybeNumber = Option.Some(42);
9+
Option<string> emptyName = Option.None<string>();
10+
```
11+
12+
---
13+
14+
## 🏗 Construction
15+
16+
| Syntax | Description |
17+
|-----------------------------|-----------------------------------------|
18+
| `Option.Some(value)` | Wraps a non-null value as `Some` |
19+
| `Option.None<T>()` | Creates a `None` of type `T` |
20+
| `value.ToOption()` | Converts value or default to Option |
21+
| `value.ToOption(predicate)` | Converts only if predicate returns true |
22+
| `nullable.ToOption()` | Converts nullable struct to Option |
23+
24+
---
25+
26+
## 🧪 Pattern Matching
27+
28+
```csharp
29+
option.Match(
30+
some => $"Value: {some}",
31+
() => "No value"
32+
);
33+
```
34+
35+
Or via deconstruction:
36+
37+
```csharp
38+
var (isSome, value) = option;
39+
```
40+
41+
Or with TryGet:
42+
43+
```csharp
44+
if (option.TryGetValue(out var value)) { /* use value */ }
45+
```
46+
47+
---
48+
49+
## 🔧 Transformation
50+
51+
| Method | Description |
52+
|---------------------|---------------------------------------------|
53+
| `Map(func)` | Transforms value inside Some |
54+
| `Bind(func)` | Chains function that returns another Option |
55+
| `ToResult(errorFn)` | Converts Option to `Result<T, TError>` |
56+
| `ToNullable()` | Converts to nullable (structs only) |
57+
| `ToEnumerable()` | Converts to `IEnumerable<T>` |
58+
59+
---
60+
61+
## 🪄 LINQ Support
62+
63+
```csharp
64+
var result =
65+
from name in Option.Some("Jason")
66+
from greeting in Option.Some($"Hello, {name}")
67+
select greeting;
68+
```
69+
70+
Via `Select`, `SelectMany`, or `SelectAwait` (async LINQ)
71+
72+
---
73+
74+
## 🔁 Async Support
75+
76+
| Method | Description |
77+
|------------------------------|-----------------------------------------------|
78+
| `MapAsync(func)` | Awaits and maps value |
79+
| `BindAsync(func)` | Awaits and chains async Option-returning func |
80+
| `MatchAsync(onSome, onNone)` | Async pattern match |
81+
| `SelectAwait(func)` | LINQ-friendly async projection |
82+
83+
---
84+
85+
## 🧯 Fallbacks and Conversions
86+
87+
```csharp
88+
option.OrElse("fallback"); // returns value or fallback
89+
option.OrThrow(); // throws if None
90+
option.IsSome(); // true if Some
91+
option.IsNone(); // true if None
92+
```
93+
94+
---
95+
96+
## 🐛 Debugging & Output
97+
98+
```csharp
99+
option.ToString(); // Outputs "Some(value)" or "None"
100+
```
101+
102+
---
103+
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# 🧭 Result<T, TError> Cheat Sheet
2+
3+
## 🧱 Core Concept
4+
5+
Result<T, TError> encapsulates either:
6+
7+
✅ Ok(T) — a success value
8+
9+
❌ Error(TError) — an error reason
10+
11+
```csharp
12+
Result<string, string> nameResult = new Result<string, string>.Ok("Jason");
13+
Result<int, string> errorResult = new Result<int, string>.Error("Invalid input");
14+
```
15+
16+
## 🏗 Construction Helpers
17+
18+
| Expression | Outcome |
19+
|--------------------------------|-----------------------------|
20+
| new Result<T, E>.Ok(value) | Constructs a success result |
21+
| new Result<T, E>.Error(reason) | Constructs an error result |
22+
23+
## 🔧 Transformation
24+
25+
| Method | Description |
26+
|-------------|--------------------------------------------------|
27+
| Map(fn) | Transforms the success value |
28+
| Bind(fn) | Chains to another result-returning function |
29+
| Tap(action) | Invokes side effect on success, returns original |
30+
31+
```csharp
32+
result.Map(value => value.ToUpper());
33+
result.Bind(value => Validate(value));
34+
result.Tap(Console.WriteLine);
35+
```
36+
37+
## 🧪 Pattern Matching
38+
39+
```csharp
40+
result.Match(
41+
onSuccess: value => $"✅ {value}",
42+
onError: reason => $"❌ {reason}"
43+
);
44+
```
45+
46+
## 🧞 LINQ Composition
47+
48+
```csharp
49+
var final =
50+
from input in GetInput()
51+
from valid in Validate(input)
52+
select $"Welcome, {valid}";
53+
```
54+
55+
## LINQ Methods
56+
57+
| Method | Description |
58+
|----------------------|---------------------------------------------|
59+
| Select(fn) | Maps over success value |
60+
| SelectMany(fn) | Binds to next result |
61+
| SelectMany(..., ...) | Binds and projects from intermediate result |
62+
63+
## ⚡ Async Support
64+
65+
```csharp
66+
var asyncResult = await resultTask.MapAsync(val => val.Length);
67+
var finalValue = await resultTask.MatchAsync(...);
68+
```
69+
70+
## Async LINQ
71+
72+
```csharp
73+
var result =
74+
await GetAsync()
75+
.SelectMany(asyncValue => ValidateAsync(asyncValue), (a, b) => $"{a}-{b}");
76+
```
77+
78+
## 🧯 Error Handling
79+
80+
```csharp
81+
if (result is Result<T, TError>.Error err)
82+
Log(err.Reason);
83+
```
84+
85+
Or selectively tap into errors:
86+
87+
```csharp
88+
public static Result<T, TError> TapError<T, TError>(
89+
this Result<T, TError> result,
90+
Action<TError> handler)
91+
{
92+
if (result is Result<T, TError>.Error error)
93+
handler(error.Reason);
94+
return result;
95+
}
96+
```
Lines changed: 16 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,29 @@
1-
# 🎯 Option<T> Functional Cheat Sheet
1+
# AStar Dev Functional Extensions
22

3-
## 🧩 Option Overview
3+
## Overview
44

5-
Represents a value that might exist (`Some`) or not (`None`), avoiding nulls and enabling functional composition.
5+
This project contains a bunch of classes and extension methods to facilitate a more functional approach to handling errors and optional objects.
66

7-
```csharp
8-
Option<int> maybeNumber = Option.Some(42);
9-
Option<string> emptyName = Option.None<string>();
10-
```
7+
## Cheat Sheets
118

12-
---
9+
### Result&lt;T&gt; and associated extensions
1310

14-
## 🏗 Construction
11+
Cheat sheet is [here](Readme-result.md)
1512

16-
| Syntax | Description |
17-
|-----------------------------|-----------------------------------------|
18-
| `Option.Some(value)` | Wraps a non-null value as `Some` |
19-
| `Option.None<T>()` | Creates a `None` of type `T` |
20-
| `value.ToOption()` | Converts value or default to Option |
21-
| `value.ToOption(predicate)` | Converts only if predicate returns true |
22-
| `nullable.ToOption()` | Converts nullable struct to Option |
13+
### Option&lt;T&gt; and associated extensions
2314

24-
---
15+
Cheat sheet is [here](Readme-option.md)
2516

26-
## 🧪 Pattern Matching
17+
## Build and analysis
2718

28-
```csharp
29-
option.Match(
30-
some => $"Value: {some}",
31-
() => "No value"
32-
);
33-
```
19+
### GitHub build
3420

35-
Or via deconstruction:
21+
[![SonarQube](https://github.com/astar-development/astar-dev-functional-extensions/actions/workflows/dotnet.yml/badge.svg)](https://github.com/astar-development/astar-dev-functional-extensions/actions/workflows/dotnet.yml)
3622

37-
```csharp
38-
var (isSome, value) = option;
39-
```
23+
### SonarQube details
4024

41-
Or with TryGet:
42-
43-
```csharp
44-
if (option.TryGetValue(out var value)) { /* use value */ }
45-
```
46-
47-
---
48-
49-
## 🔧 Transformation
50-
51-
| Method | Description |
52-
|---------------------|---------------------------------------------|
53-
| `Map(func)` | Transforms value inside Some |
54-
| `Bind(func)` | Chains function that returns another Option |
55-
| `ToResult(errorFn)` | Converts Option to `Result<T, TError>` |
56-
| `ToNullable()` | Converts to nullable (structs only) |
57-
| `ToEnumerable()` | Converts to `IEnumerable<T>` |
58-
59-
---
60-
61-
## 🪄 LINQ Support
62-
63-
```csharp
64-
var result =
65-
from name in Option.Some("Jason")
66-
from greeting in Option.Some($"Hello, {name}")
67-
select greeting;
68-
```
69-
70-
Via `Select`, `SelectMany`, or `SelectAwait` (async LINQ)
71-
72-
---
73-
74-
## 🔁 Async Support
75-
76-
| Method | Description |
77-
|------------------------------|-----------------------------------------------|
78-
| `MapAsync(func)` | Awaits and maps value |
79-
| `BindAsync(func)` | Awaits and chains async Option-returning func |
80-
| `MatchAsync(onSome, onNone)` | Async pattern match |
81-
| `SelectAwait(func)` | LINQ-friendly async projection |
82-
83-
---
84-
85-
## 🧯 Fallbacks and Conversions
86-
87-
```csharp
88-
option.OrElse("fallback"); // returns value or fallback
89-
option.OrThrow(); // throws if None
90-
option.IsSome(); // true if Some
91-
option.IsNone(); // true if None
92-
```
93-
94-
---
95-
96-
## 🐛 Debugging & Output
97-
98-
```csharp
99-
option.ToString(); // Outputs "Some(value)" or "None"
100-
```
101-
102-
---
25+
| | | | | |
26+
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
27+
| [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=bugs)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=coverage)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) |
28+
| [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) | [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=astar-development_astar-dev-functional-extensions&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=astar-development_astar-dev-functional-extensions) |
10329

0 commit comments

Comments
 (0)