Skip to content

Commit

Permalink
Remove sampleWith and holdWith functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh Bassett committed Dec 28, 2017
1 parent 0f6dd57 commit 0d01c71
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 49 deletions.
57 changes: 19 additions & 38 deletions src/signal.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {always, apply, compose, empty, equal, get, head, id, pair, tail} from 'fkit'
import {always, apply, compose, empty, equal, get, head, pair, tail} from 'fkit'
import Subscription from './subscription'

/**
Expand Down Expand Up @@ -537,36 +537,25 @@ export default class Signal {
}

/**
* Emits the most recent value when there is an event on the sampler signal
* `s`.
* Emits the most recent value from the given signal `s` whenever there is an
* event on the sampler signal.
*
* @param s A signal.
* @returns A new signal.
*/
sample (s) {
return this.sampleWith(id, s)
}

/**
* Generalises the `sample` function to sample the most recent value when
* there is an event on the sampler signal `s`. The most recent value, and the
* sampler value are combined using the binary function `f`.
*
* @param f A binary function.
* @param s A signal.
* @returns A new signal.
*/
sampleWith (f, s) {
let lastValue

return new Signal(emit => {
// Buffer the value.
const next = a => { lastValue = a }
const next = () => {
// Emit the buffered value.
if (lastValue !== undefined) { emit.next(lastValue) }
}

const subscription1 = this.subscribe({...emit, next})

// Emit the buffered value.
const subscription2 = s.subscribe(a => emit.next(f(lastValue, a)), emit.error)
// Store the last value.
const subscription2 = s.subscribe(a => { lastValue = a }, emit.error, emit.complete)

// Unsubscribe the sampler.
return () => {
Expand All @@ -577,34 +566,26 @@ export default class Signal {
}

/**
* Pauses emitting values when the most recent value on the sampler signal `s`
* is truthy. It will resume emitting events after there is a falsey value.
* Pauses emitting values from the given signal `s` if the most recent value
* from the sampler signal is truthy. It will resume emitting events after
* there is a falsey value.
*
* @param s A signal.
* @returns A new signal.
*/
hold (s) {
return this.holdWith(id, s)
}

/**
* Generalises the `hold` function to pause emitting values when the predicate
* function `f` is true for the most recent sampler signal value.
*
* @param p A predicate function.
* @param s A signal.
* @returns A new signal.
*/
holdWith (p, s) {
let lastValue

return new Signal(emit => {
const next = a => { if (!lastValue) { emit.next(a) } }
const next = a => {
// Emit the value if the gate is open.
if (!lastValue) { emit.next(a) }
}

const subscription1 = this.subscribe({...emit, next})
const subscription1 = s.subscribe({...emit, next})

// Store the hold value.
const subscription2 = s.subscribe(a => { lastValue = p(a) }, emit.error)
// Store the last value.
const subscription2 = this.subscribe(a => { lastValue = a }, emit.error, emit.complete)

// Unsubscribe the sampler.
return () => {
Expand Down
56 changes: 45 additions & 11 deletions test/signal_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,8 @@ describe('Signal', () => {

describe('#sample', () => {
it('emits the most recent value when there is an event on the sampler signal', () => {
const s = Signal.sequentially(500, range(1, 6))
const t = Signal.periodic(1000).always(1)
const s = Signal.periodic(1000)
const t = Signal.sequentially(500, range(1, 6))

s.sample(t).subscribe(nextSpy, errorSpy, completeSpy)

Expand All @@ -613,29 +613,52 @@ describe('Signal', () => {

assert.strictEqual(nextSpy.callCount, 3);

[2, 4, 6].forEach((ns, index) => {
[1, 3, 5].forEach((ns, index) => {
const call = nextSpy.getCall(index)
assert.isTrue(call.calledWithExactly(ns))
}, this)

assert.isTrue(completeSpy.calledAfter(nextSpy))
})

it('emits an error if either signal emits an error', () => {
let a, b
const s = Signal.fromCallback(callback => {
a = e => { callback(e) }
})
const t = Signal.fromCallback(callback => {
b = e => { callback(e) }
})

s.sample(t).subscribe({error: errorSpy})

a('foo')
b('foo')

assert.isTrue(errorSpy.calledTwice)
})
})

describe('#sampleWith', () => {
describe('#hold', () => {
it('emits the most recent value when there is an event on the sampler signal', () => {
const s = Signal.sequentially(500, range(1, 6))
const t = Signal.periodic(1000).always(1)
let a
const s = Signal.fromCallback(callback => {
a = a => { callback(null, a) }
})
const t = Signal.sequentially(500, range(1, 6))

s.sampleWith(add, t).subscribe(nextSpy, errorSpy, completeSpy)
s.hold(t).subscribe(nextSpy, errorSpy, completeSpy)

a(false)
clock.tick(1000)
a(true)
clock.tick(1000)
a(false)
clock.tick(1000)

assert.strictEqual(nextSpy.callCount, 3);
assert.strictEqual(nextSpy.callCount, 4);

[3, 5, 7].forEach((ns, index) => {
[1, 2, 5, 6].forEach((ns, index) => {
const call = nextSpy.getCall(index)
assert.isTrue(call.calledWithExactly(ns))
}, this)
Expand All @@ -652,19 +675,30 @@ describe('Signal', () => {
b = e => { callback(e) }
})

s.sampleWith(always(), t).subscribe({error: errorSpy})
s.hold(t).subscribe({error: errorSpy})

a('foo')
b('foo')

assert.isTrue(errorSpy.calledTwice)
})

it('unmounts the original signal when it is unsubscribed', () => {
const unmount = sinon.spy()
const s = new Signal(() => unmount)
const t = Signal.never()
const a = s.hold(t).subscribe(always())

a.unsubscribe()

assert.isTrue(unmount.calledOnce)
})

it('unmounts the sampler when it is unsubscribed', () => {
const unmount = sinon.spy()
const s = Signal.never()
const t = new Signal(() => unmount)
const a = s.sampleWith(always(), t).subscribe(always())
const a = s.hold(t).subscribe(always())

a.unsubscribe()

Expand Down

0 comments on commit 0d01c71

Please sign in to comment.