Permalink
Comparing changes
Choose two branches to see what’s changed or to start a new pull request.
If you need to, you can also .
Open a pull request
Create a new pull request by comparing changes across two branches. If you need to, you can also .
- 3 commits
- 7 files changed
- 0 comments
- 1 contributor
Commits on Nov 13, 2009
Commits on Nov 14, 2009
Commits on Nov 18, 2009
Unified
Split
Showing
with
137 additions
and 73 deletions.
- +30 −3 index.html
- +37 −37 test/collections.js
- +26 −14 test/objects.js
- +1 −1 test/test.html
- +15 −15 test/utility.js
- +14 −1 underscore-min.js
- +14 −2 underscore.js
@@ -107,11 +107,11 @@ <h2>Downloads <i style="padding-left: 12px; font-size:12px;">(Right-click, and u | ||
<p> | ||
<table> | ||
<tr> | ||
<td><a href="underscore.js">Development Version (0.4.3)</a></td> | ||
<td><a href="underscore.js">Development Version (0.4.4)</a></td> | ||
<td><i>18kb, Uncompressed with Comments</i></td> | ||
</tr> | ||
<tr> | ||
<td><a href="underscore-min.js">Production Version (0.4.3)</a></td> | ||
<td><a href="underscore-min.js">Production Version (0.4.4)</a></td> | ||
<td><i>2kb, Packed and Gzipped</i></td> | ||
</tr> | ||
</table> | ||
@@ -202,7 +202,8 @@ <h2>Table of Contents</h2> | ||
<span class="methods"><a href="#keys">keys</a>, <a href="#values">values</a>, | ||
<a href="#extend">extend</a>, <a href="#clone">clone</a>, | ||
<a href="#isEqual">isEqual</a>, <a href="#isEmpty">isEmpty</a>, <a href="#isElement">isElement</a>, | ||
<a href="#isArray">isArray</a>, <a href="#isFunction">isFunction</a>, <a href="#isUndefined">isUndefined</a> | ||
<a href="#isArray">isArray</a>, <a href="#isFunction">isFunction</a>, <a href="#isString">isString</a>, | ||
<a href="#isNumber">isNumber</a>, <a href="#isUndefined">isUndefined</a> | ||
</span> | ||
</p> | ||
|
||
@@ -763,6 +764,26 @@ <h2>Object Functions</h2> | ||
<pre> | ||
_.isFunction(alert); | ||
=> true | ||
</pre> | ||
|
||
<p id="isString"> | ||
<b class="header">isString</b><code>_.isString(object)</code> | ||
<br /> | ||
Returns <i>true</i> if <b>object</b> is a String. | ||
</p> | ||
<pre> | ||
_.isFunction("moe"); | ||
=> true | ||
</pre> | ||
|
||
<p id="isNumber"> | ||
<b class="header">isNumber</b><code>_.isNumber(object)</code> | ||
<br /> | ||
Returns <i>true</i> if <b>object</b> is a Number. | ||
</p> | ||
<pre> | ||
_.isNumber(8.4 * 5); | ||
=> true | ||
</pre> | ||
|
||
<p id="isUndefined"> | ||
@@ -891,6 +912,12 @@ <h2>Chaining</h2> | ||
|
||
<h2>Change Log</h2> | ||
|
||
<p> | ||
<b class="header">0.4.4</b><br /> | ||
Added <tt>isString</tt>, and <tt>isNumber</tt>, for consistency. Fixed | ||
<tt>_.isEqual(NaN, NaN)</tt> to return <i>true</i> (which is debatable). | ||
</p> | ||
|
||
<p> | ||
<b class="header">0.4.3</b><br /> | ||
Started using the native StopIteration object in browsers that support it. | ||
@@ -1,89 +1,89 @@ | ||
$(document).ready(function() { | ||
|
||
module("Collection functions (each, any, select, and so on...)"); | ||
|
||
test("collections: each", function() { | ||
_.each([1, 2, 3], function(num, i) { | ||
equals(num, i + 1, 'each iterators provide value and iteration count'); | ||
}); | ||
|
||
var answer = null; | ||
_.each([1, 2, 3], function(num){ if ((answer = num) == 2) throw '__break__'; }); | ||
_.each([1, 2, 3], function(num){ if ((answer = num) == 2) _.breakLoop(); }); | ||
equals(answer, 2, 'the loop broke in the middle'); | ||
|
||
var answers = []; | ||
_.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5}); | ||
equals(answers.join(', '), '5, 10, 15', 'context object property accessed'); | ||
|
||
answers = []; | ||
_.each("moe", function(letter){ answers.push(letter); }); | ||
equals(answers.join(', '), 'm, o, e', 'iterates over the letters in strings'); | ||
|
||
answers = []; | ||
_.forEach([1, 2, 3], function(num){ answers.push(num); }); | ||
equals(answers.join(', '), '1, 2, 3', 'aliased as "forEach"'); | ||
|
||
answers = []; | ||
var obj = {one : 1, two : 2, three : 3}; | ||
obj.constructor.prototype.four = 4; | ||
_.each(obj, function(value, key){ answers.push(key); }); | ||
equals(answers.join(", "), 'one, two, three', 'iterating over objects works, and ignores the object prototype.'); | ||
delete obj.constructor.prototype.four; | ||
|
||
answer = null; | ||
_.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'); | ||
ok(answer, 'can reference the original collection from inside the iterator'); | ||
}); | ||
|
||
test('collections: map', function() { | ||
var doubled = _.map([1, 2, 3], function(num){ return num * 2; }); | ||
equals(doubled.join(', '), '2, 4, 6', 'doubled numbers'); | ||
|
||
var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3}); | ||
equals(tripled.join(', '), '3, 6, 9', 'tripled numbers with context'); | ||
|
||
var doubled = _([1, 2, 3]).map(function(num){ return num * 2; }); | ||
equals(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers'); | ||
}); | ||
|
||
test('collections: reduce', function() { | ||
var sum = _.reduce([1, 2, 3], 0, function(sum, num){ return sum + num; }); | ||
equals(sum, 6, 'can sum up an array'); | ||
|
||
var context = {multiplier : 3}; | ||
sum = _.reduce([1, 2, 3], 0, function(sum, num){ return sum + num * this.multiplier; }, context); | ||
equals(sum, 18, 'can reduce with a context object'); | ||
|
||
sum = _.inject([1, 2, 3], 0, function(sum, num){ return sum + num; }); | ||
equals(sum, 6, 'aliased as "inject"'); | ||
|
||
sum = _([1, 2, 3]).reduce(0, function(sum, num){ return sum + num; }); | ||
equals(sum, 6, 'OO-style reduce'); | ||
}); | ||
|
||
test('collections: reduceRight', function() { | ||
var list = _.foldr([1, 2, 3], '', function(memo, num){ return memo + num; }); | ||
equals(list, '321', 'can perform right folds'); | ||
}); | ||
|
||
test('collections: detect', function() { | ||
var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; }); | ||
equals(result, 2, 'found the first "2" and broke the loop'); | ||
}); | ||
|
||
test('collections: select', function() { | ||
var evens = _.select([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); | ||
equals(evens.join(', '), '2, 4, 6', 'selected each even number'); | ||
|
||
evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); | ||
equals(evens.join(', '), '2, 4, 6', 'aliased as "filter"'); | ||
}); | ||
|
||
test('collections: reject', function() { | ||
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); | ||
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'); | ||
@@ -92,7 +92,7 @@ $(document).ready(function() { | ||
ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number'); | ||
ok(_.every([true, true, true]), 'aliased as "every"'); | ||
}); | ||
|
||
test('collections: any', function() { | ||
ok(!_.any([]), 'the empty set'); | ||
ok(!_.any([false, false, false]), 'all false values'); | ||
@@ -101,62 +101,62 @@ $(document).ready(function() { | ||
ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number'); | ||
ok(_.some([false, false, true]), 'aliased as "some"'); | ||
}); | ||
|
||
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'); | ||
ok(_.include({moe:1, larry:3, curly:9}, 3), '_.include on objects checks their values'); | ||
ok(_([1,2,3]).include(2), 'OO-style include'); | ||
}); | ||
|
||
test('collections: invoke', function() { | ||
var list = [[5, 1, 7], [3, 2, 1]]; | ||
var result = _.invoke(list, 'sort'); | ||
equals(result[0].join(', '), '1, 5, 7', 'first array sorted'); | ||
equals(result[1].join(', '), '1, 2, 3', 'second array sorted'); | ||
}); | ||
|
||
test('collections: pluck', function() { | ||
var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}]; | ||
equals(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects'); | ||
}); | ||
|
||
test('collections: max', function() { | ||
equals(3, _.max([1, 2, 3]), 'can perform a regular Math.max'); | ||
|
||
var neg = _.max([1, 2, 3], function(num){ return -num; }); | ||
equals(neg, 1, 'can perform a computation-based max'); | ||
}); | ||
|
||
test('collections: min', function() { | ||
equals(1, _.min([1, 2, 3]), 'can perform a regular Math.min'); | ||
|
||
var neg = _.min([1, 2, 3], function(num){ return -num; }); | ||
equals(neg, 3, 'can perform a computation-based min'); | ||
}); | ||
|
||
test('collections: sortBy', function() { | ||
var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}]; | ||
people = _.sortBy(people, function(person){ return person.age; }); | ||
equals(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age'); | ||
}); | ||
|
||
test('collections: sortedIndex', function() { | ||
var numbers = [10, 20, 30, 40, 50], num = 35; | ||
var index = _.sortedIndex(numbers, num); | ||
equals(index, 3, '35 should be inserted at index 3'); | ||
}); | ||
|
||
test('collections: toArray', function() { | ||
ok(!_.isArray(arguments), 'arguments object is not an array'); | ||
ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); | ||
|
||
var numbers = _.toArray({one : 1, two : 2, three : 3}); | ||
equals(numbers.join(', '), '1, 2, 3', 'object flattened into array'); | ||
}); | ||
|
||
test('collections: size', function() { | ||
equals(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object'); | ||
}); | ||
|
||
}); |
@@ -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'); | ||
@@ -13,7 +13,7 @@ | ||
<script type="text/javascript" src="objects.js"></script> | ||
<script type="text/javascript" src="utility.js"></script> | ||
<script type="text/javascript" src="chaining.js"></script> | ||
<script type="text/javascript" src="speed.js"></script> | ||
<script type="text/javascript" src="speed.js"></script> | ||
</head> | ||
<body> | ||
<h1 id="qunit-header">Underscore Test Suite</h1> | ||
Oops, something went wrong.