diff --git a/index.html b/index.html
index 55a74a7db..f0bc7a335 100644
--- a/index.html
+++ b/index.html
@@ -107,11 +107,11 @@
@@ -202,7 +202,8 @@ _(lyrics).chain()
keys, values,
extend, clone,
isEqual, isEmpty, isElement,
- isArray, isFunction, isUndefined
+ isArray, isFunction, isString,
+ isNumber, isUndefined
@@ -763,6 +764,26 @@ _.isArray([1,2,3]);
_.isFunction(alert);
=> true
+
+
+
+ _.isString(object)
+
+ Returns true if object is a String.
+
+
+_.isFunction("moe");
+=> true
+
+
+
+ _.isNumber(object)
+
+ Returns true if object is a Number.
+
+
+_.isNumber(8.4 * 5);
+=> true
@@ -891,6 +912,12 @@ _([1, 2, 3]).value();
Change Log
+
+
+ Added isString, and isNumber, for consistency. Fixed
+ _.isEqual(NaN, NaN) to return true (which is debatable).
+
+
Started using the native StopIteration object in browsers that support it.
diff --git a/test/objects.js b/test/objects.js
index 489c39f2a..d76d3e8e2 100644
--- a/test/objects.js
+++ b/test/objects.js
@@ -1,68 +1,80 @@
$(document).ready(function() {
-
+
module("Object functions (values, extend, isEqual, and so on...)");
-
+
test("objects: keys", function() {
equals(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object');
});
-
+
test("objects: values", function() {
equals(_.values({one : 1, two : 2}).join(', '), '1, 2', 'can extract the values from an object');
});
-
+
test("objects: extend", function() {
var source = {name : 'moe'}, dest = {age : 50};
_.extend(dest, source);
equals(dest.name, 'moe', 'can extend an object with the attributes of another');
});
-
+
test("objects: clone", function() {
var moe = {name : 'moe', lucky : [13, 27, 34]};
var clone = _.clone(moe);
equals(clone.name, 'moe', 'the clone as the attributes of the original');
-
+
clone.name = 'curly';
ok(clone.name == 'curly' && moe.name == 'moe', 'clones can change shallow attributes without affecting the original');
-
+
clone.lucky.push(101);
equals(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original');
});
-
+
test("objects: isEqual", function() {
var moe = {name : 'moe', lucky : [13, 27, 34]};
var clone = {name : 'moe', lucky : [13, 27, 34]};
ok(moe != clone, 'basic equality between objects is false');
ok(_.isEqual(moe, clone), 'deep equality is true');
ok(_(moe).isEqual(clone), 'OO-style deep equality works');
+ ok(!_.isEqual(5, NaN), '5 is not equal to NaN');
+ ok(_.isEqual(NaN, NaN), 'NaN is equal to NaN');
});
-
+
test("objects: isEmpty", function() {
ok(!_([1]).isEmpty(), '[1] is not empty');
ok(_.isEmpty([]), '[] is empty');
ok(!_.isEmpty({one : 1}), '{one : 1} is not empty');
ok(_.isEmpty({}), '{} is empty');
-
+
var obj = {one : 1};
delete obj.one;
ok(_.isEmpty(obj), 'deleting all the keys from an object empties it');
});
-
+
test("objects: isElement", function() {
ok(!_.isElement('div'), 'strings are not dom elements');
ok(_.isElement($('html')[0]), 'the html tag is a DOM element');
});
-
+
test("objects: isArray", function() {
ok(!_.isArray(arguments), 'the arguments object is not an array');
ok(_.isArray([1, 2, 3]), 'but arrays are');
});
-
+
+ test("objects: isString", function() {
+ ok(!_.isString(document.body), 'the document body is not a string');
+ ok(_.isString([1, 2, 3].join(', ')), 'but strings are');
+ });
+
+ test("objects: isNumber", function() {
+ ok(!_.isNumber(arguments), 'the arguments object is not a number');
+ ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are');
+ });
+
test("objects: isFunction", function() {
ok(!_.isFunction([1, 2, 3]), 'arrays are not functions');
ok(!_.isFunction('moe'), 'strings are not functions');
ok(_.isFunction(_.isFunction), 'but functions are');
});
-
+
test("objects: isUndefined", function() {
ok(!_.isUndefined(1), 'numbers are defined');
ok(!_.isUndefined(null), 'null is defined');
diff --git a/test/test.html b/test/test.html
index 30ac9098f..ea26345fb 100644
--- a/test/test.html
+++ b/test/test.html
@@ -13,7 +13,7 @@
-
+
diff --git a/test/utility.js b/test/utility.js
index 4515ba4c4..ed6ee120b 100644
--- a/test/utility.js
+++ b/test/utility.js
@@ -1,7 +1,7 @@
$(document).ready(function() {
-
+
module("Utility functions (uniqueId, template)");
-
+
test("utility: noConflict", function() {
var underscore = _.noConflict();
ok(underscore.isUndefined(_), "The '_' variable has been returned to its previous state.");
@@ -9,12 +9,12 @@ $(document).ready(function() {
equals(intersection.join(', '), '1, 2', 'but the intersection function still works');
window._ = underscore;
});
-
+
test("utility: identity", function() {
var moe = {name : 'moe'};
equals(_.identity(moe), moe, 'moe is the same as his identity');
});
-
+
test('utility: breakLoop', function() {
var result = null;
_([1,2,3,4,5,6]).each(function(num) {
@@ -23,25 +23,25 @@ $(document).ready(function() {
});
equals(result, 3, 'broke out of a loop');
});
-
+
test("utility: uniqueId", function() {
var ids = [], i = 0;
while(i++ < 100) ids.push(_.uniqueId());
equals(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids');
});
-
+
test("utility: functions", function() {
- var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact", "compose",
- "defer", "delay", "detect", "each", "every", "extend", "filter", "first",
- "flatten", "foldl", "foldr", "forEach", "functions", "identity", "include",
- "indexOf", "inject", "intersect", "invoke", "isArray", "isElement", "isEmpty", "isEqual",
- "isFunction", "isUndefined", "keys", "last", "lastIndexOf", "map", "max",
- "methods", "min", "pluck", "reduce", "reduceRight", "reject", "select",
- "size", "some", "sortBy", "sortedIndex", "template", "toArray", "uniq",
+ var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact", "compose",
+ "defer", "delay", "detect", "each", "every", "extend", "filter", "first",
+ "flatten", "foldl", "foldr", "forEach", "functions", "identity", "include",
+ "indexOf", "inject", "intersect", "invoke", "isArray", "isElement", "isEmpty", "isEqual",
+ "isFunction", "isNumber", "isString", "isUndefined", "keys", "last", "lastIndexOf", "map", "max",
+ "methods", "min", "pluck", "reduce", "reduceRight", "reject", "select",
+ "size", "some", "sortBy", "sortedIndex", "template", "toArray", "uniq",
"uniqueId", "values", "without", "wrap", "zip"];
ok(_(expected).isEqual(_.methods()), 'provides a sorted list of functions');
});
-
+
test("utility: template", function() {
var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
var result = basicTemplate({thing : 'This'});
@@ -50,5 +50,5 @@ $(document).ready(function() {
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equals(result, "MoeLarryCurly", 'can run arbitrary javascript in templates');
});
-
+
});
diff --git a/underscore-min.js b/underscore-min.js
index dcc64d912..dbaff85cd 100644
--- a/underscore-min.js
+++ b/underscore-min.js
@@ -1 +1,14 @@
-(function(){var c=this;var e=c._;var g=function(h){this._wrapped=h};var f=typeof StopIteration!=="undefined"?StopIteration:"__break__";var d=c._=function(h){return new g(h)};if(typeof exports!=="undefined"){exports._=d}d.VERSION="0.4.3";d.each=function(q,o,n){var j=0;try{if(q.forEach){q.forEach(o,n)}else{if(q.length){for(var m=0,h=q.length;m=h.computed&&(h={value:o,computed:m})});return h.value};d.min=function(k,j,i){if(!j&&d.isArray(k)){return Math.min.apply(Math,k)}var h={computed:Infinity};d.each(k,function(o,l,n){var m=j?j.call(i,o,l,n):o;mk?1:0}),"value")};d.sortedIndex=function(m,l,j){j=j||d.identity;var h=0,k=m.length;while(h>1;j(m[i])=0})})};d.zip=function(){var h=d.toArray(arguments);var l=d.max(d.pluck(h,"length"));var k=new Array(l);for(var j=0;j=0;j--){arguments=[h[j].apply(this,arguments)]}return arguments[0]}};d.keys=function(h){return d.map(h,function(j,i){return i})};d.values=function(h){return d.map(h,d.identity)};d.extend=function(h,j){for(var i in j){h[i]=j[i]}return h};d.clone=function(h){if(d.isArray(h)){return h.slice(0)}return d.extend({},h)};d.isEqual=function(i,h){if(i===h){return true}var l=typeof(i),n=typeof(h);if(l!=n){return false}if(i==h){return true}if(i.isEqual){return i.isEqual(h)}if(l!=="object"){return false}var j=d.keys(i),m=d.keys(h);if(j.length!=m.length){return false}for(var k in i){if(!d.isEqual(i[k],h[k])){return false}}return true};d.isEmpty=function(h){return(d.isArray(h)?h:d.values(h)).length==0};d.isElement=function(h){return !!(h&&h.nodeType==1)};d.isArray=function(h){return Object.prototype.toString.call(h)=="[object Array]"};d.isFunction=function(h){return Object.prototype.toString.call(h)=="[object Function]"};d.isUndefined=function(h){return typeof h=="undefined"};d.noConflict=function(){c._=e;return this};d.identity=function(h){return h};d.breakLoop=function(){throw f};var b=0;d.uniqueId=function(h){var i=b++;return h?h+i:i};d.functions=function(){var i=[];for(var h in d){if(Object.prototype.hasOwnProperty.call(d,h)){i.push(h)}}return d.without(i,"VERSION","prototype","noConflict").sort()};d.template=function(j,i){var h=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+j.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return i?h(i):h};d.forEach=d.each;d.foldl=d.inject=d.reduce;d.foldr=d.reduceRight;d.filter=d.select;d.every=d.all;d.some=d.any;d.methods=d.functions;var a=function(i,h){return h?d(i).chain():i};d.each(d.functions(),function(h){g.prototype[h]=function(){Array.prototype.unshift.call(arguments,this._wrapped);return a(d[h].apply(d,arguments),this._chain)}});d.each(["pop","push","reverse","shift","sort","splice","unshift"],function(h){g.prototype[h]=function(){Array.prototype[h].apply(this._wrapped,arguments);return a(this._wrapped,this._chain)}});d.each(["concat","join","slice"],function(h){g.prototype[h]=function(){return a(Array.prototype[h].apply(this._wrapped,arguments),this._chain)}});g.prototype.chain=function(){this._chain=true;return this};g.prototype.value=function(){return this._wrapped}})();
\ No newline at end of file
+(function(){var j=this,m=j._;function i(a){this._wrapped=a}var l=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;b.VERSION="0.4.4";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(a.length)for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});
+return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gf?1:0}),"value")};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=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e=0;c--)arguments=[a[c].apply(this,arguments)];return arguments[0]}};b.keys=function(a){return b.map(a,function(c,d){return d})};b.values=function(a){return b.map(a,b.identity)};b.extend=function(a,c){for(var d in c)a[d]=
+c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a,e=typeof c;if(d!=e)return false;if(a==c)return true;if(a.isEqual)return a.isEqual(c);if(b.isNumber(a)&&b.isNumber(c)&&isNaN(a)&&isNaN(c))return true;if(d!=="object")return false;d=b.keys(a);e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return(b.isArray(a)?a:b.values(a)).length==
+0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return Object.prototype.toString.call(a)=="[object Array]"};b.isFunction=function(a){return Object.prototype.toString.call(a)=="[object Function]"};b.isString=function(a){return Object.prototype.toString.call(a)=="[object String]"};b.isNumber=function(a){return Object.prototype.toString.call(a)=="[object Number]"};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=m;return this};b.identity=
+function(a){return a};b.breakLoop=function(){throw l;};var n=0;b.uniqueId=function(a){var c=n++;return a?a+c:c};b.functions=function(){var a=[];for(var c in b)Object.prototype.hasOwnProperty.call(b,c)&&a.push(c);return b.without(a,"VERSION","prototype","noConflict").sort()};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,
+"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.methods=b.functions;function k(a,c){return c?b(a).chain():a}b.each(b.functions(),function(a){i.prototype[a]=function(){Array.prototype.unshift.call(arguments,this._wrapped);return k(b[a].apply(b,arguments),this._chain)}});b.each(["pop","push","reverse","shift",
+"sort","splice","unshift"],function(a){i.prototype[a]=function(){Array.prototype[a].apply(this._wrapped,arguments);return k(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){i.prototype[a]=function(){return k(Array.prototype[a].apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
diff --git a/underscore.js b/underscore.js
index 4a85af41f..ac1b8659d 100644
--- a/underscore.js
+++ b/underscore.js
@@ -31,7 +31,7 @@
if (typeof exports !== 'undefined') exports._ = _;
// Current version.
- _.VERSION = '0.4.3';
+ _.VERSION = '0.4.4';
/*------------------------ Collection Functions: ---------------------------*/
@@ -399,6 +399,8 @@
if (a == b) return true;
// One of them implements an isEqual()?
if (a.isEqual) return a.isEqual(b);
+ // Both are NaN?
+ if (_.isNumber(a) && _.isNumber(b) && isNaN(a) && isNaN(b)) return true;
// If a is not an object by this point, we can't handle it.
if (atype !== 'object') return false;
// Nothing else worked, deep compare the contents.
@@ -430,6 +432,16 @@
return Object.prototype.toString.call(obj) == '[object Function]';
};
+ // Is a given value a String?
+ _.isString = function(obj) {
+ return Object.prototype.toString.call(obj) == '[object String]';
+ };
+
+ // Is a given value a Number?
+ _.isNumber = function(obj) {
+ return Object.prototype.toString.call(obj) == '[object Number]';
+ };
+
// Is a given variable undefined?
_.isUndefined = function(obj) {
return typeof obj == 'undefined';