From c174663ea3b7d18d9df4f94dfb69eddc35686522 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Sun, 24 Apr 2011 11:41:31 -0400
Subject: [PATCH 01/36] fixing docs for 'all'
---
index.html | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/index.html b/index.html
index 04c878ad0..685706fee 100644
--- a/index.html
+++ b/index.html
@@ -340,16 +340,14 @@ Collection Functions (Arrays or Objects)
- _.all(list, [iterator], [context])
+ _.all(list, iterator, [context])
Alias: every
Returns true if all of the values in the list pass the iterator
- truth test. If an iterator is not provided, the truthy value of
- the element will be used instead. Delegates to the native method every, if
- present.
+ truth test. Delegates to the native method every, if present.
-_.all([true, 1, null, 'yes']);
+_.all([true, 1, null, 'yes'], _.identity);
=> false
From efa717b09ef63f4ed5ccf18de9d0ef44aa947be1 Mon Sep 17 00:00:00 2001
From: Danny Tatom
Date: Tue, 3 May 2011 17:29:21 -0700
Subject: [PATCH 02/36] Should be 'A convenient,' not 'An convenient'
---
index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/index.html b/index.html
index 685706fee..181c0b1f1 100644
--- a/index.html
+++ b/index.html
@@ -393,7 +393,7 @@ Collection Functions (Arrays or Objects)
_.pluck(list, propertyName)
- An convenient version of what is perhaps the most common use-case for
+ A convenient version of what is perhaps the most common use-case for
map: extracting a list of property values.
From f8a4b78a86660fe0e030d9bd7f7350fbb788cb01 Mon Sep 17 00:00:00 2001
From: Andrei
Date: Thu, 5 May 2011 14:00:40 -0400
Subject: [PATCH 03/36] Adding groupBy.
---
index.html | 13 ++++++++++++-
test/collections.js | 6 ++++++
underscore.js | 15 +++++++++++++++
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/index.html b/index.html
index 685706fee..d83ed3796 100644
--- a/index.html
+++ b/index.html
@@ -141,7 +141,7 @@ Table of Contents
any, include,
invoke, pluck,
max, min,
- sortBy, sortedIndex,
+ sortBy, groupBy, sortedIndex,
toArray, size
@@ -437,6 +437,17 @@ Collection Functions (Arrays or Objects)
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
=> [5, 4, 6, 3, 1, 2]
+
+
+
+ _.groupBy(list, iterator)
+
+ Splits a collection into sets, grouped by the result of running each
+ value through iterator.
+
+
+_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
+=> {1: [1.3], 2: [2.1, 2.4]}
diff --git a/test/collections.js b/test/collections.js
index ff365f8ea..e1dc5ebfc 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -185,6 +185,12 @@ $(document).ready(function() {
people = _.sortBy(people, function(person){ return person.age; });
equals(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
});
+
+ test('collections: groupBy', function() {
+ var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
+ equals(_.keys(parity).join(', '), '0, 1', 'created a group for each value');
+ equals(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
+ })
test('collections: sortedIndex', function() {
var numbers = [10, 20, 30, 40, 50], num = 35;
diff --git a/underscore.js b/underscore.js
index eaba008c4..468c06a9e 100644
--- a/underscore.js
+++ b/underscore.js
@@ -250,6 +250,21 @@
return a < b ? -1 : a > b ? 1 : 0;
}), 'value');
};
+
+ // Groups the object's values by a criterion produced by an iterator
+ _.groupBy = function(obj, iterator) {
+ var result = {};
+ each(obj, function(value) {
+ var key = iterator(value);
+ if (result.hasOwnProperty(key)) {
+ result[key].push(value);
+ }
+ else {
+ result[key] = [value];
+ }
+ });
+ return result;
+ }
// Use a comparator function to figure out at what index an object should
// be inserted so as to maintain order. Uses binary search.
From b75e48c0575184680b545927775c200c84557b3e Mon Sep 17 00:00:00 2001
From: Andrei
Date: Thu, 5 May 2011 14:31:40 -0400
Subject: [PATCH 04/36] cleaned up key check in groupBy
---
underscore.js | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/underscore.js b/underscore.js
index 468c06a9e..cbcd476e4 100644
--- a/underscore.js
+++ b/underscore.js
@@ -256,12 +256,7 @@
var result = {};
each(obj, function(value) {
var key = iterator(value);
- if (result.hasOwnProperty(key)) {
- result[key].push(value);
- }
- else {
- result[key] = [value];
- }
+ (result[key] || (result[key] = [])).push(value)
});
return result;
}
From 1681d250635d099fe2d7d88e275322eecb0699af Mon Sep 17 00:00:00 2001
From: Andrei
Date: Thu, 5 May 2011 14:43:28 -0400
Subject: [PATCH 05/36] in groupBy, also pass index to iterator.
---
underscore.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/underscore.js b/underscore.js
index cbcd476e4..a0ad75eec 100644
--- a/underscore.js
+++ b/underscore.js
@@ -254,8 +254,8 @@
// Groups the object's values by a criterion produced by an iterator
_.groupBy = function(obj, iterator) {
var result = {};
- each(obj, function(value) {
- var key = iterator(value);
+ each(obj, function(value, index) {
+ var key = iterator(value, index);
(result[key] || (result[key] = [])).push(value)
});
return result;
From 6846d71f88417905ab0284e89f15e0b0a140ad2c Mon Sep 17 00:00:00 2001
From: shinuza
Date: Sat, 7 May 2011 11:24:05 +0200
Subject: [PATCH 06/36] Fixing _.any returning an incorrect result when
Array.prototype.some is missing but Array.prototype.forEach exists.
---
underscore.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/underscore.js b/underscore.js
index a0ad75eec..1119eb400 100644
--- a/underscore.js
+++ b/underscore.js
@@ -186,7 +186,10 @@
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) {
- if (result = iterator.call(context, value, index, list)) return breaker;
+ if (iterator.call(context, value, index, list)) {
+ result = true;
+ return breaker;
+ }
});
return result;
};
From 899000c21771120933e914da14ab8b2279a0d424 Mon Sep 17 00:00:00 2001
From: shinuza
Date: Sat, 7 May 2011 12:03:02 +0200
Subject: [PATCH 07/36] Hashmap keys are not necessarily ordered. groupBy test
may fail if the expected order is not correct. Fixing this by checking if the
keys are present in the hash so the order is not deterministic.
---
test/collections.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/collections.js b/test/collections.js
index e1dc5ebfc..1ca9d5de2 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -188,9 +188,9 @@ $(document).ready(function() {
test('collections: groupBy', function() {
var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
- equals(_.keys(parity).join(', '), '0, 1', 'created a group for each value');
+ ok('0' in parity && '1' in parity, 'created a group for each value');
equals(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
- })
+ });
test('collections: sortedIndex', function() {
var numbers = [10, 20, 30, 40, 50], num = 35;
From 5141a51298c0c4ef02219ec404736a425ebf3da9 Mon Sep 17 00:00:00 2001
From: shinuza
Date: Sat, 7 May 2011 16:29:43 +0200
Subject: [PATCH 08/36] Refactored fix as suggested in
https://github.com/documentcloud/underscore/issues/177
---
underscore.js | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/underscore.js b/underscore.js
index 1119eb400..d007edf57 100644
--- a/underscore.js
+++ b/underscore.js
@@ -180,19 +180,16 @@
// Determine if at least one element in the object matches a truth test.
// Delegates to **ECMAScript 5**'s native `some` if available.
// Aliased as `any`.
- var any = _.some = _.any = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
+ var any = _.some = _.any = function (obj, iterator, context) {
+ iterator = iterator || _.identity;
var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
- each(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) {
- result = true;
- return breaker;
- }
+ each(obj, function (value, index, list) {
+ if (result |= iterator.call(context, value, index, list)) return breaker;
});
- return result;
- };
+ return !!result;
+ }
// Determine if a given value is included in the array or object using `===`.
// Aliased as `contains`.
From 72c5558471000615d17a9e744684ac20453ab77e Mon Sep 17 00:00:00 2001
From: Dustin Diaz
Date: Tue, 10 May 2011 23:09:26 -0700
Subject: [PATCH 09/36] set "_" extern for use with Closure Compilers
ADVANCED_OPTIMIZATIONS
---
underscore.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/underscore.js b/underscore.js
index a0ad75eec..f7505825a 100644
--- a/underscore.js
+++ b/underscore.js
@@ -55,7 +55,7 @@
module.exports = _;
_._ = _;
} else {
- root._ = _;
+ root['_'] = _;
}
// Current version.
@@ -250,7 +250,7 @@
return a < b ? -1 : a > b ? 1 : 0;
}), 'value');
};
-
+
// Groups the object's values by a criterion produced by an iterator
_.groupBy = function(obj, iterator) {
var result = {};
From 057da5bc82f823562f7642f19bd8d2dce58c2907 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Wed, 11 May 2011 10:27:52 -0400
Subject: [PATCH 10/36] Issue #202 ... fallback method for sparse arrays.
---
test/collections.js | 6 +-----
underscore.js | 6 +++---
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/test/collections.js b/test/collections.js
index 1ca9d5de2..32a1ee1bf 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -26,10 +26,6 @@ $(document).ready(function() {
_.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
ok(answer, 'can reference the original collection from inside the iterator');
- answers = [];
- _.each({range : 1, speed : 2, length : 3}, function(v){ answers.push(v); });
- ok(answers.join(', '), '1, 2, 3', 'can iterate over objects with numeric length properties');
-
answers = 0;
_.each(null, function(){ ++answers; });
equals(answers, 0, 'handles a null properly');
@@ -185,7 +181,7 @@ $(document).ready(function() {
people = _.sortBy(people, function(person){ return person.age; });
equals(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
});
-
+
test('collections: groupBy', function() {
var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
ok('0' in parity && '1' in parity, 'created a group for each value');
diff --git a/underscore.js b/underscore.js
index a0ad75eec..2aa216835 100644
--- a/underscore.js
+++ b/underscore.js
@@ -73,7 +73,7 @@
obj.forEach(iterator, context);
} else if (_.isNumber(obj.length)) {
for (var i = 0, l = obj.length; i < l; i++) {
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
+ if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
@@ -250,7 +250,7 @@
return a < b ? -1 : a > b ? 1 : 0;
}), 'value');
};
-
+
// Groups the object's values by a criterion produced by an iterator
_.groupBy = function(obj, iterator) {
var result = {};
@@ -512,7 +512,7 @@
var funcs = slice.call(arguments);
return function() {
var args = slice.call(arguments);
- for (var i=funcs.length-1; i >= 0; i--) {
+ for (var i = funcs.length - 1; i >= 0; i--) {
args = [funcs[i].apply(this, args)];
}
return args[0];
From 910af6797ffd9197f54bce2c41735e88023f3dfd Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Wed, 11 May 2011 11:00:15 -0400
Subject: [PATCH 11/36] Fixing #185
---
index.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/index.html b/index.html
index f0c754728..9cbc3a0a7 100644
--- a/index.html
+++ b/index.html
@@ -431,8 +431,8 @@ Collection Functions (Arrays or Objects)
_.sortBy(list, iterator, [context])
- Returns a sorted list, ranked by the results of running each
- value through iterator.
+ Returns a sorted copy of list, ranked by the results of running
+ each value through iterator.
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
From 1331d814f9f27e45feefd8ca4f5ca4fd09391160 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Wed, 11 May 2011 11:02:51 -0400
Subject: [PATCH 12/36] re-adding underscore-min.js to master
---
.npmignore | 1 -
underscore-min.js | 26 ++++++++++++++++++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
create mode 100644 underscore-min.js
diff --git a/.npmignore b/.npmignore
index f5717584f..2ce268489 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,4 +1,3 @@
test/
-underscore-min.js
Rakefile
docs/
\ No newline at end of file
diff --git a/underscore-min.js b/underscore-min.js
new file mode 100644
index 000000000..54bd0649f
--- /dev/null
+++ b/underscore-min.js
@@ -0,0 +1,26 @@
+// Underscore.js 1.1.6
+// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+(function(){var p=this,C=p._,m={},i=Array.prototype,n=Object.prototype,f=i.slice,D=i.unshift,E=n.toString,l=n.hasOwnProperty,s=i.forEach,t=i.map,u=i.reduce,v=i.reduceRight,w=i.filter,x=i.every,y=i.some,o=i.indexOf,z=i.lastIndexOf;n=Array.isArray;var F=Object.keys,q=Function.prototype.bind,b=function(a){return new j(a)};typeof module!=="undefined"&&module.exports?(module.exports=b,b._=b):p._=b;b.VERSION="1.1.6";var h=b.each=b.forEach=function(a,c,d){if(a!=null)if(s&&a.forEach===s)a.forEach(c,d);else if(b.isNumber(a.length))for(var e=
+0,k=a.length;e=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,
+c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;bd?1:0}),"value")};b.groupBy=function(a,b){var d={};h(a,function(a,f){var g=b(a,f);(d[g]||(d[g]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||
+(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=f.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return function(){if(--a<1)return b.apply(this,arguments)}};b.keys=F||function(a){if(a!==Object(a))throw new TypeError("Invalid object");
+var b=[],d;for(d in a)l.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){return b.filter(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a){h(f.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){h(f.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return b.isArray(a)?a.slice():b.extend({},a)};
+b.tap=function(a,b){b(a);return a};b.isEqual=function(a,c){if(a===c)return!0;var d=typeof a;if(d!=typeof c)return!1;if(a==c)return!0;if(!a&&c||a&&!c)return!1;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return!1;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return!1;if(a.length&&
+a.length!==c.length)return!1;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return!1;for(var f in a)if(!(f in c)||!b.isEqual(a[f],c[f]))return!1;return!0};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(l.call(a,c))return!1;return!0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=n||function(a){return E.call(a)==="[object Array]"};b.isArguments=function(a){return!(!a||!l.call(a,"callee"))};b.isFunction=function(a){return!(!a||!a.constructor||
+!a.call||!a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===!0||a===!1};b.isDate=function(a){return!(!a||!a.getTimezoneOffset||!a.setUTCFullYear)};b.isRegExp=function(a){return!(!a||!a.test||!a.exec||!(a.ignoreCase||a.ignoreCase===!1))};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=
+function(){p._=C;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,
+function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return c?d(c):d};var j=function(a){this._wrapped=a};b.prototype=j.prototype;var r=function(a,c){return c?b(a).chain():a},H=function(a,c){j.prototype[a]=function(){var a=f.call(arguments);D.call(a,this._wrapped);return r(c.apply(b,
+a),this._chain)}};b.mixin(b);h(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=i[a];j.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});h(["concat","join","slice"],function(a){var b=i[a];j.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});j.prototype.chain=function(){this._chain=!0;return this};j.prototype.value=function(){return this._wrapped}})();
From bf6098f986450dad312a8ceacd3c02415e93f722 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Wed, 11 May 2011 13:08:59 -0400
Subject: [PATCH 13/36] closure-compiler comment, plus semicolons.
---
underscore.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/underscore.js b/underscore.js
index 1688e42fa..84fc889ee 100644
--- a/underscore.js
+++ b/underscore.js
@@ -55,6 +55,7 @@
module.exports = _;
_._ = _;
} else {
+ // Exported as a string, for Closure Compiler "advanced" mode.
root['_'] = _;
}
@@ -256,10 +257,10 @@
var result = {};
each(obj, function(value, index) {
var key = iterator(value, index);
- (result[key] || (result[key] = [])).push(value)
+ (result[key] || (result[key] = [])).push(value);
});
return result;
- }
+ };
// Use a comparator function to figure out at what index an object should
// be inserted so as to maintain order. Uses binary search.
From cf6cc16f4308a7055bff8140f3fe33518c01ffd7 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Fri, 13 May 2011 17:09:15 -0400
Subject: [PATCH 14/36] Issue #207 -- add Data.js to the docs.
---
index.html | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/index.html b/index.html
index 9cbc3a0a7..8e73aba63 100644
--- a/index.html
+++ b/index.html
@@ -1245,6 +1245,11 @@ Links & Suggested Reading
Functional JavaScript,
which includes comprehensive higher-order function support as well as string lambdas.
+
+
+ Michael Aufreiter's Data.js,
+ a data manipulation + persistence library for JavaScript.
+
Python's itertools.
From 40af1652ebb1b07ae1dc7e754e9872b1db5a5a5f Mon Sep 17 00:00:00 2001
From: shinuza
Date: Fri, 20 May 2011 09:13:58 +0200
Subject: [PATCH 15/36] Modified any/some test case to demonstrate issue #177
Fixed any/some formatting to be consistent with the rest of underscore.js
---
test/collections.js | 3 +++
underscore.js | 4 ++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/test/collections.js b/test/collections.js
index e1dc5ebfc..91027f217 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -132,12 +132,15 @@ $(document).ready(function() {
});
test('collections: any', function() {
+ var nativeSome = Array.prototype.some;
+ Array.prototype.some = null;
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');
ok(_.some([false, false, true]), 'aliased as "some"');
+ Array.prototype.some = nativeSome;
});
test('collections: include', function() {
diff --git a/underscore.js b/underscore.js
index d007edf57..5c707e99f 100644
--- a/underscore.js
+++ b/underscore.js
@@ -186,10 +186,10 @@
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function (value, index, list) {
- if (result |= iterator.call(context, value, index, list)) return breaker;
+ if (result |= iterator.call(context, value, index, list)) return breaker;
});
return !!result;
- }
+ };
// Determine if a given value is included in the array or object using `===`.
// Aliased as `contains`.
From 42487bf47dff4b0732977af2c6297b67ecec70af Mon Sep 17 00:00:00 2001
From: Dmitry Baranovskiy
Date: Tue, 7 Jun 2011 09:48:34 +1000
Subject: [PATCH 16/36] Fixed isEqual if second object has isEqual implemented
and added isObject method
---
test/objects.js | 17 +++++++++++++++++
underscore.js | 6 ++++++
2 files changed, 23 insertions(+)
diff --git a/test/objects.js b/test/objects.js
index 93c441176..48971c079 100644
--- a/test/objects.js
+++ b/test/objects.js
@@ -77,6 +77,8 @@ $(document).ready(function() {
ok(_.isEqual(new Date(100), new Date(100)), 'identical dates are equal');
ok(_.isEqual((/hello/ig), (/hello/ig)), 'identical regexes are equal');
ok(!_.isEqual(null, [1]), 'a falsy is never equal to a truthy');
+ ok(_.isEqual({isEqual: function () { return true; }}, {}), 'first object implements `isEqual`');
+ ok(_.isEqual({}, {isEqual: function () { return true; }}), 'second object implements `isEqual`');
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), 'objects with the same number of undefined keys are not equal');
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'wrapped objects are not equal');
equals(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, 'wrapped objects are equal');
@@ -136,6 +138,21 @@ $(document).ready(function() {
ok(_.isArguments(iArguments), 'even from another frame');
});
+ test("objects: isObject", function() {
+ ok(_.isObject(arguments), 'the arguments object is object');
+ ok(_.isObject([1, 2, 3]), 'and arrays');
+ ok(_.isObject($('html')[0]), 'and DOM element');
+ ok(_.isObject(iElement), 'even from another frame');
+ ok(_.isObject(function () {}), 'and functions');
+ ok(_.isObject(iFunction), 'even from another frame');
+ ok(!_.isObject(null), 'but not null');
+ ok(!_.isObject(undefined), 'and not undefined');
+ ok(!_.isObject('string'), 'and not string');
+ ok(!_.isObject(12), 'and not number');
+ ok(!_.isObject(true), 'and not boolean');
+ ok(_.isObject(new String('string')), 'but new String()');
+ });
+
test("objects: isArray", function() {
ok(!_.isArray(arguments), 'the arguments object is not an array');
ok(_.isArray([1, 2, 3]), 'but arrays are');
diff --git a/underscore.js b/underscore.js
index 84fc889ee..61fdb6ed5 100644
--- a/underscore.js
+++ b/underscore.js
@@ -600,6 +600,7 @@
if (b._chain) b = b._wrapped;
// One of them implements an isEqual()?
if (a.isEqual) return a.isEqual(b);
+ if (b.isEqual) return b.isEqual(a);
// Check dates' integer values.
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
// Both are NaN?
@@ -641,6 +642,11 @@
return toString.call(obj) === '[object Array]';
};
+ // Is a given variable an object?
+ _.isObject = function(obj) {
+ return obj === Object(obj);
+ };
+
// Is a given variable an arguments object?
_.isArguments = function(obj) {
return !!(obj && hasOwnProperty.call(obj, 'callee'));
From b949d0345f11f67310cc06ff72a926f7814942a3 Mon Sep 17 00:00:00 2001
From: Cat Chen
Date: Mon, 20 Jun 2011 22:30:35 +0800
Subject: [PATCH 17/36] updated _.delay test to use setTimeout to verify
_.delay's behavior
---
test/functions.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/functions.js b/test/functions.js
index 95267e73a..2a1bd51bd 100644
--- a/test/functions.js
+++ b/test/functions.js
@@ -73,8 +73,8 @@ $(document).ready(function() {
asyncTest("functions: delay", 2, function() {
var delayed = false;
_.delay(function(){ delayed = true; }, 100);
- _.delay(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
- _.delay(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
+ setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
+ setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
});
asyncTest("functions: defer", 1, function() {
From 0202f9f79b882723e3aa19598cc31492c07c3096 Mon Sep 17 00:00:00 2001
From: Florian Friesdorf
Date: Tue, 21 Jun 2011 18:31:40 +0200
Subject: [PATCH 18/36] make toArray return a clone in case of an array
In combination with backbone this makes coll.toArray() return an array
instead of just returning coll.models, enabling
coll.remove(coll.toArray()) whithout failing half way through.
---
test/collections.js | 3 +++
underscore.js | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/test/collections.js b/test/collections.js
index 32a1ee1bf..912abaf26 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -197,6 +197,9 @@ $(document).ready(function() {
test('collections: toArray', function() {
ok(!_.isArray(arguments), 'arguments object is not an array');
ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
+ var a = [1,2,3];
+ ok(_.toArray(a) !== a, 'array is cloned');
+ equals(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements');
var numbers = _.toArray({one : 1, two : 2, three : 3});
equals(numbers.join(', '), '1, 2, 3', 'object flattened into array');
diff --git a/underscore.js b/underscore.js
index 61fdb6ed5..804a005e2 100644
--- a/underscore.js
+++ b/underscore.js
@@ -278,7 +278,7 @@
_.toArray = function(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
- if (_.isArray(iterable)) return iterable;
+ if (_.isArray(iterable)) return slice.call(iterable);
if (_.isArguments(iterable)) return slice.call(iterable);
return _.values(iterable);
};
From 9ab3ac44bbb39d21bb0ec1334fe9901e5b3f42bc Mon Sep 17 00:00:00 2001
From: Florian Friesdorf
Date: Sat, 25 Jun 2011 09:01:51 +0200
Subject: [PATCH 19/36] move underscore test into a div
more comfortable to include underscore with tests in some other project.
---
test/collections.js | 2 +-
test/test.html | 35 ++++++++++++++++++-----------------
2 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/test/collections.js b/test/collections.js
index 912abaf26..9a4d49ec4 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -41,7 +41,7 @@ $(document).ready(function() {
var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
equals(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
- var ids = _.map(document.body.childNodes, function(n){ return n.id; });
+ var ids = _.map($('div.underscore-test').children(), function(n){ return n.id; });
ok(_.include(ids, 'qunit-header'), 'can use collection methods on NodeLists');
var ids = _.map(document.images, function(n){ return n.id; });
diff --git a/test/test.html b/test/test.html
index c67acf596..f8609aa26 100644
--- a/test/test.html
+++ b/test/test.html
@@ -16,26 +16,27 @@
-
-
-
-
-
-
-
- A representative sample of the functions are benchmarked here, to provide
- a sense of how fast they might run in different browsers.
- Each iteration runs on an array of 1000 elements.
- For example, the 'intersect' test measures the number of times you can
- find the intersection of two thousand-element arrays in one second.
-
-
+
+
+
+
+
+
+
+
+ A representative sample of the functions are benchmarked here, to provide
+ a sense of how fast they might run in different browsers.
+ Each iteration runs on an array of 1000 elements.
+ For example, the 'intersect' test measures the number of times you can
+ find the intersection of two thousand-element arrays in one second.
+
+
-
-
+
+