From ebd03ee7037b3fe7e42dad9362b8f39c67ab30c3 Mon Sep 17 00:00:00 2001 From: Andrei Dumitrescu <5057797+andreidcm@users.noreply.github.com> Date: Fri, 28 Aug 2020 17:21:46 +0200 Subject: [PATCH] feat: Add "converge" functions --- src/converge/converge.js | 46 +++++++++++++++++++++++++++++++++++ src/converge/converge.test.js | 27 ++++++++++++++++++++ src/index.js | 7 +++--- 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/converge/converge.js create mode 100644 src/converge/converge.test.js diff --git a/src/converge/converge.js b/src/converge/converge.js new file mode 100644 index 0000000..8d1cf13 --- /dev/null +++ b/src/converge/converge.js @@ -0,0 +1,46 @@ +import { pipe } from "../pipe/pipe" + +const _converge = (_accFn, _extractFn, source) => { + const accFn = Array.isArray(_accFn) ? pipe(..._accFn) : _accFn + const extractFn = Array.isArray(_extractFn) ? _extractFn : [_extractFn] + const extractValues = [] + + for (let i = 0; i < extractFn.length; ++i) { + extractValues.push(extractFn[i](source)) + } + + return accFn(...extractValues) +} + +/** + * Apply a list of function, extract functions, on the same input and use + * those results as parameters for another accumulator function. + * + * @param {Fn|Fn[]} accFn Accumulator or final aggreate function + * @param {Fn|Fn[]} extractFn List of functions to be applied on input + * @param {Any} source Source input + * + * @return {Any} + * + * @name converge + * @tag Core + * @signature (accFn: Fn|Fn[], extractFn: Fn|Fn[]) => (source: Array): Any + * @signature (accFn: Fn|Fn[], extractFn: Fn|Fn[], source: Array): Any + * + * @example + * const divide = () => ... + * const sum = () => ... + * const count = () => ... + * + * converge(divide, [sum, count], [1, 2, 3, 4, 5, 6, 7]) + * // => 4 + */ +export const converge = (...params) => { + // @signature (accFn, extractFn) => (source) + if (params.length <= 2) { + return source => _converge(params[0], params[1], source) + } + + // @signature (accFn, extractFn, source) + return _converge(...params) +} diff --git a/src/converge/converge.test.js b/src/converge/converge.test.js new file mode 100644 index 0000000..5202608 --- /dev/null +++ b/src/converge/converge.test.js @@ -0,0 +1,27 @@ +import test from "tape" +import { converge, reduce, read } from ".." + +test("converge", t => { + const obj = { a: 1, b: 2 } + const sum = (...params) => reduce((acc, item) => acc + item, 0, params) + + t.equals( + converge(sum, [read("a"), read("b")])(obj), + 3, + "Extract object properties + sum (curried)" + ) + + t.equals( + converge(sum, read("b"), obj), + 2, + "Extract object property + sum (uncurried)" + ) + + t.equals( + converge([sum], [read("a"), read("b")], obj), + 3, + "Extract object properties + sum (uncurried)" + ) + + t.end() +}) diff --git a/src/index.js b/src/index.js index 60e05c4..ec03296 100644 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,8 @@ -export { curry } from "./curry/curry" -export { zipToObj } from "./zip-to-obj/zip-to-obj" export { isDeepEqual, isDeepEqual as deepEqual } from "./deep-equal/deep-equal" export { elapsedTime } from "./elapsed-time/elapsed-time" export { groupBy } from "./group-by/group-by" export { indexBy } from "./index-by/index-by" export { hist } from "./hist/hist" -export { isMatch } from "./is-match/is-match" export { protoChain } from "./proto-chain/proto-chain" export { renameFile } from "./rename-file/rename-file" export { sequence, sequenceWhile } from "./sequence/sequence" @@ -16,9 +13,11 @@ export { throttle } from "./throttle/throttle" export { debounce } from "./debounce/debounce" // Core +export { curry } from "./curry/curry" export { map } from "./map/map" export { mapMatrix } from "./map-matrix/map-matrix" export { reduce } from "./reduce/reduce" +export { converge } from "./converge/converge" export { forEach } from "./for-each/for-each" export { pipe } from "./pipe/pipe" export { pipeP } from "./pipeP/pipeP" @@ -37,12 +36,14 @@ export { any, anyWith } from "./any/any" export { all, allWith } from "./all/all" export { when } from "./when/when" export { cases } from "./cases/cases" +export { isMatch } from "./is-match/is-match" // Object export { pick } from "./pick/pick" export { pluck } from "./pluck/pluck" export { merge } from "./merge/merge" export { keys } from "./keys/keys" +export { zipToObj } from "./zip-to-obj/zip-to-obj" // Array export { top } from "./top/top"