Skip to content

Commit 6044558

Browse files
committed
2 parents d626878 + c944e05 commit 6044558

File tree

3 files changed

+44
-42
lines changed

3 files changed

+44
-42
lines changed

Gemfile.lock

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ GEM
6060
jekyll (>= 3.5, < 5.0)
6161
jekyll-feed (~> 0.9)
6262
jekyll-seo-tag (~> 2.1)
63-
nokogiri (1.16.7-arm64-darwin)
63+
nokogiri (1.18.9-arm64-darwin)
6464
racc (~> 1.4)
65-
nokogiri (1.16.7-x64-mingw-ucrt)
65+
nokogiri (1.18.9-x64-mingw-ucrt)
6666
racc (~> 1.4)
67-
nokogiri (1.16.7-x86_64-linux)
67+
nokogiri (1.18.9-x86_64-linux-gnu)
6868
racc (~> 1.4)
6969
pathutil (0.16.2)
7070
forwardable-extended (~> 2.6)
@@ -86,7 +86,6 @@ GEM
8686
tzinfo-data (1.2024.1)
8787
tzinfo (>= 1.0.0)
8888
unicode-display_width (2.5.0)
89-
wdm (0.1.1)
9089
webrick (1.8.2)
9190

9291
PLATFORMS
@@ -103,7 +102,6 @@ DEPENDENCIES
103102
minima
104103
nokogiri
105104
tzinfo-data
106-
wdm (~> 0.1.0)
107105
webrick
108106

109107
BUNDLED WITH

