Skip to content

Commit 8953c0a

Browse files
Added support for output-only pipelines
1 parent 39ba63f commit 8953c0a

13 files changed

Lines changed: 386 additions & 11 deletions

FluentPipelines/IPipelineStartBuilder.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@
22

33
namespace FluentPipelines
44
{
5+
/// <summary>
6+
/// Defines methods for a builder that constructs the beginning of pipelines with no input data.
7+
/// </summary>
8+
public interface IPipelineStartBuilder
9+
{
10+
/// <summary>
11+
/// Defines the starting step of the pipeline.
12+
/// </summary>
13+
/// <typeparam name="TNext">
14+
/// The type of data returned from the step.
15+
/// This will be passed onto the next step (or returned as the output of the pipeline, if no more steps are added).
16+
/// </typeparam>
17+
/// <param name="action">A function acting as the first step of the pipeline.</param>
18+
/// <returns>A builder that allows you to continue building the rest of the pipeline.</returns>
19+
IOutPipelineBuilder<TNext> Start<TNext>(OutPipelineStepDelegate<TNext> action);
20+
21+
/// <summary>
22+
/// Defines the starting step of the pipeline.
23+
/// </summary>
24+
/// <typeparam name="TNext">
25+
/// The type of data returned from the step.
26+
/// This will be passed onto the next step (or returned as the output of the pipeline, if no more steps are added).
27+
/// </typeparam>
28+
/// <param name="step">The first step of the pipeline.</param>
29+
/// <returns>A builder that allows you to continue building the rest of the pipeline.</returns>
30+
IOutPipelineBuilder<TNext> Start<TNext>(IOutPipelineStep<TNext> step);
31+
}
32+
533
/// <summary>
634
/// Defines methods for a builder that constructs the beginning of pipelines taking input data.
735
/// </summary>

FluentPipelines/Pipelines/InputOutputPipeline.cs renamed to FluentPipelines/InputOutput/InOutPipeline.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@
22
using System.Collections.Generic;
33
using System.Linq;
44

5-
namespace FluentPipelines.Pipelines
5+
namespace FluentPipelines
66
{
77
/// <summary>
88
/// A pipeline that takes <typeparamref name="TInput"/> as input, and returns <typeparamref name="TOutput"/>.
99
/// </summary>
1010
/// <typeparam name="TInput">The type of data used as input to the pipeline.</typeparam>
1111
/// <typeparam name="TOutput">The type of data returned from the pipeline.</typeparam>
12-
public sealed class InputOutputPipeline<TInput, TOutput> : IPipeline<TInput, TOutput>
12+
public sealed class InOutPipeline<TInput, TOutput> : IPipeline<TInput, TOutput>
1313
{
1414
private readonly PipelineStep[] steps;
1515

1616
/// <summary>
17-
/// Initializes a new instance of the <see cref="InputOutputPipeline{TInput, TOutput}"/> class.
17+
/// Initializes a new instance of the <see cref="InOutPipeline{TInput, TOutput}"/> class.
1818
/// </summary>
1919
/// <param name="steps">
2020
/// The steps to be executed as part of the pipeline.
2121
/// It is important that the first step takes <typeparamref name="TInput"/> as input,
2222
/// and that the final step returns <typeparamref name="TOutput"/>.
2323
/// </param>
24-
public InputOutputPipeline(IEnumerable<PipelineStep> steps)
24+
public InOutPipeline(IEnumerable<PipelineStep> steps)
2525
{
2626
if(steps is null)
2727
throw new ArgumentNullException(nameof(steps));
@@ -40,20 +40,20 @@ public TOutput Run(TInput input)
4040
}
4141

4242
/// <summary>
43-
/// A static class containing helper methods for <see cref="InputOutputPipeline{TInput, TOutput}"/>.
43+
/// A static class containing helper methods for <see cref="InOutPipeline{TInput, TOutput}"/>.
4444
/// </summary>
4545
public static class InputOutputPipeline
4646
{
4747
/// <summary>
48-
/// Creates an <see cref="InputOutputPipeline{TInput, TOutput}"/> from a <see cref="PipelineBuilder{TInput, TOutput}"/>.
48+
/// Creates an <see cref="InOutPipeline{TInput, TOutput}"/> from a <see cref="PipelineBuilder{TInput, TOutput}"/>.
4949
/// </summary>
5050
/// <typeparam name="TInput">The type of data used as input to the pipeline.</typeparam>
5151
/// <typeparam name="TOutput">The type of data returned from the pipeline.</typeparam>
5252
/// <param name="builder">The builder containing the steps to be executed as part of the pipeline.</param>
5353
/// <returns>The resulting pipeline.</returns>
54-
public static InputOutputPipeline<TInput, TOutput> CreateFrom<TInput, TOutput>(PipelineBuilder<TInput, TOutput> builder)
54+
public static InOutPipeline<TInput, TOutput> CreateFrom<TInput, TOutput>(PipelineBuilder<TInput, TOutput> builder)
5555
{
56-
return new InputOutputPipeline<TInput, TOutput>(builder.Steps);
56+
return new InOutPipeline<TInput, TOutput>(builder.Steps);
5757
}
5858
}
5959
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace FluentPipelines
4+
{
5+
/// <summary>
6+
/// Defines methods for a pipeline that takes no input, and returns <typeparamref name="TOutput"/>.
7+
/// </summary>
8+
/// <typeparam name="TOutput">The type of data returned from the pipeline.</typeparam>
9+
public interface IOutPipeline<TOutput>
10+
{
11+
/// <summary>
12+
/// Runs the pipeline.
13+
/// </summary>
14+
/// <returns>The result of the pipeline.</returns>
15+
TOutput Run();
16+
}
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
3+
namespace FluentPipelines
4+
{
5+
/// <summary>
6+
/// Defines methods for a builder that constructs pipelines with output data and no input data.
7+
/// </summary>
8+
/// <typeparam name="TOutput">The type of data returned as the output of the pipeline.</typeparam>
9+
public interface IOutPipelineBuilder<TOutput>
10+
{
11+
/// <summary>
12+
/// Compiles all steps and builds a runnable pipeline.
13+
/// </summary>
14+
/// <returns>The resulting pipeline.</returns>
15+
IOutPipeline<TOutput> Build();
16+
17+
/// <summary>
18+
/// Defines the next step of the pipeline.
19+
/// </summary>
20+
/// <typeparam name="TNext">
21+
/// The type of data returned from the step.
22+
/// This will be passed onto the next step (or returned as the output of the pipeline, if no more steps are added).
23+
/// </typeparam>
24+
/// <param name="action">A function acting as the next step of the pipeline, processing the data from the previous step.</param>
25+
/// <returns>A builder that allows you to continue building the rest of the pipeline.</returns>
26+
IOutPipelineBuilder<TNext> Then<TNext>(PipelineStepDelegate<TOutput, TNext> action);
27+
28+
/// <summary>
29+
/// Defines the next step of the pipeline.
30+
/// </summary>
31+
/// <typeparam name="TNext">
32+
/// The type of data returned from the step.
33+
/// This will be passed onto the next step (or returned as the output of the pipeline, if no more steps are added).
34+
/// </typeparam>
35+
/// <param name="step">The next step of the pipeline, processing the data from the previous step.</param>
36+
/// <returns>A builder that allows you to continue building the rest of the pipeline.</returns>
37+
IOutPipelineBuilder<TNext> Then<TNext>(IPipelineStep<TOutput, TNext> step);
38+
}
39+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace FluentPipelines
4+
{
5+
/// <summary>
6+
/// Defines methods for a pipeline step with an output and no input.
7+
/// </summary>
8+
/// <typeparam name="TOutput">The type of data returned from the step.</typeparam>
9+
public interface IOutPipelineStep<TOutput>
10+
{
11+
/// <summary>
12+
/// Executes the step.
13+
/// </summary>
14+
/// <returns>The resulting output data from the step.</returns>
15+
TOutput Run();
16+
}
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
3+
namespace FluentPipelines
4+
{
5+
/// <summary>
6+
/// A pipeline step that executes a delegate method.
7+
/// </summary>
8+
/// <typeparam name="TOutput">The type of data returned from the step.</typeparam>
9+
public class OutFunctionStep<TOutput> : IOutPipelineStep<TOutput>
10+
{
11+
private readonly OutPipelineStepDelegate<TOutput> function;
12+
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="OutFunctionStep{TOutput}"/> class.
15+
/// </summary>
16+
/// <param name="function">The delegate method to execute.</param>
17+
public OutFunctionStep(OutPipelineStepDelegate<TOutput> function)
18+
{
19+
this.function = function ?? throw new ArgumentNullException(nameof(function));
20+
}
21+
22+
/// <inheritdoc/>
23+
public TOutput Run()
24+
{
25+
return function();
26+
}
27+
}
28+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace FluentPipelines
6+
{
7+
/// <summary>
8+
/// A pipeline that takes no input, and returns <typeparamref name="TOutput"/>.
9+
/// </summary>
10+
/// <typeparam name="TOutput">The type of data returned from the pipeline.</typeparam>
11+
public sealed class OutPipeline<TOutput> : IOutPipeline<TOutput>
12+
{
13+
private readonly OutPipelineStep firstStep;
14+
private readonly PipelineStep[] steps;
15+
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="OutPipeline{TOutput}"/> class.
18+
/// </summary>
19+
/// <param name="firstStep">
20+
/// The first step to execute.
21+
/// <para><b>IMPORTANT:</b> If this is the only step in the pipeline, it must return <typeparamref name="TOutput"/>.</para>
22+
/// </param>
23+
/// <param name="steps">
24+
/// The rest of the steps to be executed as part of the pipeline.
25+
/// It is important that the final step returns <typeparamref name="TOutput"/>.
26+
/// </param>
27+
public OutPipeline(OutPipelineStep firstStep, IEnumerable<PipelineStep> steps)
28+
{
29+
this.firstStep = firstStep ?? throw new ArgumentNullException(nameof(firstStep));
30+
this.steps = steps?.ToArray() ?? Array.Empty<PipelineStep>();
31+
}
32+
33+
/// <inheritdoc/>
34+
public TOutput Run()
35+
{
36+
var output = firstStep.Run();
37+
38+
if(steps.Length == 0)
39+
return (TOutput)output;
40+
41+
return (TOutput)steps.Execute(output);
42+
}
43+
}
44+
45+
/// <summary>
46+
/// A static class containing helper methods for <see cref="OutPipeline{TOutput}"/>.
47+
/// </summary>
48+
public static class OutputPipeline
49+
{
50+
/// <summary>
51+
/// Creates an <see cref="OutPipeline{TOutput}"/> from a <see cref="OutPipelineBuilder{TOutput}"/>.
52+
/// </summary>
53+
/// <typeparam name="TOutput">The type of data returned from the pipeline.</typeparam>
54+
/// <param name="builder">The builder containing the steps to be executed as part of the pipeline.</param>
55+
/// <returns>The resulting pipeline.</returns>
56+
public static OutPipeline<TOutput> CreateFrom<TOutput>(OutPipelineBuilder<TOutput> builder)
57+
{
58+
return new OutPipeline<TOutput>(builder.FirstStep, builder.Steps);
59+
}
60+
}
61+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace FluentPipelines
5+
{
6+
/// <summary>
7+
/// A builder that builds a pipeline with output data and no input data.
8+
/// </summary>
9+
/// <typeparam name="TOutput">The type of data returned from the pipeline.</typeparam>
10+
public class OutPipelineBuilder<TOutput> : IOutPipelineBuilder<TOutput>
11+
{
12+
/// <summary>
13+
/// Gets the first step of the pipeline.
14+
/// </summary>
15+
protected internal OutPipelineStep FirstStep { get; }
16+
17+
/// <summary>
18+
/// Gets the collection of steps added to the builder, which will be used to construct the pipeline.
19+
/// </summary>
20+
protected internal List<PipelineStep> Steps { get; }
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="OutPipelineBuilder{TOutput}"/> class.
24+
/// </summary>
25+
/// <param name="firstStep">
26+
/// The first step of the pipeline.
27+
/// <para><b>IMPORTANT:</b> If this is the only step, it must return <typeparamref name="TOutput"/>, otherwise the built-in pipeline types will not work.</para>
28+
/// </param>
29+
/// <param name="steps">
30+
/// The collection of steps to add to the builder, which will be used to construct the pipeline.
31+
/// <para><b>IMPORTANT:</b> The the last step must return <typeparamref name="TOutput"/>, otherwise the built-in pipeline types will not work.</para>
32+
/// <para><b>IMPORTANT:</b> <paramref name="steps"/> is taken by reference! The list is NOT copied!</para>
33+
/// </param>
34+
protected OutPipelineBuilder(OutPipelineStep firstStep, List<PipelineStep> steps)
35+
{
36+
FirstStep = firstStep ?? throw new ArgumentNullException(nameof(firstStep));
37+
Steps = steps ?? throw new ArgumentNullException(nameof(steps));
38+
}
39+
40+
/// <summary>
41+
/// Initializes a new instance of the <see cref="OutPipelineBuilder{TOutput}"/> class.
42+
/// </summary>
43+
/// <param name="firstStep">The first step of the pipeline, processing the input data.</param>
44+
public OutPipelineBuilder(IOutPipelineStep<TOutput> firstStep)
45+
{
46+
if(firstStep is null)
47+
throw new ArgumentNullException(nameof(firstStep));
48+
49+
FirstStep = new OutPipelineStep<TOutput>(firstStep);
50+
Steps = new List<PipelineStep>();
51+
}
52+
53+
/// <inheritdoc/>
54+
public virtual IOutPipeline<TOutput> Build()
55+
{
56+
return new OutPipeline<TOutput>(FirstStep, Steps);
57+
}
58+
59+
/// <inheritdoc/>
60+
public virtual IOutPipelineBuilder<TNext> Then<TNext>(PipelineStepDelegate<TOutput, TNext> action)
61+
{
62+
if(action is null)
63+
throw new ArgumentNullException(nameof(action));
64+
65+
return Then(new FunctionStep<TOutput, TNext>(action));
66+
}
67+
68+
/// <inheritdoc/>
69+
public virtual IOutPipelineBuilder<TNext> Then<TNext>(IPipelineStep<TOutput, TNext> step)
70+
{
71+
if(step is null)
72+
throw new ArgumentNullException(nameof(step));
73+
74+
Steps.Add(new PipelineStep<TOutput, TNext>(step));
75+
76+
return new OutPipelineBuilder<TNext>(FirstStep, Steps);
77+
}
78+
}
79+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
3+
namespace FluentPipelines
4+
{
5+
/// <summary>
6+
/// A pipeline step with an output and no input.
7+
/// </summary>
8+
/// <typeparam name="TOutput">The type of data returned from the step.</typeparam>
9+
public sealed class OutPipelineStep<TOutput> : OutPipelineStep
10+
{
11+
private readonly IOutPipelineStep<TOutput> step;
12+
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="OutPipelineStep{TOutput}"/> class.
15+
/// </summary>
16+
/// <param name="step">The base step to create this generic step from.</param>
17+
public OutPipelineStep(IOutPipelineStep<TOutput> step)
18+
{
19+
this.step = step ?? throw new ArgumentNullException(nameof(step));
20+
}
21+
22+
internal override object Run()
23+
{
24+
return step.Run();
25+
}
26+
}
27+
28+
/// <summary>
29+
/// The base class for generic, typeless pipeline steps. Also contains helper methods to create strongly typed generic steps.
30+
/// </summary>
31+
public class OutPipelineStep
32+
{
33+
/// <summary>
34+
/// Creates a <see cref="OutPipelineStep{TOutput}"/>.
35+
/// </summary>
36+
/// <typeparam name="TOutput">The type of data returned from the step.</typeparam>
37+
/// <param name="step">The base step to create the generic step from.</param>
38+
/// <returns>A generic pipeline step.</returns>
39+
public static OutPipelineStep<TOutput> Create<TOutput>(IOutPipelineStep<TOutput> step)
40+
{
41+
return new OutPipelineStep<TOutput>(step);
42+
}
43+
44+
internal OutPipelineStep()
45+
{
46+
}
47+
48+
internal virtual object Run()
49+
{
50+
throw new NotImplementedException();
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)