diff --git a/README b/README
index 333b13f45..c7eb97bd1 100644
--- a/README
+++ b/README
@@ -27,5 +27,6 @@ Many thanks to our contributors:
Kris Kowal
Jed Schmidt
Noah Sloan
+ Nick Stenning
Luke Sutton
John Wright
diff --git a/index.html b/index.html
index 289bbb520..597d8f602 100644
--- a/index.html
+++ b/index.html
@@ -110,12 +110,12 @@
Downloads (Right-click, and u
@@ -216,10 +216,10 @@ Object-Oriented and Functional Styles
_(lyrics).chain()
.map(function(line) { return line.words.split(' '); })
.flatten()
- .reduce({}, function(counts, word) {
+ .reduce(function(counts, word) {
counts[word] = (counts[word] || 0) + 1;
return counts;
-}).value();
+}, {}).value();
=> {lumberjack : 2, all : 4, night : 2 ... }
@@ -261,7 +261,7 @@ Collection Functions (Arrays or Objects)
=> [3, 6, 9]
- _.reduce(list, memo, iterator, [context])
+ _.reduce(list, iterator, memo, [context])
Aliases: inject, foldl
Also known as inject and foldl, reduce boils down a
@@ -270,12 +270,12 @@
Collection Functions (Arrays or Objects)
iterator.
-var sum = _.reduce([1, 2, 3], 0, function(memo, num){ return memo + num });
+var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num }, 0);
=> 6
- _.reduceRight(list, memo, iterator, [context])
+ _.reduceRight(list, iterator, memo, [context])
Alias: foldr
The right-associative version of reduce. Delegates to the
@@ -285,7 +285,7 @@
Collection Functions (Arrays or Objects)
var list = [[0, 1], [2, 3], [4, 5]];
-var flat = _.reduceRight(list, [], function(a, b) { return a.concat(b); });
+var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
=> [4, 5, 2, 3, 0, 1]
@@ -356,6 +356,7 @@ Collection Functions (Arrays or Objects)
_.include(list, value)
+ Alias: contains
Returns true if the value is present in the list, using
=== to test equality. Uses indexOf internally, if list
@@ -1128,6 +1129,13 @@
Links & Suggested Reading
The source is
available on GitHub.
+
+
+ Underscore.strings,
+ an Underscore extension that adds functions for string-manipulation:
+ trim, startsWith, contains, capitalize,
+ reverse, sprintf, and more.
+
Ruby's Enumerable module.
@@ -1150,10 +1158,20 @@
Links & Suggested Reading
Change Log
+
+
+ The method signature of _.reduce has been changed to match
+ the ECMAScript 5 signature, instead of the Ruby/Prototype.js version.
+ This is a backwards-incompatible change. _.template may now be
+ called with no arguments, and preserves whitespace. _.contains
+ is a new alias for _.include.
+
+
- Andri Möll contributed the _.memoize function, which can be
- used to speed up expensive repeated computations by caching the results.
+ Andri Möll contributed the _.memoize
+ function, which can be used to speed up expensive repeated computations
+ by caching the results.
@@ -1248,7 +1266,8 @@
Change Log
Added an _.isArguments function. Lots of little safety checks
and optimizations contributed by
- Noah Sloan and Andri Möll.
+ Noah Sloan and
+ Andri Möll.
diff --git a/package.json b/package.json
index 5a1d90d4a..f00dacc03 100644
--- a/package.json
+++ b/package.json
@@ -8,5 +8,5 @@
"dependencies" : [],
"lib" : ".",
"main" : "underscore.js",
- "version" : "1.0.4"
+ "version" : "1.1.0"
}
diff --git a/test/chaining.js b/test/chaining.js
index 55f0c8c0d..e633ba5ad 100644
--- a/test/chaining.js
+++ b/test/chaining.js
@@ -12,11 +12,11 @@ $(document).ready(function() {
var counts = _(lyrics).chain()
.map(function(line) { return line.split(''); })
.flatten()
- .reduce({}, function(hash, l) {
+ .reduce(function(hash, l) {
hash[l] = hash[l] || 0;
hash[l]++;
return hash;
- }).value();
+ }, {}).value();
ok(counts['a'] == 16 && counts['e'] == 10, 'counted all the letters in the song');
});
diff --git a/test/collections.js b/test/collections.js
index 3759a6495..9c72e889e 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -53,22 +53,22 @@ $(document).ready(function() {
});
test('collections: reduce', function() {
- var sum = _.reduce([1, 2, 3], 0, function(sum, num){ return sum + num; });
+ var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }, 0);
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);
+ sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num * this.multiplier; }, 0, context);
equals(sum, 18, 'can reduce with a context object');
- sum = _.inject([1, 2, 3], 0, function(sum, num){ return sum + num; });
+ sum = _.inject([1, 2, 3], function(sum, num){ return sum + num; }, 0);
equals(sum, 6, 'aliased as "inject"');
- sum = _([1, 2, 3]).reduce(0, function(sum, num){ return sum + num; });
+ sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0);
equals(sum, 6, 'OO-style reduce');
});
test('collections: reduceRight', function() {
- var list = _.foldr([1, 2, 3], '', function(memo, num){ return memo + num; });
+ var list = _.foldr([1, 2, 3], function(memo, num){ return memo + num; }, '');
equals(list, '321', 'can perform right folds');
});
@@ -111,7 +111,7 @@ $(document).ready(function() {
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(_.contains({moe:1, larry:3, curly:9}, 3), '_.include on objects checks their values');
ok(_([1,2,3]).include(2), 'OO-style include');
});
diff --git a/test/objects.js b/test/objects.js
index 7dadb8476..fc9c93d42 100644
--- a/test/objects.js
+++ b/test/objects.js
@@ -12,7 +12,7 @@ $(document).ready(function() {
test("objects: functions", function() {
var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact",
- "compose","defer", "delay", "detect", "each", "every", "extend", "filter", "first",
+ "compose", "contains", "defer", "delay", "detect", "each", "every", "extend", "filter", "first",
"flatten", "foldl", "foldr", "forEach", "functions", "head", "identity", "include",
"indexOf", "inject", "intersect", "invoke", "isArguments", "isArray", "isBoolean", "isDate", "isElement", "isEmpty", "isEqual",
"isFunction", "isNaN", "isNull", "isNumber", "isRegExp", "isString", "isUndefined", "keys", "last", "lastIndexOf", "map", "max",
diff --git a/test/utility.js b/test/utility.js
index c9498c227..8670a9fda 100644
--- a/test/utility.js
+++ b/test/utility.js
@@ -59,12 +59,19 @@ $(document).ready(function() {
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equals(result, "
", 'can run arbitrary javascript in templates');
+ var noInterpolateTemplate = _.template("Just some text. Hey, I know this is silly but it aids consistency.
");
+ result = noInterpolateTemplate();
+ equals(result, "Just some text. Hey, I know this is silly but it aids consistency.
");
+
var quoteTemplate = _.template("It's its, not it's");
equals(quoteTemplate({}), "It's its, not it's");
var quoteInStatementAndBody = _.template("<% if(foo == 'bar'){ %>Statement quotes and 'quotes'.<% } %>");
equals(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
+ var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.');
+ equals(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
+
_.templateSettings = {
start : '{{',
end : '}}',
diff --git a/underscore-min.js b/underscore-min.js
index 2ee918c5d..18fed07f9 100644
--- a/underscore-min.js
+++ b/underscore-min.js
@@ -1,10 +1,10 @@
-(function(){var n=this,A=n._,r=typeof StopIteration!=="undefined"?StopIteration:"__break__",j=Array.prototype,l=Object.prototype,o=j.slice,B=j.unshift,C=l.toString,p=l.hasOwnProperty,s=j.forEach,t=j.map,u=j.reduce,v=j.reduceRight,w=j.filter,x=j.every,y=j.some,m=j.indexOf,z=j.lastIndexOf;l=Array.isArray;var D=Object.keys,b=function(a){return new k(a)};if(typeof exports!=="undefined")exports._=b;n._=b;b.VERSION="1.0.4";var i=b.forEach=function(a,c,d){try{if(s&&a.forEach===s)a.forEach(c,d);else if(b.isNumber(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};i(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gh?
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;e0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||{},d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);i(c,function(d){a[d]=b.bind(a[d],a)});return a};b.memoize=function(a,c){var d={};c=c||b.identity;return function(){var e=c.apply(this,arguments);return e in
d?d[e]:(d[e]=a.apply(this,arguments))}};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=D||function(a){if(b.isArray(a))return b.range(0,
@@ -12,6 +12,7 @@ a.length);var c=[];for(var d in a)p.call(a,d)&&c.push(d);return c};b.values=func
if(a==c)return true;if(!a&&c||a&&!c)return false;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 false;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 false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!(f in c)||!b.isEqual(a[f],
c[f]))return false;return true};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(p.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=l||function(a){return!!(a&&a.concat&&a.unshift&&!a.callee)};b.isArguments=function(a){return a&&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===
+a||C.call(a)==="[object Number]"};b.isBoolean=function(a){return a===true||a===false};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){n._=A;return this};b.identity=function(a){return a};b.times=function(a,c,d){for(var e=
-0;e",interpolate:/<%=(.+?)%>/g};b.template=function(a,c){var d=b.templateSettings,e=new RegExp("'(?=[^"+d.end.substr(0,1)+"]*"+d.end.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")+")","g");d=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g,
-" ").replace(e,"\t").split("'").join("\\'").split("\t").join("'").replace(d.interpolate,"',$1,'").split(d.start).join("');").split(d.end).join("p.push('")+"');}return p.join('');");return c?d(c):d};b.each=b.forEach;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.select=b.filter;b.all=b.every;b.any=b.some;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var k=function(a){this._wrapped=a},q=function(a,c){return c?b(a).chain():a},E=function(a,c){k.prototype[a]=function(){var d=b.toArray(arguments);
-B.call(d,this._wrapped);return q(c.apply(b,d),this._chain)}};b.mixin(b);i(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=j[a];k.prototype[a]=function(){c.apply(this._wrapped,arguments);return q(this._wrapped,this._chain)}});i(["concat","join","slice"],function(a){var c=j[a];k.prototype[a]=function(){return q(c.apply(this._wrapped,arguments),this._chain)}});k.prototype.chain=function(){this._chain=true;return this};k.prototype.value=function(){return this._wrapped}})();
+0;e",interpolate:/<%=(.+?)%>/g};b.template=function(a,c){var d=b.templateSettings,e=new RegExp("'(?=[^"+d.end.substr(0,1)+"]*"+d.end.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")+")","g");d=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj||{}){p.push('"+a.replace(/\r/g,
+"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(e,"\u2704").split("'").join("\\'").split("\u2704").join("'").replace(d.interpolate,"',$1,'").split(d.start).join("');").split(d.end).join("p.push('")+"');}return p.join('');");return c?d(c):d};b.each=b.forEach;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.select=b.filter;b.all=b.every;b.any=b.some;b.contains=b.include;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var k=function(a){this._wrapped=a},q=function(a,c){return c?b(a).chain():
+a},E=function(a,c){k.prototype[a]=function(){var d=b.toArray(arguments);B.call(d,this._wrapped);return q(c.apply(b,d),this._chain)}};b.mixin(b);i(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=j[a];k.prototype[a]=function(){c.apply(this._wrapped,arguments);return q(this._wrapped,this._chain)}});i(["concat","join","slice"],function(a){var c=j[a];k.prototype[a]=function(){return q(c.apply(this._wrapped,arguments),this._chain)}});k.prototype.chain=function(){this._chain=
+true;return this};k.prototype.value=function(){return this._wrapped}})();
diff --git a/underscore.js b/underscore.js
index 1170caf8d..60bf47ccd 100644
--- a/underscore.js
+++ b/underscore.js
@@ -55,7 +55,7 @@
root._ = _;
// Current version.
- _.VERSION = '1.0.4';
+ _.VERSION = '1.1.0';
// ------------------------ Collection Functions: ---------------------------
@@ -92,8 +92,11 @@
// Reduce builds up a single result from a list of values, aka inject, or foldl.
// Delegates to JavaScript 1.8's native reduce if available.
- _.reduce = function(obj, memo, iterator, context) {
- if (nativeReduce && obj.reduce === nativeReduce) return obj.reduce(_.bind(iterator, context), memo);
+ _.reduce = function(obj, iterator, memo, context) {
+ if (nativeReduce && obj.reduce === nativeReduce) {
+ if (context) iterator = _.bind(iterator, context);
+ return obj.reduce(iterator, memo);
+ }
each(obj, function(value, index, list) {
memo = iterator.call(context, memo, value, index, list);
});
@@ -102,10 +105,13 @@
// The right-associative version of reduce, also known as foldr. Uses
// Delegates to JavaScript 1.8's native reduceRight if available.
- _.reduceRight = function(obj, memo, iterator, context) {
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) return obj.reduceRight(_.bind(iterator, context), memo);
+ _.reduceRight = function(obj, iterator, memo, context) {
+ if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
+ if (context) iterator = _.bind(iterator, context);
+ return obj.reduceRight(iterator, memo);
+ }
var reversed = _.clone(_.toArray(obj)).reverse();
- return _.reduce(reversed, memo, iterator, context);
+ return _.reduce(reversed, iterator, memo, context);
};
// Return the first value which passes a truth test.
@@ -277,11 +283,11 @@
// Return a completely flattened version of an array.
_.flatten = function(array) {
- return _.reduce(array, [], function(memo, value) {
+ return _.reduce(array, function(memo, value) {
if (_.isArray(value)) return memo.concat(_.flatten(value));
memo.push(value);
return memo;
- });
+ }, []);
};
// Return a version of the array that does not contain the specified value(s).
@@ -293,10 +299,10 @@
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
_.uniq = function(array, isSorted) {
- return _.reduce(array, [], function(memo, el, i) {
+ return _.reduce(array, function(memo, el, i) {
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo.push(el);
return memo;
- });
+ }, []);
};
// Produce an array that contains every item shared between all the
@@ -619,17 +625,19 @@
// JavaScript templating a-la ERB, pilfered from John Resig's
// "Secrets of the JavaScript Ninja", page 83.
// Single-quote fix from Rick Strahl's version.
- // With alterations for arbitrary delimiters.
+ // With alterations for arbitrary delimiters, and to preserve whitespace.
_.template = function(str, data) {
var c = _.templateSettings;
var endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g");
var fn = new Function('obj',
'var p=[],print=function(){p.push.apply(p,arguments);};' +
- 'with(obj){p.push(\'' +
- str.replace(/[\r\t\n]/g, " ")
- .replace(endMatch,"\t")
+ 'with(obj||{}){p.push(\'' +
+ str.replace(/\r/g, '\\r')
+ .replace(/\n/g, '\\n')
+ .replace(/\t/g, '\\t')
+ .replace(endMatch,"✄")
.split("'").join("\\'")
- .split("\t").join("'")
+ .split("✄").join("'")
.replace(c.interpolate, "',$1,'")
.split(c.start).join("');")
.split(c.end).join("p.push('")
@@ -645,6 +653,7 @@
_.select = _.filter;
_.all = _.every;
_.any = _.some;
+ _.contains = _.include;
_.head = _.first;
_.tail = _.rest;
_.methods = _.functions;