Skip to content

Commit

Permalink
feat(pluck): add higher-order lettable version of pluck
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonaden committed Aug 28, 2017
1 parent 595e588 commit 8ab0914
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 23 deletions.
25 changes: 2 additions & 23 deletions src/operator/pluck.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Observable } from '../Observable';
import { map } from './map';
import { pluck as higherOrder } from '../operators/pluck';

/**
* Maps each source value (an object) to its specified nested property.
Expand Down Expand Up @@ -28,26 +28,5 @@ import { map } from './map';
* @owner Observable
*/
export function pluck<T, R>(this: Observable<T>, ...properties: string[]): Observable<R> {
const length = properties.length;
if (length === 0) {
throw new Error('list of properties cannot be empty.');
}
return map.call(this, plucker(properties, length));
}

function plucker(props: string[], length: number): (x: string) => any {
const mapper = (x: string) => {
let currentProp = x;
for (let i = 0; i < length; i++) {
const p = currentProp[props[i]];
if (typeof p !== 'undefined') {
currentProp = p;
} else {
return undefined;
}
}
return currentProp;
};

return mapper;
return higherOrder(...properties)(this);
}
1 change: 1 addition & 0 deletions src/operators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export { observeOn } from './observeOn';
export { onErrorResumeNext } from './onErrorResumeNext';
export { pairwise } from './pairwise';
export { partition } from './partition';
export { pluck } from './pluck';
export { publish } from './publish';
export { race } from './race';
export { reduce } from './reduce';
Expand Down
54 changes: 54 additions & 0 deletions src/operators/pluck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Observable } from '../Observable';
import { map } from './map';
import { OperatorFunction } from '../interfaces';

/**
* Maps each source value (an object) to its specified nested property.
*
* <span class="informal">Like {@link map}, but meant only for picking one of
* the nested properties of every emitted object.</span>
*
* <img src="./img/pluck.png" width="100%">
*
* Given a list of strings describing a path to an object property, retrieves
* the value of a specified nested property from all values in the source
* Observable. If a property can't be resolved, it will return `undefined` for
* that value.
*
* @example <caption>Map every click to the tagName of the clicked target element</caption>
* var clicks = Rx.Observable.fromEvent(document, 'click');
* var tagNames = clicks.pluck('target', 'tagName');
* tagNames.subscribe(x => console.log(x));
*
* @see {@link map}
*
* @param {...string} properties The nested properties to pluck from each source
* value (an object).
* @return {Observable} A new Observable of property values from the source values.
* @method pluck
* @owner Observable
*/
export function pluck<T, R>(...properties: string[]): OperatorFunction<T, R> {
const length = properties.length;
if (length === 0) {
throw new Error('list of properties cannot be empty.');
}
return (source: Observable<T>) => map(plucker(properties, length))(source as any);
}

function plucker(props: string[], length: number): (x: string) => any {
const mapper = (x: string) => {
let currentProp = x;
for (let i = 0; i < length; i++) {
const p = currentProp[props[i]];
if (typeof p !== 'undefined') {
currentProp = p;
} else {
return undefined;
}
}
return currentProp;
};

return mapper;
}

0 comments on commit 8ab0914

Please sign in to comment.