Skip to content

Commit

Permalink
feat(take): add higher-order lettable version of take
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonaden committed Sep 7, 2017
1 parent 2640184 commit 089a5a6
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 47 deletions.
49 changes: 2 additions & 47 deletions src/operator/take.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { Operator } from '../Operator';
import { Subscriber } from '../Subscriber';
import { ArgumentOutOfRangeError } from '../util/ArgumentOutOfRangeError';
import { EmptyObservable } from '../observable/EmptyObservable';
import { Observable } from '../Observable';
import { TeardownLogic } from '../Subscription';
import { take as higherOrder } from '../operators/take';

/**
* Emits only the first `count` values emitted by the source Observable.
Expand Down Expand Up @@ -39,46 +35,5 @@ import { TeardownLogic } from '../Subscription';
* @owner Observable
*/
export function take<T>(this: Observable<T>, count: number): Observable<T> {
if (count === 0) {
return new EmptyObservable<T>();
} else {
return this.lift(new TakeOperator(count));
}
}

class TakeOperator<T> implements Operator<T, T> {
constructor(private total: number) {
if (this.total < 0) {
throw new ArgumentOutOfRangeError;
}
}

call(subscriber: Subscriber<T>, source: any): TeardownLogic {
return source.subscribe(new TakeSubscriber(subscriber, this.total));
}
}

/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
class TakeSubscriber<T> extends Subscriber<T> {
private count: number = 0;

constructor(destination: Subscriber<T>, private total: number) {
super(destination);
}

protected _next(value: T): void {
const total = this.total;
const count = ++this.count;
if (count <= total) {
this.destination.next(value);
if (count === total) {
this.destination.complete();
this.unsubscribe();
}
}
}
return higherOrder(count)(this);
}
1 change: 1 addition & 0 deletions src/operators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export { subscribeOn } from './subscribeOn';
export { switchAll } from './switchAll';
export { switchMap } from './switchMap';
export { switchMapTo } from './switchMapTo';
export { take } from './take';
export { takeLast } from './takeLast';
export { tap } from './tap';
export { timestamp } from './timestamp';
Expand Down
87 changes: 87 additions & 0 deletions src/operators/take.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Operator } from '../Operator';
import { Subscriber } from '../Subscriber';
import { ArgumentOutOfRangeError } from '../util/ArgumentOutOfRangeError';
import { EmptyObservable } from '../observable/EmptyObservable';
import { Observable } from '../Observable';
import { TeardownLogic } from '../Subscription';
import { MonoTypeOperatorFunction } from '../interfaces';

/**
* Emits only the first `count` values emitted by the source Observable.
*
* <span class="informal">Takes the first `count` values from the source, then
* completes.</span>
*
* <img src="./img/take.png" width="100%">
*
* `take` returns an Observable that emits only the first `count` values emitted
* by the source Observable. If the source emits fewer than `count` values then
* all of its values are emitted. After that, it completes, regardless if the
* source completes.
*
* @example <caption>Take the first 5 seconds of an infinite 1-second interval Observable</caption>
* var interval = Rx.Observable.interval(1000);
* var five = interval.take(5);
* five.subscribe(x => console.log(x));
*
* @see {@link takeLast}
* @see {@link takeUntil}
* @see {@link takeWhile}
* @see {@link skip}
*
* @throws {ArgumentOutOfRangeError} When using `take(i)`, it delivers an
* ArgumentOutOrRangeError to the Observer's `error` callback if `i < 0`.
*
* @param {number} count The maximum number of `next` values to emit.
* @return {Observable<T>} An Observable that emits only the first `count`
* values emitted by the source Observable, or all of the values from the source
* if the source emits fewer than `count` values.
* @method take
* @owner Observable
*/
export function take<T>(count: number): MonoTypeOperatorFunction<T> {
return (source: Observable<T>) => {
if (count === 0) {
return new EmptyObservable<T>();
} else {
return source.lift(new TakeOperator(count));
}
};
}

class TakeOperator<T> implements Operator<T, T> {
constructor(private total: number) {
if (this.total < 0) {
throw new ArgumentOutOfRangeError;
}
}

call(subscriber: Subscriber<T>, source: any): TeardownLogic {
return source.subscribe(new TakeSubscriber(subscriber, this.total));
}
}

/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
class TakeSubscriber<T> extends Subscriber<T> {
private count: number = 0;

constructor(destination: Subscriber<T>, private total: number) {
super(destination);
}

protected _next(value: T): void {
const total = this.total;
const count = ++this.count;
if (count <= total) {
this.destination.next(value);
if (count === total) {
this.destination.complete();
this.unsubscribe();
}
}
}
}

0 comments on commit 089a5a6

Please sign in to comment.