Skip to content

Commit 346d35c

Browse files
Updates to GitHub ReadMe documentation, and created a smaller ReadMe for Nuget packages
1 parent c021da4 commit 346d35c

File tree

5 files changed

+216
-12
lines changed

5 files changed

+216
-12
lines changed

README.md

Lines changed: 190 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
# Hyperbee.Pipeline
22

3-
Classes for building composable async pipelines supporting:
3+
The `Hyperbee.Pipeline` library is a sophisticated tool for constructing asynchronous fluent pipelines in .NET. A pipeline, in this context, refers to a sequence of data processing elements arranged in series, where the output of one element serves as the input for the subsequent element.
44

5-
* Value projections
6-
* Early returns
7-
* Child pipelines
8-
* [Middleware](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/middleware.md)
9-
* [Conditional flow](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/execution.md)
10-
* [Dependency Injection](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/dependencyInjection.md)
5+
A distinguishing feature of the `Hyperbee.Pipeline` library, setting it apart from other pipeline implementations, is its inherent support for **middleware** and **dependency injection**. Middleware introduces a higher degree of flexibility and control over the data flow, enabling developers to manipulate data as it traverses through the pipeline. This can be leveraged to implement a variety of functionalities such as eventing, caching, logging, and more, thereby enhancing the customizability of the code.
116

12-
## Usage
7+
Furthermore, the support for dependency injection facilitates efficient management of dependencies within the pipeline. This leads to code that is more maintainable and testable, thereby improving the overall quality of the software.
8+
9+
## Example
1310

