diff --git a/.npmignore b/.npmignore index 4dc102d..a6e5a66 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,4 @@ test/ .nvmrc .eslintrc +.idea/ diff --git a/README.md b/README.md index 857a21c..0051839 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,19 @@ flattenObject(obj); ``` +#### functionOrValue(fnOrValue, [...args]) + +Returns either the value given or the return value of the function passed in. Can be called with optional arguments (...args). +Also cascades downward if functions return functions. + +```JavaScript +console.log(functionOrValue(true)); // true +console.log(functionOrValue(() => false)); // false +console.log(functionOrValue((a, b, c) => a + b + c, 5, 6, 7)); // 18 +console.log(functionOrValue((a, b, c) => () => a + c, 5, 6, 7)); // 12 +``` + + #### isJsonString(str) Returns a boolean that specifies whether the string is parsable JSON. diff --git a/lib/function.js b/lib/function.js index 3cf3743..db431df 100644 --- a/lib/function.js +++ b/lib/function.js @@ -4,6 +4,11 @@ function acceptNoArguments(fn, ...args) { return _.ary(_.partial(fn, ...args), 0); } +function functionOrValue(fnOrValue, ...args) { + return _.isFunction(fnOrValue) ? functionOrValue(fnOrValue(...args), ...args) : fnOrValue; +} + module.exports = { - acceptNoArguments + acceptNoArguments, + functionOrValue }; diff --git a/test/function.spec.js b/test/function.spec.js index f17bef0..97f05ec 100644 --- a/test/function.spec.js +++ b/test/function.spec.js @@ -2,7 +2,7 @@ const chai = require('chai'); const { expect } = chai; const sinon = require('sinon'); -const { acceptNoArguments } = require('../'); +const { acceptNoArguments, functionOrValue } = require('../'); chai.use(require('sinon-chai')); @@ -36,4 +36,47 @@ describe('function', function () { expect(fn.args[0]).to.be.eql([3, 4]); }); }); + + describe('functionOrValue()', function () { + let fn; + + beforeEach(function () { + fn = sinon.stub().returns(55); + }); + + it('should return a non-function nil value if passed', function () { + expect(functionOrValue(null)).to.be.null; + }); + + it('should return a non-function primitive value of passed', function () { + expect(functionOrValue(55)).to.equal(55); + }); + + it('should return an object if passed', function () { + expect(functionOrValue({ name: 'Koolaid' })).to.eql({ name: 'Koolaid' }); + }); + + it('should return an array if passed', function () { + expect(functionOrValue([1, 2, 5])).to.eql([1, 2, 5]); + }); + + it('should call a function even if no additional arguments are passed', function () { + expect(functionOrValue(fn)).to.equal(55); + expect(fn).to.have.been.calledOnce; + }); + + it('should call a function with the additional arguments', function () { + expect(functionOrValue(fn, 44, {}, 'orange')).to.equal(55); + expect(fn).to.have.been.calledOnce; + expect(fn).to.have.been.calledWith(44, {}, 'orange'); + }); + + it('should be able to call cascading functions that return other functions', function () { + const stub = sinon.stub().returns(true); + fn = () => () => () => stub; + expect(functionOrValue(fn, 78, [55, 66, 77])).to.be.true; + expect(stub).to.have.been.calledOnce; + expect(stub).to.have.been.calledWith(78, [55, 66, 77]); + }); + }); });