_chapters/asteroids.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ Let’s say we want a left- or right-arrow keydown event to start the ship rotat
100100
```
101101
102102
So as promised, this function is setting the `transform` property on the ship, using the position and angle information stored in our local `state` object. We compute the new position by deducting or removing 1 (degree) from the angle (for a left or right rotation respectively) and simultaneously update the state object with the new angle.
103-
Since we specify 10-millisecond delay, the ship will rotate 100 times per second.
103+
Since we specify 10-millisecond delay, the ship will rotate 100 degrees per second.
104104
105105
We’re not done yet. We have to stop the rotation on keyup by calling `clearInterval`, for the specific interval we just created on keydown (using the `handle` we stored). To do this, we’ll use `document.addEventListener` to specify a separate keyup handler for each keydown event, and since we will be creating a new keyup listener for each keydown event, we will also have to cleanup after ourselves or we’ll have a memory (event) leak:
106106

_chapters/functionalreactiveprogramming.md

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Functional Reactive Programming describes an approach to modelling complex, asyn
2020

2121
We will explore FRP through an implementation of the [Observable](#observable-streams) data structure in [the Reactive Extensions for JavaScript (RxJS) library](https://www.learnrxjs.io/). We will then see it applied in application to a straightforward [browser-based user interface problem](#a-user-interface-example).
2222

23-
To support the code examples, the streams are visualised using [rxviz](https://rxviz.com/)
23+
To support the code examples, the streams are visualised using [rxviz](https://rx-viz.vercel.app/).
2424

2525
## Observable Streams
2626

@@ -53,12 +53,13 @@ You could think of our lazy sequences as being “pull-based” data structures,
5353
Just as we have done for various data structures (arrays and so on) in previous chapters, we can define a transform over an Observable to create a new Observable. This transformation may have multiple steps the same way that we chained `filter` and `map` operations over arrays previously. In RxJS’s Observable implementation, however, they’ve gone a little bit more functional, by insisting that such operations are composed (rather than chained) inside a `pipe`. For example, here’s the squares of even numbers in the range [0,10):
5454

5555
```javascript
56-
const isEven = x=>x%2===0,
57-
square = x=>x*x
56+
const isEven = x => x%2 === 0,
57+
square = x => x*x
5858
range(10)
5959
.pipe(
6060
filter(isEven),
61-
map(square))
61+
map(square)
62+
)
6263
.subscribe(console.log)
6364
```
6465

@@ -87,9 +88,10 @@ To solve the first Project Euler problem using RxJS, we generate a sequence of n
8788
```javascript
8889
range(1000)
8990
.pipe(
90-
filter(x=> x%3===0 || x%5===0),
91-
scan((a,v)=>a+v),
92-
last())
91+
filter(x => x%3 === 0 || x%5 === 0),
92+
scan((a,v) => a+v),
93+
last()
94+
)
9395
.subscribe(console.log);
9496
```
9597

@@ -125,8 +127,8 @@ By contrast, the `mergeMap` operator gives the *Cartesian product* of two stream
125127

126128
```javascript
127129
columns.pipe(
128-
mergeMap(column=>rows.pipe(
129-
map(row=>[column, row])
130+
mergeMap(column => rows.pipe(
131+
map(row => [column, row])
130132
))
131133
).subscribe(console.log)
132134
```
@@ -147,8 +149,8 @@ If we contrast `mergeMap` and `map`, `map` will produce an Observable of Observa
147149

148150
```javascript
149151
columns.pipe(
150-
map(column=>rows.pipe(
151-
map(row=>[column, row])
152+
map(column => rows.pipe(
153+
map(row => [column, row])
152154
))
153155
).subscribe(console.log)
154156
```
@@ -191,7 +193,7 @@ The following lets us see in the console the keys pressed as they come in, it wi
191193

192194
```javascript
193195
key$.pipe(
194-
map(e=>e.key)
196+
map(e => e.key)
195197
).subscribe(console.log)
196198
```
197199

@@ -203,7 +205,7 @@ The following prints “!!” on every mousedown:
203205

204206
```javascript
205207
mouse$.pipe(
206-
map(_=>"!!")
208+
map(_ => "!!")
207209
).subscribe(console.log)
208210
```
209211

@@ -216,8 +218,8 @@ Once again this will keep producing the message for every mouse click for as lon
216218
The following achieves the same thing with a single subscription using `merge`:
217219

218220
```javascript
219-
merge(key$.pipe(map(e=>e.key)),
220-
mouse$.pipe(map(_=>"!!"))
221+
merge(key$.pipe(map(e => e.key)),
222+
mouse$.pipe(map(_ => "!!"))
221223
).subscribe(console.log)
222224
```
223225

@@ -266,7 +268,7 @@ Creating new Observable streams from existing streams
266268
merge<T, U...>(t: Observable<T>, u: Observable<U>, ...): Observable<T | U | ...>
267269

268270
// create n-ary tuples (arrays) of the elements at the head of each of the incoming streams
269-
zip<T, U...>(t: Observable<T>, r: Observable<U>):Observable<[T, U, ...]>
271+
zip<T, U...>(t: Observable<T>, r: Observable<U>): Observable<[T, U, ...]>
270272
```
271273
272274
### Observable methods
@@ -348,15 +350,15 @@ Here’s an event-driven code fragment that provides such dragging for some SVG
348350
```typescript
349351
const svg = document.getElementById("svgCanvas")!;
350352
const rect = document.getElementById("draggableRect")!;
351-
rect.addEventListener('mousedown',e => {
353+
rect.addEventListener('mousedown', e => {
352354
const
353355
xOffset = Number(rect.getAttribute('x')) - e.clientX,
354356
yOffset = Number(rect.getAttribute('y')) - e.clientY,
355-
moveListener = (e:MouseEvent)=>{
356-
rect.setAttribute('x',String(e.clientX + xOffset));
357-
rect.setAttribute('y',String(e.clientY + yOffset));
357+
moveListener = (e:MouseEvent) => {
358+
rect.setAttribute('x', String(e.clientX + xOffset));
359+
rect.setAttribute('y', String(e.clientY + yOffset));
358360
},
359-
done = ()=>{
361+
done = () => {
360362
svg.removeEventListener('mousemove', moveListener);
361363
};
362364
svg.addEventListener('mousemove', moveListener);
@@ -402,9 +404,9 @@ We now rewrite precisely the same behaviour using Observable FRP:
402404
x: clientX + mouseDownXOffset, // E
403405
y: clientY + mouseDownYOffset // N
404406
}))))) // C
405-
.subscribe(({x, y}) => { // Y
406-
rect.setAttribute('x', String(x)) // >-----------------------------|
407-
rect.setAttribute('y', String(y)) // >-----------------------------/
407+
.subscribe(({x, y}) => { // Y
408+
rect.setAttribute('x', String(x)) // >-----------------------------|
409+
rect.setAttribute('y', String(y)) // >-----------------------------/
408410
});
409411
```
410412

@@ -427,38 +429,38 @@ the position of the top-left corner of the rectangle, and (optionally, since it
427429

428430
```typescript
429431
type State = Readonly<{
430-
pos:Point,
431-
offset?:Point
432+
pos: Point,
433+
offset?: Point
432434
}>
433435
```
434436
435437
We’ll introduce some types to model the objects coming through the stream and the effects they have when applied to a `State` object in the `scan`. First, all the events we care about have a position on the SVG canvas associated with them, so we’ll have a simple immutable `Point` interface with `x` and `y` positions and a couple of handy vector math methods (note that these create a new `Point` rather than mutating any existing state within the `Point`):
436438
437439
```typescript
438440
class Point {
439-
constructor(public readonly x:number, public readonly y:number){}
440-
add(p:Point) { return new Point(this.x+p.x,this.y+p.y) }
441-
sub(p:Point) { return new Point(this.x-p.x,this.y-p.y) }
441+
constructor(public readonly x: number, public readonly y: number) {}
442+
add(p: Point) { return new Point(this.x + p.x,this.y + p.y) }
443+
sub(p: Point) { return new Point(this.x - p.x,this.y - p.y) }
442444
}
443445
```
444446

445447
Now we create a subclass of `Point` with a constructor letting us instantiate it for a given (DOM) `MouseEvent` and an `abstract` (placeholder) definition for a function to apply the correct update action to the `State`:
446448

447449
```typescript
448450
abstract class MousePosEvent extends Point {
449-
constructor(e:MouseEvent) { super(e.clientX, e.clientY) }
450-
abstract apply(s:State):State;
451+
constructor(e: MouseEvent) { super(e.clientX, e.clientY) }
452+
abstract apply(s: State): State;
451453
}
452454
```
453455

454456
And now two further subclasses with concrete definitions for `apply`.
455457

456458
```typescript
457459
class DownEvent extends MousePosEvent {
458-
apply(s:State) { return { pos: s.pos, offset: s.pos.sub(this) }}
460+
apply(s: State) { return { pos: s.pos, offset: s.pos.sub(this) } }
459461
}
460462
class DragEvent extends MousePosEvent {
461-
apply(s:State) { return { pos: this.add(s.offset), offset: s.offset }}
463+
apply(s: State) { return { pos: this.add(s.offset), offset: s.offset } }
462464
}
463465
```
464466

@@ -478,7 +480,8 @@ But now we’ll capture initial position of the rectangle one time only in an im
478480
const initialState: State = {
479481
pos: new Point(
480482
Number(rect.getAttribute('x')),
481-
Number(rect.getAttribute('y')))
483+
Number(rect.getAttribute('y'))
484+
)
482485
}
483486
```
484487

@@ -491,9 +494,10 @@ mousedown
491494
mergeMap(mouseDownEvent =>
492495
mousemove.pipe(
493496
takeUntil(mouseup),
494-
map(mouseDragEvent=>new DragEvent(mouseDragEvent)),
497+
map(mouseDragEvent => new DragEvent(mouseDragEvent)),
495498
startWith(new DownEvent(mouseDownEvent)))),
496-
scan((s: State, e: MousePosEvent) => e.apply(s),
499+
scan(
500+
(s: State, e: MousePosEvent) => e.apply(s),
497501
initialState))
498502
.subscribe(e => {
499503
rect.setAttribute('x', String(e.rect.x))

0 commit comments

Comments
 (0)