1411
```csharp
1512
// Takes a string and returns a number
@@ -28,6 +25,190 @@ Assert.AreEqual(42, answer1);
2825
var answer2 = await question(new PipelineContext(), "Smith");
2926
Assert.AreEqual(0, answer2);
3027
```
28+
## Middleware
29+
30+
Hyperbee pipelines come with the ability to enhance processing with custom middleware. The `PipelineFactory` library provides functionality that allows you to manipulate the data as it passes through the pipeline. This is done using the `Hook` and `Wrap` methods.
31+
32+
### Hook
33+
34+
The `Hook` and `HookAsync` methods allow you to add a hook that is called for every statement in the pipeline. This hook takes the current context, the current argument, and a delegate to the next part of the pipeline. It can manipulate the argument before and after calling the next part of the pipeline.
35+
36+
Here's an example of how to use `HookAsync`:
37+
38+
```csharp
39+
var command = PipelineFactory
40+
.Start<string>()
41+
.HookAsync( async ( ctx, arg, next ) => await next( ctx, arg + "{" ) + "}" )
42+
.Pipe( ( ctx, arg ) => arg + "1" )
43+
.Pipe( ( ctx, arg ) => arg + "2" )
44+
.Build();
45+
46+
var result = await command( new PipelineContext() );
47+
48+
Assert.AreEqual( "{1}{2}", result );
49+
```
50+
51+
### Wrap
52+
53+
The `Wrap` and `WrapAsync` method allows you to wrap a part of the pipeline. This is useful when you want to apply a transformation to only a part of the pipeline.
54+
55+
Here’s an example of how to use `WrapAsync`:
56+
57+
```csharp
58+
var command = PipelineFactory
59+
.Start<string>()
60+
.Pipe( ( ctx, arg ) => arg + "1" )
61+
.Pipe( ( ctx, arg ) => arg + "2" )
62+
.WrapAsync( async ( ctx, arg, next ) => await next( ctx, arg + "{" ) + "}" )
63+
.Pipe( ( ctx, arg ) => arg + "3" )
64+
.Build();
65+
66+
var result = await command( new PipelineContext() );
67+
68+
Assert.AreEqual( "{12}3", result );
69+
70+
```
71+
72+
## Dependency Injection
73+
74+
Sometimes Pipelines and Pipeline middleware need access to specific container services. This can be
75+
accomplished by registering services with the `PipelineContextFactory`. This can be done through
76+
DI configuration, or manually through the `PipelineContextFactoryProvider` if you are not using DI.
77+
78+
Pipelines manage dependencies with a specialized container. This allows the implementor to control
79+
the services that are exposed through the pipeline. If you want to expose all application
80+
services then you can call `AddPipeline` and pass `includeAllServices: true`.
81+
82+
Register pipelines with DI and provide Pipeline dependencies using the application container.
83+
84+
```csharp
85+
services.AddPipeline( includeAllServices: true );
86+
```
87+
88+
Register Pipelines with DI and provide Pipeline dependencies using a specialized container.
89+
90+
```csharp
91+
services.AddPipeline( (factoryServices, rootProvider) =>
92+
{
93+
factoryServices.AddTransient<IThing>()
94+
factoryServices.ProxyService<IPrincipalProvider>( rootProvider ); // pull from root container
95+
} );
96+
```
97+
98+
## Advanced Features
99+
100+
The `PipelineFactory` library provides a variety of helper methods that allow you to customize the behavior of your pipelines. These methods provide powerful functionality for manipulating data as it passes through the pipeline.
101+
102+
### Reduce
103+
104+
The `Reduce` and `ReduceAsync` methods allow you to reduce a sequence of elements to a single value. You can specify a reducer function that defines how the elements should be combined, and a builder function that creates the pipeline for processing the elements.
105+
106+
### WaitAll
107+
108+
The `WaitAll` method allows you to wait for all pipelines to complete before continuing. You can specify a set of builders that create the pipelines to wait for, a reducer function that combines the results of the pipelines.
109+
110+
```csharp
111+
var count = 0;
112+
113+
var command = PipelineFactory
114+
.Start<int>()
115+
.WaitAll( builders => builders.Create(
116+
builder => builder.Pipe( ( ctx, arg ) => Interlocked.Increment( ref count ) ),
117+
builder => builder.Pipe( ( ctx, arg ) => Interlocked.Increment( ref count ) )
118+
),
119+
reducer: ( ctx, arg, results ) => { return arg + results.Sum( x => (int) x.Result ); }
120+
)
121+
.Build();
122+
123+
var result = await command( new PipelineContext() );
124+
125+
Assert.AreEqual( 2, count );
126+
Assert.AreEqual( 3, result );
127+
```
128+
129+
### PipeIf
130+
131+
The `PipeIf` method allows you to conditionally add a step to the pipeline. You can specify a condition function that determines whether the step should be added, a builder function that creates the step, and an optional flag indicating whether middleware should be inherited.
132+
133+
### ForEach and ForEachAsync
134+
135+
The `ForEach` and `ForEachAsync` methods allow you to apply a pipeline to each element in a sequence. You can specify a builder function that creates the pipeline for processing the elements.
136+
137+
```csharp
138+
var count = 0;
139+
140+
var command = PipelineFactory
141+
.Start<string>()
142+
.Pipe( ( ctx, arg ) => arg.Split( ' ' ) )
143+
.ForEach<string>( builder => builder
144+
.Pipe( ( ctx, arg ) => count += 10 )
145+
)
146+
.Pipe( ( ctx, arg ) => count += 5 )
147+
.Build();
148+
149+
await command( new PipelineContext(), "e f" );
150+
151+
Assert.AreEqual( count, 25 );
152+
```
153+
154+
### Call and CallAsync
155+
156+
The `Call` and `CallAsync` methods allow you to add a procedure to the pipeline. You can think of these as `Action<T>` and `Pipe` like `Func<T>`.
157+
158+
In this example notice that `arg + 9` is not returned from the use of `Call`
159+
160+
```csharp
161+
var callResult = string.Empty;
162+
163+
var command = PipelineFactory
164+
.Start<string>()
165+
.Pipe( ( ctx, arg ) => arg + "1" )
166+
.Pipe( ( ctx, arg ) => arg + "2" )
167+
.Call( builder => builder
168+
.Call( ( ctx, arg ) => callResult = arg + "3" )
169+
.Pipe( ( ctx, arg ) => arg + "9" )
170+
)
171+
.Pipe( ( ctx, arg ) => arg + "4" )
172+
.Build();
173+
174+
var result = await command( new PipelineContext() );
175+
176+
Assert.AreEqual( "124", result );
177+
Assert.AreEqual( "123", callResult );
178+
```
179+
180+
### Chaining Child Pipelines
181+
182+
The `PipelineFactory` library allows you to chain pipelines together. Since pipelines are just functions, they can be used as input to other pipelines. This allows you to create complex data processing flows by reusing and chaining together multiple pipelines.
183+
184+
Here's an example of how to chain pipelines together:
185+
186+
```csharp
187+
var command2 = PipelineFactory
188+
.Start<string>()
189+
.Pipe( ( ctx, arg ) => $"{arg} again!" )
190+
.Build();
191+
192+
var command1 = PipelineFactory
193+
.Start<string>()
194+
.Pipe( ( ctx, arg ) => $"hello {arg}" )
195+
.PipeAsync( command2 )
196+
.Build();
197+
198+
var result = await command1( new PipelineContext(), "pipeline" );
199+
200+
Assert.AreEqual( "hello pipeline again!", result );
201+
```
202+
203+
## Additional Documentation
204+
Classes for building composable async pipelines supporting:
205+
206+
* [Middleware](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/middleware.md)
207+
* [Conditional flow](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/execution.md)
208+
* [Dependency Injection](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/dependencyInjection.md)
209+
* Value projections
210+
* Early returns
211+
* Child pipelines
31212

