Skip to content

Commit 0dfd59f

Browse files
committed
Initial commit
0 parents  commit 0dfd59f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+5645
-0
lines changed

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
root = true
2+
3+
[]
4+
end_of_line = crlf
5+
insert_final_newline = true
6+
7+
[*.xml]
8+
indent_style = space
9+
indent_size = 4
10+
11+
[*.{json,yml}]
12+
indent_style = space
13+
indent_size = 2

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.DS_Store
2+
.vscode/
3+
.vs
4+
tools/
5+
[Oo]bj/
6+
[Bb]in/
7+
.nuget/
8+
_ReSharper.*
9+
packages/
10+
artifacts/
11+
*.user
12+
*.suo
13+
*.userprefs
14+
*DS_Store
15+
*.sln.ide

.paket/Paket.Restore.targets

Lines changed: 557 additions & 0 deletions
Large diffs are not rendered by default.

Directory.Build.props

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project>
2+
<PropertyGroup>
3+
<SolutionDirectory Condition="'$(SolutionDirectory)'==''">$(MSBuildThisFileDirectory)</SolutionDirectory>
4+
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
5+
</PropertyGroup>
6+
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
7+
<DefineConstants>$(DefineConstants);NETFRAMEWORK</DefineConstants>
8+
</PropertyGroup>
9+
<!-- Enable building .NET Framework projects on any machine with at least MSBuild or the .NET Core SDK installed.-->
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0">
12+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
13+
<PrivateAssets>all</PrivateAssets>
14+
</PackageReference>
15+
</ItemGroup>
16+
</Project>

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2015 - 2021 Giacomo Stelluti Scala
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
2+
# SharpX
3+
4+
![alt text](/assets/icon.png "SharpX Logo")
5+
6+
SharpX is derived from [CSharpx](https://github.com/gsscoder/csharpx) 2.8.0-rc.2 (_which was practically a stable_) and [RailwaySharp](https://github.com/gsscoder/railwaysharp) 1.2.2. While both projects were meant mainly for source inclusion, SharpX is designed to be pulled from [NuGet](https://www.nuget.org/).
7+
8+
The library contains functional types and other utilities, following _don't reinvent the wheel_ philosophy. This project was inspired by [Real-World Functional Programming](https://www.amazon.com/Real-World-Functional-Programming-Tomas-Petricek/dp/1933988924/ref=sr_1_1?keywords=Real-World+Functional+Programming&qid=1580118924&s=books&sr=1-1) and includes code from [MoreLINQ](https://github.com/morelinq/MoreLINQ).
9+
10+
## Compatibility
11+
12+
SharpX is almost fully compatible with projects using previous libraries. CSharpx changed symbols are listed below.
13+
14+
- `StringExtensions::StripMl` renamed as `StripML`.
15+
- `ResultType` renamed as `OutcomeType`.
16+
- `Result` renamed as `Outcome`.
17+
18+
## Targets
19+
20+
- .NET Standard 2.0
21+
- .NET Core 3.1
22+
- .NET 5.0
23+
24+
## Install via NuGet
25+
26+
If you prefer, you can install it via NuGet:
27+
28+
```sh
29+
$ dotnet add package SharpX --version 1.0.0
30+
Determining projects to restore...
31+
...
32+
```
33+
34+
## Versions
35+
36+
- In `develop` branch source code may differ also from latest preview.
37+
- The letest version on NuGet is [1.0.0](https://www.nuget.org/packages/SharpX/1.0.0).
38+
- The latest stable version on NuGet is [1.0.0](https://www.nuget.org/packages/SharpX/1.0.0).
39+
40+
## [Maybe]
41+
42+
- Encapsulates an optional value that can contain a value or being empty.
43+
- Similar to F# `'T option` / Haskell `data Maybe a = Just a | Nothing` type.
44+
45+
```csharp
46+
var greet = true;
47+
var value = greet ? "world".ToMaybe() : Maybe.Nothing<string>();
48+
value.Match(
49+
who => Console.WriteLine($"hello {who}!"),
50+
() => Environment.Exit(1));
51+
```
52+
53+
- Supports LINQ syntax:
54+
55+
```csharp
56+
var result1 = Maybe.Just(30);
57+
var result2 = Maybe.Just(10);
58+
var result3 = Maybe.Just(2);
59+
60+
var sum = from r1 in result1
61+
from r2 in result2
62+
where r1 > 0
63+
select r1 - r2 into temp
64+
from r3 in result3
65+
select temp * r3;
66+
67+
var value = sum.FromJust(); // outcome: 40
68+
```
69+
70+
## Either
71+
72+
- Represents a value that can contain either a value or an error.
73+
- Similar to Haskell `data Either a b = Left a | Right b` type.
74+
- Similar also to F# `Choice<'T, 'U>`.
75+
- Like in Haskell the convention is to let `Right` case hold the value and `Left` keep track of error or similar data.
76+
- If you want a more complete implementation of this kind of types, consider using `Result`.
77+
78+
## Result
79+
80+
This type was originally present in RailwaySharp. Check the test project to see a more complete usage example.
81+
82+
``` csharp
83+
public static Result<Request, string> ValidateInput(Request input)
84+
{
85+
if (input.Name == string.Empty) {
86+
return Result<Request, string>.FailWith("Name must not be blank");
87+
}
88+
if (input.EMail == string.Empty) {
89+
return Result<Request, string>.FailWith("Email must not be blank");
90+
}
91+
return Result<Request, string>.Succeed(input);
92+
}
93+
94+
var request = new Request { Name = "Giacomo", EMail = "[email protected]" };
95+
var result = Validation.ValidateInput(request);
96+
result.Match(
97+
(x, msgs) => { Logic.SendMail(x.EMail); },
98+
msgs => { Logic.HandleFailure(msgs) });
99+
```
100+
101+
## Outcome
102+
103+
- Represents a value that can be a success or a failure in form of a type that can contains a custom error message and optionally an exception.
104+
105+
```csharp
106+
Outcome ValidateArtifact(Artifact artifact)
107+
{
108+
try {
109+
artifact = ArtifactManager.Load(artifact.Path);
110+
}
111+
catch (IOException e) {
112+
return Result.Failure($"Unable to load artifcat {path}:\n{e.Message}", exception: e);
113+
}
114+
return artifact.CheckIntegrity() switch {
115+
Integrity.Healthy => Outcome.Success(),
116+
_ => Outcome.Failure("Artifact integrity is compromised")
117+
};
118+
}
119+
120+
if (ValidateArtifact(artifact).MatchFailure(out Error error)) {
121+
//Error::ToString creates a string with message and exception details
122+
_logger.LogError(error.Exception.FromJust(), error.ToString());
123+
Environment.Exit(1);
124+
}
125+
// do something useful with artifact
126+
```
127+
128+
## Unit
129+
130+
- `Unit` is similar to `void` but, since it's a *real* type. `void` is not, in fact you can't declare a variable of that type. `Unit` allows the use functions without a result in a computation (*functional style*). It's essentially **F#** `unit` and **Haskell** `Unit`.
131+
132+
```csharp
133+
// prints each word and returns 0 to the shell
134+
static int Main(string[] args)
135+
{
136+
var sentence = "this is a sentence";
137+
return (from _ in
138+
from word in sentence.Split()
139+
select Unit.Do(() => Console.WriteLine(word))
140+
select 0).Distinct().Single();
141+
}
142+
```
143+
144+
## CryptoRandom
145+
146+
A thread safe random number generator based on [this code](https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom) compatible with `System.Random` interface.
147+
148+
```csharp
149+
Random random = new CryptoRandom();
150+
151+
var int = randome.Next(9); // outcome: 3
152+
```
153+
154+
## FSharpResultExtensions
155+
156+
- Convenient extension methods to consume `FSharpResult<T, TError>` in simple and functional for other **.NET** languages.
157+
158+
```csharp
159+
// pattern match like
160+
var result = Query.GetStockQuote("ORCL");
161+
result.Match(
162+
quote => Console.WriteLine($"Price: {quote.Price}"),
163+
error => Console.WriteLine($"Trouble: {error}"));
164+
// mapping
165+
var result = Query.GetIndex(".DJI");
166+
result.Map(
167+
quote => CurrencyConverter.Change(quote.Price, "$", ""));
168+
```
169+
170+
- Blog [post](https://gsscoder.github.io/consuming-fsharp-results-in-c/) about it.
171+
172+
## StringExtensions
173+
174+
- General purpose and randomness string manipulation extensions.
175+
176+
```csharp
177+
Console.WriteLine(
178+
"\t[hello\world@\t".Sanitize(normalizeWhiteSpace: true));
179+
// outcome: ' hello world '
180+
181+
Console.WriteLine(
182+
"I want to change a word".ApplyAt(4, word => word.Mangle()));
183+
// outcome like: 'I want to change &a word'
184+
```
185+
186+
## EnumerableExtensions
187+
188+
- Most useful extension methods from [MoreLINQ](https://github.com/morelinq/MoreLINQ).
189+
- Some of these reimplemnted (e.g. `Choose` using `Maybe`):
190+
- **LINQ** `...OrDefault` implemented with `Maybe` type as return value.
191+
192+
```csharp
193+
var numbers = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
194+
var evens = numbers.Choose(x => x % 2 == 0
195+
? Maybe.Just(x)
196+
: Maybe.Nothing<int>());
197+
// outcome: {0, 2, 4, 6, 8}
198+
```
199+
200+
- With other useful methods too:
201+
202+
```CSharp
203+
var sequence = new int[] {0, 1, 2, 3, 4}.Intersperse(5);
204+
// outcome: {0, 5, 1, 5, 2, 5, 3, 5, 4}
205+
var element = sequence.Choice();
206+
// will choose a random element
207+
var sequence = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }.ChunkBySize(3);
208+
// outcome: { [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10] }
209+
var maybeFirst = new int[] {0, 1, 2}.FirstOrNothing(x => x == 1)
210+
// outcome: Just(1)
211+
```
212+
213+
## Icon
214+
215+
[Tool](https://thenounproject.com/search/?q=tool&i=3902696) icon designed by Cattaleeya Thongsriphong from [The Noun Project](https://thenounproject.com/)

SharpX.sln

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.31729.503
5+
MinimumVisualStudioVersion = 15.0.26124.0
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpX", "src\SharpX\SharpX.csproj", "{2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpX.Specs", "tests\SharpX.Specs\SharpX.Specs.csproj", "{BBDB5904-5A75-49E7-A57E-EB92E32A7527}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{434B6A60-0D64-4958-991F-17DBC9DC0F18}"
11+
EndProject
12+
Global
13+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
14+
Debug|Any CPU = Debug|Any CPU
15+
Release|Any CPU = Release|Any CPU
16+
EndGlobalSection
17+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
18+
{2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19+
{2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
20+
{2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
21+
{2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|Any CPU.Build.0 = Release|Any CPU
22+
{BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23+
{BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|Any CPU.Build.0 = Debug|Any CPU
24+
{BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|Any CPU.ActiveCfg = Release|Any CPU
25+
{BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|Any CPU.Build.0 = Release|Any CPU
26+
EndGlobalSection
27+
GlobalSection(SolutionProperties) = preSolution
28+
HideSolutionNode = FALSE
29+
EndGlobalSection
30+
GlobalSection(ExtensibilityGlobals) = postSolution
31+
SolutionGuid = {A02DD375-4885-4373-B792-B2541B428719}
32+
SolutionGuid = {9EDE47D4-D8AA-406C-A4FC-DE8735C3B386}
33+
EndGlobalSection
34+
EndGlobal

assets/icon.png

7.84 KB
Loading

paket.dependencies

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
group main
2+
source https://www.nuget.org/api/v2
3+
framework: netstandard20, netcoreapp31, net50
4+
nuget FSharp.Core 4.7.0
5+
6+
group specs
7+
source https://www.nuget.org/api/v2
8+
framework: net50
9+
nuget Microsoft.NET.Test.Sdk 16.9.4
10+
nuget coverlet.collector 1.0.1
11+
nuget xunit 2.4.1
12+
nuget xunit.runner.visualstudio 2.4.3
13+
nuget FsCheck 3.0.0-alpha4 prerelease
14+
nuget FsCheck.Xunit 3.0.0-alpha4 prerelease
15+
nuget FluentAssertions 6.2.0
16+
nuget Bogus 33.1.1
17+
nuget WaffleGenerator 4.2.1
18+
nuget WaffleGenerator.Bogus 4.2.1

0 commit comments

Comments
 (0)