Skip to content

Commit

Permalink
feat(Observable.generate): add generate static creation method
Browse files Browse the repository at this point in the history
- add overloads that accepts distinct options and a single options object
- add tests with marble diagrams
- add JSDoc
  • Loading branch information
Igorbek authored and benlesh committed Apr 14, 2016
1 parent abac3d1 commit c03434c
Show file tree
Hide file tree
Showing 6 changed files with 479 additions and 0 deletions.
3 changes: 3 additions & 0 deletions doc/decision-tree-widget/tree.yml
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ children:
- label: using custom logic
children:
- label: Observable.create
- label: using a state machine similar to a for loop
children:
- label: Observable.generate
- label: that throws an error
children:
- label: Observable.throw
Expand Down
1 change: 1 addition & 0 deletions doc/operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ There are operators for different purposes, and they may be categorized as: crea
- [`fromEvent`](../class/es6/Observable.js~Observable.html#static-method-fromEvent)
- [`fromEventPattern`](../class/es6/Observable.js~Observable.html#static-method-fromEventPattern)
- [`fromPromise`](../class/es6/Observable.js~Observable.html#static-method-fromPromise)
- [`generate`](../class/es6/Observable.js~Observable.html#static-method-generate)
- [`interval`](../class/es6/Observable.js~Observable.html#static-method-interval)
- [`never`](../class/es6/Observable.js~Observable.html#static-method-never)
- [`of`](../class/es6/Observable.js~Observable.html#static-method-of)
Expand Down
168 changes: 168 additions & 0 deletions spec/observables/generate-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import * as Rx from '../../dist/cjs/Rx.KitchenSink';
import '../../dist/cjs/add/observable/generate';
import {TestScheduler} from '../../dist/cjs/testing/TestScheduler';
import {expect} from 'chai';
declare const {asDiagram, expectObservable};
declare const rxTestScheduler: TestScheduler;

const Observable = Rx.Observable;

function err(): any {
throw 'error';
}

describe('Observable.generate', () => {
asDiagram('generate(1, x => false, x => x + 1)')
('should complete if condition does not meet', () => {
const source = Observable.generate(1, x => false, x => x + 1);
const expected = '|';

expectObservable(source).toBe(expected);
});

asDiagram('generate(1, x => x == 1, x => x + 1)')
('should produce first value immediately', () => {
const source = Observable.generate(1, x => x == 1, x => x + 1);
const expected = '(1|)';

expectObservable(source).toBe(expected, { '1': 1 });
});

asDiagram('generate(1, x => x < 3, x => x + 1)')
('should produce all values synchronously', () => {
const source = Observable.generate(1, x => x < 3, x => x + 1);
const expected = '(12|)';

expectObservable(source).toBe(expected, { '1': 1, '2': 2 });
});

it('should use result selector', () => {
const source = Observable.generate(1, x => x < 3, x => x + 1, x => (x + 1).toString());
const expected = '(23|)';

expectObservable(source).toBe(expected);
});

it('should allow omit condition', () => {
const source = Observable.generate({
initialState: 1,
iterate: x => x + 1,
resultSelector: x => x.toString()
}).take(5);
const expected = '(12345|)';

expectObservable(source).toBe(expected);
});

it('should stop producing when unsubscribed', () => {
const source = Observable.generate(1, x => x < 4, x => x + 1);
let count = 0;
const subscriber = new Rx.Subscriber<number>(
x => {
count++;
if (x == 2) {
subscriber.unsubscribe();
}
}
);
source.subscribe(subscriber);
expect(count).to.be.equal(2);
});

it('should accept a scheduler', () => {
const source = Observable.generate({
initialState: 1,
condition: x => x < 4,
iterate: x => x + 1,
resultSelector: x => x,
scheduler: rxTestScheduler
});
const expected = '(123|)';

let count = 0;
source.subscribe(x => count++);

expect(count).to.be.equal(0);
rxTestScheduler.flush();
expect(count).to.be.equal(3);

expectObservable(source).toBe(expected, { '1': 1, '2': 2, '3': 3 });
});

it('should allow minimal possible options', () => {
const source = Observable.generate({
initialState: 1,
iterate: x => x * 2
}).take(3);
const expected = '(124|)';

expectObservable(source).toBe(expected, { '1': 1, '2': 2, '4': 4 });
});

it('should emit error if result selector throws', () => {
const source = Observable.generate({
initialState: 1,
iterate: x => x * 2,
resultSelector: err
});
const expected = '(#)';

expectObservable(source).toBe(expected);
});

it('should emit error if result selector throws on scheduler', () => {
const source = Observable.generate({
initialState: 1,
iterate: x => x * 2,
resultSelector: err,
scheduler: rxTestScheduler
});
const expected = '(#)';

expectObservable(source).toBe(expected);
});

it('should emit error after first value if iterate function throws', () => {
const source = Observable.generate({
initialState: 1,
iterate: err
});
const expected = '(1#)';

expectObservable(source).toBe(expected, { '1': 1 });
});

it('should emit error after first value if iterate function throws on scheduler', () => {
const source = Observable.generate({
initialState: 1,
iterate: err,
scheduler: rxTestScheduler
});
const expected = '(1#)';

expectObservable(source).toBe(expected, { '1': 1 });
});

it('should emit error if condition function throws', () => {
const source = Observable.generate({
initialState: 1,
iterate: x => x + 1,
condition: err
});
const expected = '(#)';

expectObservable(source).toBe(expected);
});

it('should emit error if condition function throws on scheduler', () => {
const source = Observable.generate({
initialState: 1,
iterate: x => x + 1,
condition: err,
scheduler: rxTestScheduler
});
const expected = '(#)';

expectObservable(source).toBe(expected);
});
});
1 change: 1 addition & 0 deletions src/Rx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import './add/observable/from';
import './add/observable/fromEvent';
import './add/observable/fromEventPattern';
import './add/observable/fromPromise';
import './add/observable/generate';
import './add/observable/interval';
import './add/observable/merge';
import './add/observable/race';
Expand Down
10 changes: 10 additions & 0 deletions src/add/observable/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {Observable} from '../../Observable';
import {GenerateObservable} from '../../observable/GenerateObservable';

Observable.generate = GenerateObservable.create;

declare module '../../Observable' {
namespace Observable {
export let generate: typeof GenerateObservable.create;
}
}
Loading

0 comments on commit c03434c

Please sign in to comment.