From 85f4e083d85634fc550818fe7f329a6e1902c60d Mon Sep 17 00:00:00 2001 From: Marcus Stade Date: Fri, 18 Apr 2014 15:32:32 +0200 Subject: [PATCH 1/3] Added `and` for logical testing Will return the last value if all values are logically true; or the first logically false value. --- lib/and.js | 20 ++++++++++++++++++++ test/and.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 lib/and.js create mode 100644 test/and.js diff --git a/lib/and.js b/lib/and.js new file mode 100644 index 0000000..c8969f5 --- /dev/null +++ b/lib/and.js @@ -0,0 +1,20 @@ +module.exports = require('./variadic')(and) + +function and(x, rest) { + if (isEmpty(arguments)) return true + + var result = val(x) + + if (isnt(result) || isnt(rest)) return result + + rest.every(function(x) { + return is(result = val(x)) + }) + + return result +} + +const isEmpty = require('./isEmpty') + , isnt = require('./isnt') + , val = require('./val') + , is = require('./is') \ No newline at end of file diff --git a/test/and.js b/test/and.js new file mode 100644 index 0000000..a800877 --- /dev/null +++ b/test/and.js @@ -0,0 +1,50 @@ +const constantly = require('../lib/constantly') + , expect = require('chai').expect + , and = require('../lib/and') + +describe('`and`', function() { + describe('given zero arguments', function() { + it('should return `true`', function() { + expect(and()).to.equal(true) + }) + }) + + describe('given one argument', function() { + it('should return the value of that argument', function() { + expect(and(1)).to.equal(1) + expect(and(0)).to.equal(0) + expect(and(false)).to.equal(false) + }) + + describe('and when that argument is a function', function() { + it('should return the value of calling that function', function() { + expect(and(constantly('wibble'))).to.equal('wibble') + }) + }) + }) + + describe('given two or more arguments', function() { + describe('when the values of all arguments are logically true', function() { + it('should return the last supplied value', function() { + expect(and(0, 1, 2, 3)).to.equal(3) + }) + }) + + describe('when any one argument is logically false', function() { + it('should return the value that was logically false', function() { + expect(and(0, null, 1)).to.equal(null) + expect(and(false, true, 1)).to.equal(false) + expect(and(0, true, undefined)).to.equal(undefined) + }) + }) + + describe('when an argument is a function', function() { + it('should call the function and evaluate its return value', function() { + var called = false + + expect(and(0, function() { return (called = true) }, 1, 'yup')).to.equal('yup') + expect(called).to.be.true + }) + }) + }) +}) \ No newline at end of file From fa7b133d3014b2a206523f087163ef3d131f2c23 Mon Sep 17 00:00:00 2001 From: Marcus Stade Date: Sat, 31 Jan 2015 14:20:33 +0000 Subject: [PATCH 2/3] Fix variadic to always set fixed arguments If a variadic function is called with fewer arguments than specified by `fn`, then the arguments should still be filled, and rest should be empty. --- lib/variadic.js | 65 +++++++++++++++++++++++++++--------------------- test/variadic.js | 22 +++++++++++++++- 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/lib/variadic.js b/lib/variadic.js index 2781218..6c7e024 100644 --- a/lib/variadic.js +++ b/lib/variadic.js @@ -7,39 +7,46 @@ function variadic(fn) { switch (argc) { case -1 : return fn - case 0 : return function (rest) { return apply(fn, this, argc, slice(arguments)) } - case 1 : return function (a, rest) { return apply(fn, this, argc, slice(arguments)) } - case 2 : return function (a, b, rest) { return apply(fn, this, argc, slice(arguments)) } - case 3 : return function (a, b, c, rest) { return apply(fn, this, argc, slice(arguments)) } - case 4 : return function (a, b, c, d, rest) { return apply(fn, this, argc, slice(arguments)) } - case 5 : return function (a, b, c, d, e, rest) { return apply(fn, this, argc, slice(arguments)) } - case 6 : return function (a, b, c, d, e, f, rest) { return apply(fn, this, argc, slice(arguments)) } - case 7 : return function (a, b, c, d, e, f, g, rest) { return apply(fn, this, argc, slice(arguments)) } - case 8 : return function (a, b, c, d, e, f, g, h, rest) { return apply(fn, this, argc, slice(arguments)) } - case 9 : return function (a, b, c, d, e, f, g, h, i, rest) { return apply(fn, this, argc, slice(arguments)) } - case 10 : return function (a, b, c, d, e, f, g, h, i, j, rest) { return apply(fn, this, argc, slice(arguments)) } - case 11 : return function (a, b, c, d, e, f, g, h, i, j, k, rest) { return apply(fn, this, argc, slice(arguments)) } - case 12 : return function (a, b, c, d, e, f, g, h, i, j, k, l, rest) { return apply(fn, this, argc, slice(arguments)) } - case 13 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, rest) { return apply(fn, this, argc, slice(arguments)) } - case 14 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, rest) { return apply(fn, this, argc, slice(arguments)) } - case 15 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, rest) { return apply(fn, this, argc, slice(arguments)) } - case 16 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, rest) { return apply(fn, this, argc, slice(arguments)) } - case 17 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, rest) { return apply(fn, this, argc, slice(arguments)) } - case 18 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, rest) { return apply(fn, this, argc, slice(arguments)) } - case 19 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, rest) { return apply(fn, this, argc, slice(arguments)) } - case 20 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, rest) { return apply(fn, this, argc, slice(arguments)) } - case 21 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, rest) { return apply(fn, this, argc, slice(arguments)) } - case 22 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, rest) { return apply(fn, this, argc, slice(arguments)) } - case 23 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, rest) { return apply(fn, this, argc, slice(arguments)) } - case 24 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, rest) { return apply(fn, this, argc, slice(arguments)) } - case 25 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, rest) { return apply(fn, this, argc, slice(arguments)) } - default : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, rest) { return apply(fn, this, argc, slice(arguments)) } + case 0 : return function (rest) { return apply(fn, this, argc, arguments) } + case 1 : return function (a, rest) { return apply(fn, this, argc, arguments) } + case 2 : return function (a, b, rest) { return apply(fn, this, argc, arguments) } + case 3 : return function (a, b, c, rest) { return apply(fn, this, argc, arguments) } + case 4 : return function (a, b, c, d, rest) { return apply(fn, this, argc, arguments) } + case 5 : return function (a, b, c, d, e, rest) { return apply(fn, this, argc, arguments) } + case 6 : return function (a, b, c, d, e, f, rest) { return apply(fn, this, argc, arguments) } + case 7 : return function (a, b, c, d, e, f, g, rest) { return apply(fn, this, argc, arguments) } + case 8 : return function (a, b, c, d, e, f, g, h, rest) { return apply(fn, this, argc, arguments) } + case 9 : return function (a, b, c, d, e, f, g, h, i, rest) { return apply(fn, this, argc, arguments) } + case 10 : return function (a, b, c, d, e, f, g, h, i, j, rest) { return apply(fn, this, argc, arguments) } + case 11 : return function (a, b, c, d, e, f, g, h, i, j, k, rest) { return apply(fn, this, argc, arguments) } + case 12 : return function (a, b, c, d, e, f, g, h, i, j, k, l, rest) { return apply(fn, this, argc, arguments) } + case 13 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, rest) { return apply(fn, this, argc, arguments) } + case 14 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, rest) { return apply(fn, this, argc, arguments) } + case 15 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, rest) { return apply(fn, this, argc, arguments) } + case 16 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, rest) { return apply(fn, this, argc, arguments) } + case 17 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, rest) { return apply(fn, this, argc, arguments) } + case 18 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, rest) { return apply(fn, this, argc, arguments) } + case 19 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, rest) { return apply(fn, this, argc, arguments) } + case 20 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, rest) { return apply(fn, this, argc, arguments) } + case 21 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, rest) { return apply(fn, this, argc, arguments) } + case 22 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, rest) { return apply(fn, this, argc, arguments) } + case 23 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, rest) { return apply(fn, this, argc, arguments) } + case 24 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, rest) { return apply(fn, this, argc, arguments) } + case 25 : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, rest) { return apply(fn, this, argc, arguments) } + default : return function (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, rest) { return apply(fn, this, argc, arguments) } } } function apply(fn, host, argc, argv) { - var rest = slice(argv, argc) - argv = slice(argv, 0, argc) + var rest = [] + + if (argv.length < argc) { + argv = slice(argv).concat(Array(argc - argv.length)) + } else { + rest = slice(argv, argc) + argv = slice(argv, 0, argc) + } + argv.push(rest) return fn.apply(host, argv) diff --git a/test/variadic.js b/test/variadic.js index 1a31a02..48b0b51 100644 --- a/test/variadic.js +++ b/test/variadic.js @@ -5,6 +5,7 @@ var variadic = require('../lib/variadic') , slice = require('../lib/slice') , each = require('../lib/each') , src = require('../lib/src') + , is = require('../lib/is') describe('`variadic`', function() { describe('given an argument `fn`', function() { @@ -32,6 +33,25 @@ describe('`variadic`', function() { }) }) + describe('of arity 1', function() { + + it('should return a 1-arity function', function() { + var fn = variadic(function(rest) {}) + expect(fn).to.have.length(1) + }) + + describe('when called without arguments', function() { + it('should set `rest` to an empty array', function(done) { + var fn = variadic(function(rest) { + is(Array, rest) && expect(rest).to.have.length(0) + done() + }) + + fn() + }) + }) + }) + each(range(1, 28), function(n) { describe('of arity '+n, function() { var sig = slice('abcdefghijklmnopqrstuvwxyz', 0, n - 1).concat('rest') @@ -49,7 +69,7 @@ describe('`variadic`', function() { while (args.length) { var fn = Function.apply(Function, sig.concat( - [ 'this.expect(arguments).to.have.length('+(args.length + 1)+')' + [ 'this.expect(arguments).to.have.length('+sig.length+')' , 'this.expect(rest).to.be.empty' ].join('\n') )) From a22e94d71cde71ef6905bc385a709679f080a016 Mon Sep 17 00:00:00 2001 From: Marcus Stade Date: Sat, 31 Jan 2015 14:22:18 +0000 Subject: [PATCH 3/3] Add `and` for logical testing --- index.js | 3 ++- lib/and.js | 2 +- test/and.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 9a8929c..285cddf 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ module.exports = - { apply : require('./lib/apply') + { and : require('./lib/and') + , apply : require('./lib/apply') , assert : require('./lib/assert') , call : require('./lib/call') , compose : require('./lib/compose') diff --git a/lib/and.js b/lib/and.js index c8969f5..b2cf711 100644 --- a/lib/and.js +++ b/lib/and.js @@ -1,7 +1,7 @@ module.exports = require('./variadic')(and) function and(x, rest) { - if (isEmpty(arguments)) return true + if (x === undefined && isEmpty(rest)) return true var result = val(x) diff --git a/test/and.js b/test/and.js index a800877..95fa90f 100644 --- a/test/and.js +++ b/test/and.js @@ -1,5 +1,5 @@ const constantly = require('../lib/constantly') - , expect = require('chai').expect + , expect = require('must') , and = require('../lib/and') describe('`and`', function() {