diff --git a/test/arrays.js b/test/arrays.js index 97ff295a9..7b4e45692 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -37,6 +37,12 @@ $(document).ready(function() { equals(_.intersect(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays'); }); + test('arrays: zip', function() { + var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true]; + var stooges = _.zip(names, ages, leaders); + equals(_.toString(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths'); + }); + test("arrays: indexOf", function() { var numbers = [1, 2, 3]; numbers.indexOf = null; diff --git a/test/collections.js b/test/collections.js index 4aebedba4..1ba3512b7 100644 --- a/test/collections.js +++ b/test/collections.js @@ -16,22 +16,6 @@ $(document).ready(function() { equals(answers.join(', '), '5, 10, 15', 'context object property accessed'); }); - test('collections: all', function() { - ok(_.all([]), 'the empty set'); - ok(_.all([true, true, true]), 'all true values'); - ok(!_.all([true, false, true]), 'one false value'); - ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers'); - ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number'); - }); - - test('collections: any', function() { - ok(!_.any([]), 'the empty set'); - ok(!_.any([false, false, false]), 'all false values'); - ok(_.any([false, false, true]), 'one true value'); - ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers'); - ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number'); - }); - test('collections: map', function() { var doubled = _.map([1, 2, 3], function(num){ return num * 2; }); equals(doubled.join(', '), '2, 4, 6', 'doubled numbers'); @@ -60,6 +44,22 @@ $(document).ready(function() { equals(odds.join(', '), '1, 3, 5', 'rejected each even number'); }); + test('collections: all', function() { + ok(_.all([]), 'the empty set'); + ok(_.all([true, true, true]), 'all true values'); + ok(!_.all([true, false, true]), 'one false value'); + ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers'); + ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number'); + }); + + test('collections: any', function() { + ok(!_.any([]), 'the empty set'); + ok(!_.any([false, false, false]), 'all false values'); + ok(_.any([false, false, true]), 'one true value'); + ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers'); + ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number'); + }); + test('collections: include', function() { ok(_.include([1,2,3], 2), 'two is in the array'); ok(!_.include([1,3,9], 2), 'two is not in the array'); diff --git a/test/functions.js b/test/functions.js index 0f9362def..47de34699 100644 --- a/test/functions.js +++ b/test/functions.js @@ -7,6 +7,13 @@ $(document).ready(function() { var func = function() { return "name: " + this.name; }; var bound = _.bind(func, context); equals(bound(), 'name: moe', 'can bind a function to a context'); + + var func = function(salutation, name) { return salutation + ': ' + name; }; + func = _.bind(func, this, 'hello'); + equals(func('moe'), 'hello: moe', 'the function was partially applied in advance'); + + func = _.bind(func, this, 'curly'); + equals(func(), 'hello: curly', 'the function was completely applied in advance'); }); test("functions: bindAll", function() { diff --git a/underscore.js b/underscore.js index c32e87a2d..8f4ba6ee4 100644 --- a/underscore.js +++ b/underscore.js @@ -28,35 +28,10 @@ window._ = { return obj; }, - // Determine whether all of the elements match a truth test. Delegate to - // Javascript 1.6's every(), if it is present. - all : function(obj, iterator, context) { - iterator = iterator || function(v){ return v; }; - if (obj.every) return obj.every(iterator, context); - var result = true; - _.each(obj, function(value, index) { - result = result && !!iterator.call(context, value, index); - if (!result) throw '__break__'; - }); - return result; - }, - - // Determine if at least one element in the object matches a truth test. Use - // Javascript 1.6's some(), if it exists. - any : function(obj, iterator, context) { - iterator = iterator || function(v) { return v; }; - if (obj.some) return obj.some(iterator, context); - var result = false; - _.each(obj, function(value, index) { - if (result = !!iterator.call(context, value, index)) throw '__break__'; - }); - return result; - }, - // Return the results of applying the iterator to each element. Use Javascript // 1.6's version of map, if possible. map : function(obj, iterator, context) { - if (obj.map) return obj.map(iterator, context); + if (obj && obj.map) return obj.map(iterator, context); var results = []; _.each(obj, function(value, index) { results.push(iterator.call(context, value, index)); @@ -64,7 +39,8 @@ window._ = { return results; }, - // Aka reduce. Inject builds up a single result from a list of values. + // Inject builds up a single result from a list of values. Also known as + // reduce, and foldl. inject : function(obj, memo, iterator, context) { _.each(obj, function(value, index) { memo = iterator.call(context, memo, value, index); @@ -104,6 +80,31 @@ window._ = { return results; }, + // Determine whether all of the elements match a truth test. Delegate to + // Javascript 1.6's every(), if it is present. + all : function(obj, iterator, context) { + iterator = iterator || function(v){ return v; }; + if (obj.every) return obj.every(iterator, context); + var result = true; + _.each(obj, function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw '__break__'; + }); + return result; + }, + + // Determine if at least one element in the object matches a truth test. Use + // Javascript 1.6's some(), if it exists. + any : function(obj, iterator, context) { + iterator = iterator || function(v) { return v; }; + if (obj.some) return obj.some(iterator, context); + var result = false; + _.each(obj, function(value, index) { + if (result = !!iterator.call(context, value, index)) throw '__break__'; + }); + return result; + }, + // Determine if a given value is included in the array or object, // based on '=='. include : function(obj, target) { @@ -239,6 +240,16 @@ window._ = { }); }, + // Zip together multiple lists into a single array -- elements that share + // an index go together. + zip : function() { + var args = _.toArray(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i=0; i