Skip to content

Commit bb9080d

Browse files
committed
Remove the puppeteer-sharp-integration.md pointer, add a pipe() example
RxJS's pipe(op1, op2, ...) is mostly just method chaining, already shown throughout the README - but pipe() has a second job, building a reusable transformation once and applying it to multiple streams. Shows RxSharp's OperatorFunction + Pipe as the equivalent, with a real compiling sample kept in sync via MarkdownSnippets, and explains why there's no hand-written multi-arity Pipe overload set.
1 parent 3a5b9bb commit bb9080d

2 files changed

Lines changed: 49 additions & 5 deletions

File tree

README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,33 @@ Observable.Interval(TimeSpan.FromSeconds(1))
4242
<sup><a href='https://github.com/hardkoded/ReactiveExtensions-Sharp/blob/main/test/RxSharp.Tests/Samples/QuickTasteSample.cs#L19-L27' title='Snippet source file'>snippet source</a> | <a href='#snippet-quick-taste-csharp' title='Start of snippet'>anchor</a></sup>
4343
<!-- endSnippet -->
4444

45+
## What about `pipe`?
46+
47+
RxJS's `pipe(op1, op2, op3)` is mostly just method chaining wearing a different hat — `source.Map(...).Filter(...)`
48+
above *is* the translation. But RxJS's `pipe()` has a second job: called on its own (not as an `Observable`
49+
method), it builds a **reusable** transformation out of several operators, so you can define it once and apply
50+
it to multiple streams. RxSharp covers that with `OperatorFunction<TSource, TResult>` + `Pipe`:
51+
52+
<!-- snippet: pipe-csharp -->
53+
<a id='snippet-pipe-csharp'></a>
54+
```cs
55+
public static void Run(Observable<int> numbersA, Observable<int> numbersB)
56+
{
57+
// A reusable transformation, defined once - the equivalent of RxJS's standalone
58+
// `const squareAndFilterEven = pipe(map(x => x * x), filter(x => x % 2 === 0));`
59+
OperatorFunction<int, int> squareAndFilterEven = source => source.Map(x => x * x).Filter(x => x % 2 == 0);
60+
61+
numbersA.Pipe(squareAndFilterEven).Subscribe(x => Console.WriteLine(x));
62+
numbersB.Pipe(squareAndFilterEven).Subscribe(x => Console.WriteLine(x));
63+
}
64+
```
65+
<sup><a href='https://github.com/hardkoded/ReactiveExtensions-Sharp/blob/main/test/RxSharp.Tests/Samples/PipeSample.cs#L11-L21' title='Snippet source file'>snippet source</a> | <a href='#snippet-pipe-csharp' title='Start of snippet'>anchor</a></sup>
66+
<!-- endSnippet -->
67+
68+
There's no hand-written 9-arity `pipe(op1, op2, ..., op9)` overload set, deliberately — it exists in RxJS mainly
69+
to work around JS not having method chaining with generics the way C# does. `Pipe` here only takes a single,
70+
already-composed `OperatorFunction`; build that function with ordinary chaining, same as everywhere else.
71+
4572
## The example that started this project
4673

4774
[Puppeteer](https://pptr.dev/) (the JS browser-automation library) builds its `Locator.click()`/`.fill()` actions
@@ -68,11 +95,6 @@ public static async Task<string> FindElementOnceItRendersAsync(Func<Task<string>
6895
<sup><a href='https://github.com/hardkoded/ReactiveExtensions-Sharp/blob/main/test/RxSharp.Tests/Samples/RetryUntilTimeoutSample.cs#L13-L21' title='Snippet source file'>snippet source</a> | <a href='#snippet-retry-until-timeout-csharp' title='Start of snippet'>anchor</a></sup>
6996
<!-- endSnippet -->
7097

71-
One line instead of a hand-rolled state machine — same retry-until-success-or-timeout-or-cancel behavior. See
72-
[`handoff/puppeteer-sharp-integration.md`](handoff/puppeteer-sharp-integration.md) for the actual before/after
73-
against puppeteer-sharp's real current `Locator` code, and how the rest of its rxjs-based internals
74-
(`waitForNetworkIdle`, `ScreenRecorder`) map onto RxSharp.
75-
7698
## Install
7799

78100
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using RxSharp.Operators;
2+
3+
namespace RxSharp.Tests.Samples;
4+
5+
/// <summary>
6+
/// Not an NUnit test: a real, compiled source for the README's "pipe" example. Kept in sync with the README via
7+
/// MarkdownSnippets, same as <see cref="QuickTasteSample"/>.
8+
/// </summary>
9+
public static class PipeSample
10+
{
11+
// begin-snippet: pipe-csharp
12+
public static void Run(Observable<int> numbersA, Observable<int> numbersB)
13+
{
14+
// A reusable transformation, defined once - the equivalent of RxJS's standalone
15+
// `const squareAndFilterEven = pipe(map(x => x * x), filter(x => x % 2 === 0));`
16+
OperatorFunction<int, int> squareAndFilterEven = source => source.Map(x => x * x).Filter(x => x % 2 == 0);
17+
18+
numbersA.Pipe(squareAndFilterEven).Subscribe(x => Console.WriteLine(x));
19+
numbersB.Pipe(squareAndFilterEven).Subscribe(x => Console.WriteLine(x));
20+
}
21+
// end-snippet
22+
}

0 commit comments

Comments
 (0)