32213
# Status
33214

@@ -37,7 +218,5 @@ Assert.AreEqual(0, answer2);
37218
| `main` | [![Build status](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/actions/workflows/publish.yml/badge.svg)](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/actions/workflows/publish.yml) |
38219

39220

40-
[![Hyperbee.Pipeline](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/assets/hyperbee.jpg?raw=true)](https://github.com/Stillpoint-Software/Hyperbee.Pipeline)
41-
42221
# Help
43-
See [Todo](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/todo.md)
222+
See our list of items [Todo](https://github.com/Stillpoint-Software/Hyperbee.Pipeline/blob/main/docs/todo.md)

src/Hyperbee.Pipeline/Hyperbee.Pipeline.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<Pack>True</Pack>
3030
<PackagePath>\</PackagePath>
3131
</None>
32-
<None Include="..\..\README.md">
32+
<None Include="README.md">
3333
<Pack>True</Pack>
3434
<PackagePath>\</PackagePath>
3535
</None>

src/Hyperbee.Pipeline/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Hyperbee.Pipeline
2+
3+
The `Hyperbee.Pipeline` library is a sophisticated tool for constructing asynchronous fluent pipelines in .NET. A pipeline, in this context, refers to a sequence of data processing elements arranged in series, where the output of one element serves as the input for the subsequent element.
4+
5+
A distinguishing feature of the `Hyperbee.Pipeline` library, setting it apart from other pipeline implementations, is its inherent support for **middleware** and **dependency injection**. Middleware introduces a higher degree of flexibility and control over the data flow, enabling developers to manipulate data as it traverses through the pipeline. This can be leveraged to implement a variety of functionalities such as eventing, caching, logging, and more, thereby enhancing the customizability of the code.
6+
7+
Furthermore, the support for dependency injection facilitates efficient management of dependencies within the pipeline. This leads to code that is more maintainable and testable, thereby improving the overall quality of the software.
8+
9+
```csharp
10+
// Takes a string and returns a number
11+
var question = PipelineFactory
12+
.Start<string>()
13+
.PipeIf((ctx, arg) => arg == "Adams", builder => builder
14+
.Pipe((ctx, arg) => 42)
15+
.Cancel()
16+
)
17+
.Pipe((ctx, arg) => 0)
18+
.Build();
19+
20+
var answer1 = await question(new PipelineContext(), "Adams");
21+
Assert.AreEqual(42, answer1);
22+
23+
var answer2 = await question(new PipelineContext(), "Smith");
24+
Assert.AreEqual(0, answer2);
25+
```

src/Hyperbee.Project/hyperbee.project.txt

Whitespace-only changes.

test/Hyperbee.Project.Tests/hyperbee.project.test.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)