diff --git a/index.html b/index.html
index 06de0f1b9..dc65e3f33 100644
--- a/index.html
+++ b/index.html
@@ -81,7 +81,7 @@
- Underscore provides 45-odd functions that support both the usual
+ Underscore provides 50-odd functions that support both the usual
functional suspects: map, select, invoke —
as well as more specialized helpers: function binding, javascript
templating, deep equality testing, and so on. It delegates to built-in
@@ -107,11 +107,11 @@
@@ -156,6 +156,14 @@ _(lyrics).chain()
=> {lumberjack : 2, all : 4, night : 2 ... }
+
+ In addition, the
+ Array prototype's methods
+ are proxied through the chained Underscore object, so you can slip a
+ reverse or a push into your chain, and continue to
+ modify the array.
+
+
Table of Contents
@@ -860,8 +868,13 @@ _.template(list, {people : ['moe', 'curly', 'larry']});
A more realistic example.)
-_({moe : false, curly : true}).chain().values().any().isEqual(true).get();
-=> true
+var stooges = [{name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23}];
+var youngest = _(stooges).chain()
+ .sortBy(function(stooge){ return stooge.age; })
+ .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
+ .first()
+ .get();
+=> "moe is 21"
@@ -875,6 +888,15 @@ _([1, 2, 3]).get();
Change Log
+
+
+
+ Chained Underscore objects now support the Array prototype methods, so
+ that you can perform the full range of operations on a wrapped array
+ without having to break your chain. Added a breakLoop method
+ to break in the middle of any Underscore iteration. Added an
+ isEmpty function that works on arrays and objects.
+
diff --git a/test/chaining.js b/test/chaining.js
index 0f3b10037..dc6cef6a4 100644
--- a/test/chaining.js
+++ b/test/chaining.js
@@ -1,7 +1,7 @@
$(document).ready(function() {
-
+
module("Underscore chaining.");
-
+
test("chaining: map/flatten/reduce", function() {
var lyrics = [
"I'm a lumberjack and I'm okay",
@@ -12,14 +12,14 @@ $(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;
}).get();
ok(counts['a'] == 16 && counts['e'] == 10, 'counted all the letters in the song');
});
-
+
test("chaining: select/reject/sortBy", function() {
var numbers = [1,2,3,4,5,6,7,8,9,10];
numbers = _(numbers).chain().select(function(n) {
@@ -31,5 +31,17 @@ $(document).ready(function() {
}).get();
equals(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
});
-
+
+ test("chaining: reverse/concat/unshift/pop/map", function() {
+ var numbers = [1,2,3,4,5];
+ numbers = _(numbers).chain()
+ .reverse()
+ .concat([5, 5, 5])
+ .unshift(17)
+ .pop()
+ .map(function(n){ return n * 2; })
+ .get();
+ equals(numbers.join(', '), "34, 10, 8, 6, 4, 2, 10, 10", 'can chain together array functions.');
+ });
+
});
diff --git a/underscore-min.js b/underscore-min.js
index 25ad77f4c..e0fd42d76 100644
--- a/underscore-min.js
+++ b/underscore-min.js
@@ -1 +1 @@
-(function(){var b=this;var d=b._;var e=function(f){this._wrapped=f};var c=b._=function(f){return new e(f)};if(typeof exports!=="undefined"){c=exports}c.VERSION="0.4.0";c.each=function(o,m,k){var g=0;try{if(o.forEach){o.forEach(m,k)}else{if(o.length){for(var j=0,f=o.length;j=f.computed&&(f={value:o,computed:m})});return f.value};c.min=function(j,h,g){if(!h&&c.isArray(j)){return Math.min.apply(Math,j)}var f={computed:Infinity};c.each(j,function(o,k,n){var m=h?h.call(g,o,k,n):o;mj?1:0}),"value")};c.sortedIndex=function(m,k,h){h=h||c.identity;var f=0,j=m.length;while(f>1;h(m[g])=0})})};c.zip=function(){var f=c.toArray(arguments);var j=c.max(c.pluck(f,"length"));var h=new Array(j);for(var g=0;g=0;g--){arguments=[f[g].apply(this,arguments)]}return arguments[0]}};c.keys=function(f){return c.map(f,function(h,g){return g})};c.values=function(f){return c.map(f,c.identity)};c.extend=function(f,h){for(var g in h){f[g]=h[g]}return f};c.clone=function(f){if(c.isArray(f)){return f.slice(0)}return c.extend({},f)};c.isEqual=function(g,f){if(g===f){return true}var k=typeof(g),n=typeof(f);if(k!=n){return false}if(g==f){return true}if(g.isEqual){return g.isEqual(f)}if(k!=="object"){return false}var h=c.keys(g),m=c.keys(f);if(h.length!=m.length){return false}for(var j in g){if(!c.isEqual(g[j],f[j])){return false}}return true};c.isElement=function(f){return !!(f&&f.nodeType==1)};c.isArray=function(f){return Object.prototype.toString.call(f)=="[object Array]"};c.isFunction=function(f){return Object.prototype.toString.call(f)=="[object Function]"};c.isUndefined=function(f){return typeof f=="undefined"};c.noConflict=function(){b._=d;return this};c.identity=function(f){return f};var a=0;c.uniqueId=function(f){var g=a++;return f?f+g:g};c.functions=function(){var g=[];for(var f in c){if(Object.prototype.hasOwnProperty.call(c,f)){g.push(f)}}return c.without(g,"VERSION","prototype","noConflict").sort()};c.template=function(h,g){var f=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+h.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 g?f(g):f};c.forEach=c.each;c.foldl=c.inject=c.reduce;c.foldr=c.reduceRight;c.filter=c.select;c.every=c.all;c.some=c.any;c.methods=c.functions;c.each(c.functions(),function(f){e.prototype[f]=function(){Array.prototype.unshift.call(arguments,this._wrapped);var g=c[f].apply(c,arguments);return this._chain?c(g).chain():g}});e.prototype.chain=function(){this._chain=true;return this};e.prototype.get=function(){return this._wrapped}})();
\ No newline at end of file
+(function(){var c=this;var e=c._;var f=function(g){this._wrapped=g};var d=c._=function(g){return new f(g)};if(typeof exports!=="undefined"){d=exports}d.VERSION="0.4.1";d.each=function(p,n,m){var h=0;try{if(p.forEach){p.forEach(n,m)}else{if(p.length){for(var k=0,g=p.length;k=g.computed&&(g={value:p,computed:n})});return g.value};d.min=function(k,j,h){if(!j&&d.isArray(k)){return Math.min.apply(Math,k)}var g={computed:Infinity};d.each(k,function(p,m,o){var n=j?j.call(h,p,m,o):p;nk?1:0}),"value")};d.sortedIndex=function(n,m,j){j=j||d.identity;var g=0,k=n.length;while(g>1;j(n[h])=0})})};d.zip=function(){var g=d.toArray(arguments);var k=d.max(d.pluck(g,"length"));var j=new Array(k);for(var h=0;h=0;h--){arguments=[g[h].apply(this,arguments)]}return arguments[0]}};d.keys=function(g){return d.map(g,function(j,h){return h})};d.values=function(g){return d.map(g,d.identity)};d.extend=function(g,j){for(var h in j){g[h]=j[h]}return g};d.clone=function(g){if(d.isArray(g)){return g.slice(0)}return d.extend({},g)};d.isEqual=function(h,g){if(h===g){return true}var m=typeof(h),o=typeof(g);if(m!=o){return false}if(h==g){return true}if(h.isEqual){return h.isEqual(g)}if(m!=="object"){return false}var j=d.keys(h),n=d.keys(g);if(j.length!=n.length){return false}for(var k in h){if(!d.isEqual(h[k],g[k])){return false}}return true};d.isEmpty=function(g){return(d.isArray(g)?g:d.values(g)).length==0};d.isElement=function(g){return !!(g&&g.nodeType==1)};d.isArray=function(g){return Object.prototype.toString.call(g)=="[object Array]"};d.isFunction=function(g){return Object.prototype.toString.call(g)=="[object Function]"};d.isUndefined=function(g){return typeof g=="undefined"};d.noConflict=function(){c._=e;return this};d.identity=function(g){return g};d.breakLoop=function(){throw"__break__"};var b=0;d.uniqueId=function(g){var h=b++;return g?g+h:h};d.functions=function(){var h=[];for(var g in d){if(Object.prototype.hasOwnProperty.call(d,g)){h.push(g)}}return d.without(h,"VERSION","prototype","noConflict").sort()};d.template=function(j,h){var g=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 h?g(h):g};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(h,g){return g?d(h).chain():h};d.each(d.functions(),function(g){f.prototype[g]=function(){Array.prototype.unshift.call(arguments,this._wrapped);return a(d[g].apply(d,arguments),this._chain)}});d.each(["pop","push","reverse","shift","sort","splice","unshift"],function(g){f.prototype[g]=function(){Array.prototype[g].apply(this._wrapped,arguments);return a(this._wrapped,this._chain)}});d.each(["concat","join","slice"],function(g){f.prototype[g]=function(){return a(Array.prototype[g].apply(this._wrapped,arguments),this._chain)}});f.prototype.chain=function(){this._chain=true;return this};f.prototype.get=function(){return this._wrapped}})();
\ No newline at end of file
diff --git a/underscore.js b/underscore.js
index 748c6e247..c0fedb145 100644
--- a/underscore.js
+++ b/underscore.js
@@ -28,7 +28,7 @@
if (typeof exports !== 'undefined') _ = exports;
// Current version.
- _.VERSION = '0.4.0';
+ _.VERSION = '0.4.1';
/*------------------------ Collection Functions: ---------------------------*/
@@ -496,12 +496,31 @@
/*------------------------ Setup the OOP Wrapper: --------------------------*/
+ // Helper function to continue chaining intermediate results.
+ var result = function(obj, chain) {
+ return chain ? _(obj).chain() : obj;
+ };
+
// Add all of the Underscore functions to the wrapper object.
_.each(_.functions(), function(name) {
wrapper.prototype[name] = function() {
Array.prototype.unshift.call(arguments, this._wrapped);
- var result = _[name].apply(_, arguments);
- return this._chain ? _(result).chain() : result;
+ return result(_[name].apply(_, arguments), this._chain);
+ };
+ });
+
+ // Add all mutator Array functions to the wrapper.
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ wrapper.prototype[name] = function() {
+ Array.prototype[name].apply(this._wrapped, arguments);
+ return result(this._wrapped, this._chain);
+ };
+ });
+
+ // Add all accessor Array functions to the wrapper.
+ _.each(['concat', 'join', 'slice'], function(name) {
+ wrapper.prototype[name] = function() {
+ return result(Array.prototype[name].apply(this._wrapped, arguments), this._chain);
};
});