-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from evilsoft/curryN
Add `curryN` to the helper functions
- Loading branch information
Showing
6 changed files
with
122 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** @license ISC License (c) copyright 2016 original and current authors */ | ||
/** @author Ian Hofmann-Hicks (evil) */ | ||
|
||
const isNumber = require('../internal/isNumber') | ||
const isFunction = require('../internal/isFunction') | ||
const argsArray = require('../internal/argsArray') | ||
|
||
function curryN(n, fn) { | ||
if(!isNumber(n)) { | ||
throw new TypeError('curryN: Number required for first argument') | ||
} | ||
if(!isFunction(fn)) { | ||
throw new TypeError('curryN: Function required for second argument') | ||
} | ||
|
||
return function() { | ||
const xs = | ||
argsArray(arguments) | ||
|
||
const args = | ||
xs.length ? xs : [ undefined ] | ||
|
||
const remaining = | ||
Math.floor(n) - args.length | ||
|
||
return (remaining > 0) | ||
? curryN(remaining, Function.bind.apply(fn, [ null ].concat(args))) | ||
: fn.apply(null, args.slice(0, n)) | ||
} | ||
} | ||
|
||
module.exports = curryN |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
const test = require('tape') | ||
const sinon = require('sinon') | ||
const helpers = require('../test/helpers') | ||
|
||
const curryN = require('./curryN') | ||
|
||
const noop = helpers.noop | ||
const bindFunc = helpers.bindFunc | ||
const isFunction = require('../internal/isFunction') | ||
|
||
test('curryN errors', t => { | ||
const c = bindFunc(curryN) | ||
|
||
t.ok(isFunction(curryN), 'curryN is a function') | ||
|
||
t.throws(curryN, TypeError, 'throws when nothing passed') | ||
|
||
t.throws(c(undefined, noop), TypeError, 'throws when undefined passed in first argument') | ||
t.throws(c(null, noop), TypeError, 'throws when null passed in first argument') | ||
t.throws(c('', noop), TypeError, 'throws when falsey string passed in first argument') | ||
t.throws(c('string', noop), TypeError, 'throws when truthy string passed in first argument') | ||
t.throws(c(false, noop), TypeError, 'throws when false passed in first argument') | ||
t.throws(c(true, noop), TypeError, 'throws when true passed in first argument') | ||
t.throws(c(noop, noop), TypeError, 'throws when function passed in first argument') | ||
t.throws(c({}, noop), TypeError, 'throws when object passed in first argument') | ||
t.throws(c([], noop), TypeError, 'throws when array passed in first argument') | ||
|
||
t.throws(c(1, undefined), TypeError, 'throws when undefined passed in second argument') | ||
t.throws(c(1, null), TypeError, 'throws when null passed in second argument') | ||
t.throws(c(1, ''), TypeError, 'throws when falsey string passed in second argument') | ||
t.throws(c(1, 'string'), TypeError, 'throws when truthy string passed in second argument') | ||
t.throws(c(1, 0), TypeError, 'throws when falsey number passed in second argument') | ||
t.throws(c(1, 32), TypeError, 'throws when truthy number passed in second argument') | ||
t.throws(c(1, false), TypeError, 'throws when false passed in second argument') | ||
t.throws(c(1, true), TypeError, 'throws when true passed in second argument') | ||
t.throws(c(1, {}), TypeError, 'throws when object passed in second argument') | ||
t.throws(c(1, []), TypeError, 'throws when array passed in second argument') | ||
|
||
t.ok(isFunction(curryN(1, noop)), 'returns a function') | ||
|
||
t.end() | ||
}) | ||
|
||
test('curryN function functionality', t => { | ||
const result = 'result' | ||
const f = sinon.spy(() => result) | ||
const curried = curryN(3, f) | ||
|
||
t.equal(curried(2, 3, 1), result, 'returns the result when fully applied') | ||
t.equal(curried(2)(3)(1), result, 'returns the result when curried') | ||
t.equal(curried(1, 2)(3), result, 'returns the result when called (_, _)(_)') | ||
t.equal(curried(1)(2, 3), result, 'returns the result when called (_)(_, _)') | ||
|
||
curried(1, 2, 3, 4, 5) | ||
t.equal(f.lastCall.args.length, 3, 'only applies N arguments') | ||
|
||
t.equal(curried()()(), result, 'returns the result when curried with no args') | ||
t.same(f.lastCall.args, [ undefined, undefined, undefined ], 'applies undefineds when curried with no args') | ||
|
||
t.end() | ||
}) | ||
|
||
test('curry0 called with arguments', t => { | ||
const f = sinon.spy(() => 'string') | ||
const curried = curryN(0, f) | ||
|
||
t.equal(curried(1, 2, 3), 'string', 'returns the result') | ||
t.equal(f.lastCall.args.length, 0, 'does not pass arguments to function') | ||
t.end() | ||
}) | ||
|
||
test('curry0 called with no arguments', t => { | ||
const f = sinon.spy(() => 'string') | ||
const curried = curryN(0, f) | ||
|
||
t.equal(curried(), 'string', 'returns the result') | ||
t.end() | ||
}) |