From e114c180316d303551a96922b238ffd79cc2e446 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Oct 2013 23:30:49 -0700 Subject: [PATCH 001/189] Ensure `_.template` coerces the `text` argument to a string. --- dist/lodash.compat.js | 2 +- dist/lodash.compat.min.js | 2 +- dist/lodash.js | 2 +- dist/lodash.min.js | 2 +- dist/lodash.underscore.js | 2 +- dist/lodash.underscore.min.js | 2 +- lodash.js | 2 +- test/test.js | 15 +++++++++++---- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index e48344d4cf..601a814a51 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -6136,7 +6136,7 @@ // and Laura Doktorova's doT.js // https://github.com/olado/doT var settings = lodash.templateSettings; - text || (text = ''); + text = String(text || ''); // avoid missing dependencies when `iteratorTemplate` is not defined options = defaults({}, options, settings); diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index a2d078c27a..ae5a23e457 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -47,7 +47,7 @@ return a},y.tap=function(n,t){return t(n),n},y.throttle=function(n,t,e){var r=!0 }),r},y.findLastIndex=function(n,t,e){var r=n?n.length:0;for(t=y.createCallback(t,e,3);r--;)if(t(n[r],r,n))return r;return-1},y.findLastKey=function(n,t,e){var r;return t=y.createCallback(t,e,3),yt(n,function(n,e,u){return t(n,e,u)?(r=e,!1):void 0}),r},y.has=function(n,t){return n?de.call(n,t):!1},y.identity=Ht,y.indexOf=Lt,y.isArguments=vt,y.isArray=Je,y.isBoolean=function(n){return true===n||false===n||ke.call(n)==z},y.isDate=function(n){return n?typeof n=="object"&&ke.call(n)==q:!1},y.isElement=function(n){return n?1===n.nodeType:!1 },y.isEmpty=function(n){var t=!0;if(!n)return t;var e=ke.call(n),r=n.length;return e==T||e==H||(We.argsClass?e==L:vt(n))||e==J&&typeof r=="number"&&_t(n.splice)?!r:(or(n,function(){return t=!1}),t)},y.isEqual=function(n,t,e,r){return et(n,t,typeof e=="function"&&Z(e,r,2))},y.isFinite=function(n){return Ne(n)&&!Be(parseFloat(n))},y.isFunction=_t,y.isNaN=function(n){return wt(n)&&n!=+n},y.isNull=function(n){return null===n},y.isNumber=wt,y.isObject=bt,y.isPlainObject=ar,y.isRegExp=function(n){return n&&Y[typeof n]?ke.call(n)==M:!1 },y.isString=jt,y.isUndefined=function(n){return typeof n=="undefined"},y.lastIndexOf=function(n,t,e){var r=n?n.length:0;for(typeof e=="number"&&(r=(0>e?Pe(0,r+e):Re(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},y.mixin=Ut,y.noConflict=function(){return e._=pe,this},y.parseInt=pr,y.random=Vt,y.reduce=Bt,y.reduceRight=Dt,y.result=function(n,t){if(n){var e=n[t];return _t(e)?n[t]():e}},y.runInContext=h,y.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:He(n).length},y.some=Rt,y.sortedIndex=zt,y.template=function(n,t,e){var r=y.templateSettings; -n||(n=""),e=rr({},e,r);var u,o=rr({},e.imports,r.imports),r=He(o),o=xt(o),i=0,l=e.interpolate||D,f="__p+='",l=ue((e.escape||D).source+"|"+l.source+"|"+(l===N?S:D).source+"|"+(e.evaluate||D).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(R,a),e&&(f+="'+__e("+e+")+'"),l&&(u=!0,f+="';"+l+";__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),f+="';\n",l=e=e.variable,l||(e="obj",f="with("+e+"){"+f+"}"),f=(u?f.replace(C,""):f).replace(E,"$1").replace(O,"$1;"),f="function("+e+"){"+(l?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}"; +n=oe(n||""),e=rr({},e,r);var u,o=rr({},e.imports,r.imports),r=He(o),o=xt(o),i=0,l=e.interpolate||D,f="__p+='",l=ue((e.escape||D).source+"|"+l.source+"|"+(l===N?S:D).source+"|"+(e.evaluate||D).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(R,a),e&&(f+="'+__e("+e+")+'"),l&&(u=!0,f+="';"+l+";__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),f+="';\n",l=e=e.variable,l||(e="obj",f="with("+e+"){"+f+"}"),f=(u?f.replace(C,""):f).replace(E,"$1").replace(O,"$1;"),f="function("+e+"){"+(l?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}"; try{var c=ne(r,"return "+f).apply(v,o)}catch(p){throw p.source=f,p}return t?c(t):(c.source=f,c)},y.unescape=function(n){return null==n?"":oe(n).replace(Ze,ht)},y.uniqueId=function(n){var t=++d;return oe(null==n?"":n)+t},y.all=kt,y.any=Rt,y.detect=Ot,y.findWhere=Ot,y.foldl=Bt,y.foldr=Dt,y.include=Ct,y.inject=Bt,or(y,function(n,t){y.prototype[t]||(y.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return be.apply(t,arguments),t=n.apply(y,t),e?new m(t,e):t})}),y.first=$t,y.last=function(n,t,e){var r=0,u=n?n.length:0; if(typeof t!="number"&&null!=t){var o=u;for(t=y.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:v;return g(n,Pe(0,u-r))},y.sample=function(n,t,e){var r=n?n.length:0;return typeof r!="number"?n=xt(n):We.unindexedChars&&jt(n)&&(n=n.split("")),null==t||e?n?n[Vt(r-1)]:v:(n=Pt(n),n.length=Re(Pe(0,t),n.length),n)},y.take=$t,y.head=$t,or(y,function(n,t){var e="sample"!==t;y.prototype[t]||(y.prototype[t]=function(t,r){var u=this.__chain__,o=n(this.__wrapped__,t,r);return u||null!=t&&(!r||e&&typeof t=="function")?new m(o,u):o })}),y.VERSION="2.2.1",y.prototype.chain=function(){return this.__chain__=!0,this},y.prototype.toString=function(){return oe(this.__wrapped__)},y.prototype.value=Qt,y.prototype.valueOf=Qt,tr(["join","pop","shift"],function(n){var t=ie[n];y.prototype[n]=function(){var n=this.__chain__,e=t.apply(this.__wrapped__,arguments);return n?new m(e,n):e}}),tr(["push","reverse","sort","unshift"],function(n){var t=ie[n];y.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),tr(["concat","slice","splice"],function(n){var t=ie[n]; diff --git a/dist/lodash.js b/dist/lodash.js index 568c476c84..f3ce4a521b 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -5797,7 +5797,7 @@ // and Laura Doktorova's doT.js // https://github.com/olado/doT var settings = lodash.templateSettings; - text || (text = ''); + text = String(text || ''); // avoid missing dependencies when `iteratorTemplate` is not defined options = defaults({}, options, settings); diff --git a/dist/lodash.min.js b/dist/lodash.min.js index 0fd9246efa..96e61e9b0f 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -45,7 +45,7 @@ return a},Y.tap=function(n,t){return t(n),n},Y.throttle=function(n,t,e){var r=!0 }),r},Y.findLastIndex=function(n,t,e){var r=n?n.length:0;for(t=Y.createCallback(t,e,3);r--;)if(t(n[r],r,n))return r;return-1},Y.findLastKey=function(n,t,e){var r;return t=Y.createCallback(t,e,3),gt(n,function(n,e,u){return t(n,e,u)?(r=e,!1):void 0}),r},Y.has=function(n,t){return n?ye.call(n,t):!1},Y.identity=Gt,Y.indexOf=Wt,Y.isArguments=ht,Y.isArray=Pe,Y.isBoolean=function(n){return true===n||false===n||je.call(n)==F},Y.isDate=function(n){return n?typeof n=="object"&&je.call(n)==T:!1},Y.isElement=function(n){return n?1===n.nodeType:!1 },Y.isEmpty=function(n){var t=!0;if(!n)return t;var e=je.call(n),r=n.length;return e==$||e==K||e==B||e==z&&typeof r=="number"&&_t(n.splice)?!r:(y(n,function(){return t=!1}),t)},Y.isEqual=function(n,t,e,r){return ut(n,t,typeof e=="function"&&et(e,r,2))},Y.isFinite=function(n){return Ne(n)&&!Ee(parseFloat(n))},Y.isFunction=_t,Y.isNaN=function(n){return dt(n)&&n!=+n},Y.isNull=function(n){return null===n},Y.isNumber=dt,Y.isObject=bt,Y.isPlainObject=g,Y.isRegExp=function(n){return n?typeof n=="object"&&je.call(n)==P:!1 },Y.isString=wt,Y.isUndefined=function(n){return typeof n=="undefined"},Y.lastIndexOf=function(n,t,e){var r=n?n.length:0;for(typeof e=="number"&&(r=(0>e?Re(0,r+e):Ae(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},Y.mixin=Ht,Y.noConflict=function(){return e._=le,this},Y.parseInt=Qe,Y.random=Jt,Y.reduce=At,Y.reduceRight=Dt,Y.result=function(n,t){if(n){var e=n[t];return _t(e)?n[t]():e}},Y.runInContext=v,Y.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Ke(n).length},Y.some=$t,Y.sortedIndex=zt,Y.template=function(n,t,e){var r=Y.templateSettings; -n||(n=""),e=G({},e,r);var u,o=G({},e.imports,r.imports),r=Ke(o),o=jt(o),i=0,f=e.interpolate||S,l="__p+='",f=ue((e.escape||S).source+"|"+f.source+"|"+(f===N?C:S).source+"|"+(e.evaluate||S).source+"|$","g");n.replace(f,function(t,e,r,o,f,c){return r||(r=o),l+=n.slice(i,c).replace(A,a),e&&(l+="'+__e("+e+")+'"),f&&(u=!0,l+="';"+f+";__p+='"),r&&(l+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),l+="';\n",f=e=e.variable,f||(e="obj",l="with("+e+"){"+l+"}"),l=(u?l.replace(j,""):l).replace(k,"$1").replace(x,"$1;"),l="function("+e+"){"+(f?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}"; +n=oe(n||""),e=G({},e,r);var u,o=G({},e.imports,r.imports),r=Ke(o),o=jt(o),i=0,f=e.interpolate||S,l="__p+='",f=ue((e.escape||S).source+"|"+f.source+"|"+(f===N?C:S).source+"|"+(e.evaluate||S).source+"|$","g");n.replace(f,function(t,e,r,o,f,c){return r||(r=o),l+=n.slice(i,c).replace(A,a),e&&(l+="'+__e("+e+")+'"),f&&(u=!0,l+="';"+f+";__p+='"),r&&(l+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),l+="';\n",f=e=e.variable,f||(e="obj",l="with("+e+"){"+l+"}"),l=(u?l.replace(j,""):l).replace(k,"$1").replace(x,"$1;"),l="function("+e+"){"+(f?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}"; try{var c=ne(r,"return "+l).apply(h,o)}catch(p){throw p.source=l,p}return t?c(t):(c.source=l,c)},Y.unescape=function(n){return null==n?"":oe(n).replace(Ue,vt)},Y.uniqueId=function(n){var t=++m;return oe(null==n?"":n)+t},Y.all=xt,Y.any=$t,Y.detect=Ot,Y.findWhere=Ot,Y.foldl=At,Y.foldr=Dt,Y.include=kt,Y.inject=At,y(Y,function(n,t){Y.prototype[t]||(Y.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return _e.apply(t,arguments),t=n.apply(Y,t),e?new nt(t,e):t})}),Y.first=Tt,Y.last=function(n,t,e){var r=0,u=n?n.length:0; if(typeof t!="number"&&null!=t){var o=u;for(t=Y.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:h;return s(n,Re(0,u-r))},Y.sample=function(n,t,e){var r=n?n.length:0;return typeof r!="number"&&(n=jt(n)),null==t||e?n?n[Jt(r-1)]:h:(n=Bt(n),n.length=Ae(Re(0,t),n.length),n)},Y.take=Tt,Y.head=Tt,y(Y,function(n,t){var e="sample"!==t;Y.prototype[t]||(Y.prototype[t]=function(t,r){var u=this.__chain__,o=n(this.__wrapped__,t,r);return u||null!=t&&(!r||e&&typeof t=="function")?new nt(o,u):o })}),Y.VERSION="2.2.1",Y.prototype.chain=function(){return this.__chain__=!0,this},Y.prototype.toString=function(){return oe(this.__wrapped__)},Y.prototype.value=Qt,Y.prototype.valueOf=Qt,It(["join","pop","shift"],function(n){var t=ie[n];Y.prototype[n]=function(){var n=this.__chain__,e=t.apply(this.__wrapped__,arguments);return n?new nt(e,n):e}}),It(["push","reverse","sort","unshift"],function(n){var t=ie[n];Y.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),It(["concat","slice","splice"],function(n){var t=ie[n]; diff --git a/dist/lodash.underscore.js b/dist/lodash.underscore.js index 950c73f373..35cafb5186 100644 --- a/dist/lodash.underscore.js +++ b/dist/lodash.underscore.js @@ -4337,7 +4337,7 @@ var _ = lodash, settings = _.templateSettings; - text || (text = ''); + text = String(text || ''); options = defaults({}, options, settings); var index = 0, diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index 3c3a4c3cd2..54be961173 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -32,7 +32,7 @@ o in n&&(u[o]=n[o])}return u},u.pluck=D,u.range=function(n,r,t){n=+n||0,t=+t||1, },u.wrap=function(n,r){if(!j(r))throw new TypeError;return function(){var t=[n];return Sr.apply(t,arguments),r.apply(this,t)}},u.zip=function(){for(var n=-1,r=q(D(arguments,"length")),t=Array(0>r?0:r);++nt?$r(0,e+t):Ir(t,e-1))+1);e--;)if(n[e]===r)return e;return-1},u.mixin=X,u.noConflict=function(){return gr._=jr,this},u.random=Y,u.reduce=M,u.reduceRight=$,u.result=function(n,r){if(n){var t=n[r];return j(t)?n[r]():t}},u.size=function(n){var r=n?n.length:0;return typeof r=="number"?r:Hr(n).length -},u.some=W,u.sortedIndex=G,u.template=function(n,r,e){var o=u,i=o.templateSettings;n||(n=""),e=_({},e,i);var f=0,a="__p+='",i=e.variable;n.replace(RegExp((e.escape||er).source+"|"+(e.interpolate||er).source+"|"+(e.evaluate||er).source+"|$","g"),function(r,e,u,o,i){return a+=n.slice(f,i).replace(ur,t),e&&(a+="'+_.escape("+e+")+'"),o&&(a+="';"+o+";__p+='"),u&&(a+="'+((__t=("+u+"))==null?'':__t)+'"),f=i+r.length,r}),a+="';\n",i||(i="obj",a="with("+i+"||{}){"+a+"}"),a="function("+i+"){var __t,__p='',__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+a+"return __p}"; +},u.some=W,u.sortedIndex=G,u.template=function(n,r,e){var o=u,i=o.templateSettings;n=(n||"")+"",e=_({},e,i);var f=0,a="__p+='",i=e.variable;n.replace(RegExp((e.escape||er).source+"|"+(e.interpolate||er).source+"|"+(e.evaluate||er).source+"|$","g"),function(r,e,u,o,i){return a+=n.slice(f,i).replace(ur,t),e&&(a+="'+_.escape("+e+")+'"),o&&(a+="';"+o+";__p+='"),u&&(a+="'+((__t=("+u+"))==null?'':__t)+'"),f=i+r.length,r}),a+="';\n",i||(i="obj",a="with("+i+"||{}){"+a+"}"),a="function("+i+"){var __t,__p='',__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+a+"return __p}"; try{var l=Function("_","return "+a)(o)}catch(c){throw c.source=a,c}return r?l(r):(l.source=a,l)},u.unescape=function(n){return null==n?"":(n+"").replace(Lr,g)},u.uniqueId=function(n){var r=++nr+"";return n?n+r:r},u.all=S,u.any=W,u.detect=N,u.findWhere=function(n,r){return z(n,r,!0)},u.foldl=M,u.foldr=$,u.include=O,u.inject=M,u.first=P,u.last=function(n,r,t){var e=0,u=n?n.length:0;if(typeof r!="number"&&null!=r){var o=u;for(r=K(r,t,3);o--&&r(n[o],o,n);)e++}else if(e=r,null==e||t)return n?n[u-1]:Z; return zr.call(n,$r(0,u-e))},u.sample=function(n,r,t){var e=n?n.length:0;return typeof e!="number"&&(n=A(n)),null==r||t?n?n[Y(e-1)]:Z:(n=I(n),n.length=Ir($r(0,r),n.length),n)},u.take=P,u.head=P,X(u),u.VERSION="2.2.1",u.prototype.chain=function(){return this.__chain__=!0,this},u.prototype.value=function(){return this.__wrapped__},R("pop push reverse shift sort splice unshift".split(" "),function(n){var r=br[n];u.prototype[n]=function(){var n=this.__wrapped__;return r.apply(n,arguments),Ur.spliceObjects||0!==n.length||delete n[0],this }}),R(["concat","join","slice"],function(n){var r=br[n];u.prototype[n]=function(){var n=r.apply(this.__wrapped__,arguments);return this.__chain__&&(n=new o(n),n.__chain__=!0),n}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(gr._=u, define(function(){return u})):yr&&mr?_r?(mr.exports=u)._=u:yr._=u:gr._=u}).call(this); \ No newline at end of file diff --git a/lodash.js b/lodash.js index 71bb2c452f..94bd6447cf 100644 --- a/lodash.js +++ b/lodash.js @@ -6153,7 +6153,7 @@ // and Laura Doktorova's doT.js // https://github.com/olado/doT var settings = lodash.templateSettings; - text || (text = ''); + text = String(text || ''); // avoid missing dependencies when `iteratorTemplate` is not defined options = iteratorTemplate ? defaults({}, options, settings) : settings; diff --git a/test/test.js b/test/test.js index c1ee78e88d..2574dcee17 100644 --- a/test/test.js +++ b/test/test.js @@ -3857,7 +3857,7 @@ var compiled = _.template('<% var b = a; %><%= b.value %>'), data = { 'a': { 'value': 1 } }; - equal(compiled(data), '1'); + strictEqual(compiled(data), '1'); }); test('should work when passing `options.variable`', 1, function() { @@ -3870,7 +3870,7 @@ var data = { 'a': [1, 2, 3] }; try { - equal(compiled(data), '123'); + strictEqual(compiled(data), '123'); } catch(e) { ok(false); } @@ -3923,7 +3923,7 @@ test('should parse ES6 template delimiters', 2, function() { var data = { 'value': 2 }; - equal(_.template('1${value}3', data), '123'); + strictEqual(_.template('1${value}3', data), '123'); equal(_.template('${"{" + value + "\\}"}', data), '{2}'); }); @@ -3931,7 +3931,14 @@ var options = { 'imports': { 'a': 1 } }, compiled = _.template('<%= a %>', null, options); - equal(compiled({}), '1'); + strictEqual(compiled({}), '1'); + }); + + test('should coerce `text` argument to a string', function() { + var data = { 'a': 1 }, + object = { 'toString': function() { return '<%= a %>'; } }; + + strictEqual(_.template(object, data), '1'); }); }()); From fd2ddca6f27c006627c19308410b86b0b82fe357 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Oct 2013 21:24:10 -0700 Subject: [PATCH 002/189] Extend `baseCreateCallback` to functions bound with native `Function#bind` and those with `__bindData__` of `false`. --- dist/lodash.compat.js | 30 +++++++++++++--------- dist/lodash.compat.min.js | 34 ++++++++++++------------- dist/lodash.js | 30 +++++++++++++--------- dist/lodash.min.js | 26 +++++++++---------- dist/lodash.underscore.js | 4 +-- dist/lodash.underscore.min.js | 2 +- lodash.js | 30 +++++++++++++--------- test/test.js | 47 ++++++++++++++++++++++++++++++++--- 8 files changed, 131 insertions(+), 72 deletions(-) diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index 601a814a51..037022e151 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -1090,24 +1090,30 @@ if (typeof func != 'function') { return identity; } - // exit early if there is no `thisArg` - if (typeof thisArg == 'undefined') { + // exit early for no `thisArg` or already bound by `Function#bind` + if (typeof thisArg == 'undefined' || !('prototype' in func)) { return func; } - var bindData = func.__bindData__ || (support.funcNames && !func.name); + var bindData = func.__bindData__; if (typeof bindData == 'undefined') { - var source = reThis && fnToString.call(func); - if (!support.funcNames && source && !reFuncName.test(source)) { - bindData = true; + if (support.funcNames) { + bindData = !func.name; } - if (support.funcNames || !bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = !support.funcDecomp || reThis.test(source); - setBindData(func, bindData); + bindData = bindData || !support.funcDecomp; + if (!bindData) { + var source = fnToString.call(func); + if (!support.funcNames) { + bindData = !reFuncName.test(source); + } + if (!bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = reThis.test(source); + setBindData(func, bindData); + } } } // exit early if there are no `this` references or `func` is bound - if (bindData !== true && (bindData && bindData[1] & 1)) { + if (bindData === false || (bindData !== true && bindData[1] & 1)) { return func; } switch (argCount) { @@ -1528,7 +1534,7 @@ isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; - if (bindData) { + if (typeof bindData == 'object') { if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index ae5a23e457..fae5d45252 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -7,36 +7,36 @@ }}function r(n){return n.charCodeAt(0)}function u(n,t){var e=n.m,r=t.m;if(e!==r){if(e>r||typeof e=="undefined")return 1;if(ee?0:e);++r=w&&l===n,h=u||g?i():c;if(g){var v=o(h);v?(l=t,h=v):(g=!1,h=u?h:(p(h),c))}for(;++al(h,y))&&((u||g)&&h.push(y),c.push(v))}return g?(p(h.k),s(h)):u&&p(h),c}function it(n){return function(t,e,r){var u={}; -if(e=y.createCallback(e,r,3),Je(t)){r=-1;for(var o=t.length;++rk;k++)r+="n='"+e.h[k]+"';if((!(r&&x[n])&&m.call(t,n))",e.j||(r+="||(!x[n]&&t[n]!==A[n])"),r+="){"+e.g+"}";r+="}"}return(e.b||We.nonEnumArgs)&&(r+="}"),r+=e.c+";return E",n("d,j,k,m,o,p,q,s,v,A,B,y,I,J,L",t+r+"}")(Z,K,le,de,_,vt,Je,jt,X.f,fe,Y,Ke,H,ce,ke) }function ct(n){return bt(n)?Ie(n):{}}function pt(n){return Xe[n]}function st(){var t=(t=y.indexOf)===Lt?n:t;return t}function gt(n){var t,e;return!n||ke.call(n)!=J||(t=n.constructor,_t(t)&&!(t instanceof t))||!We.argsClass&&vt(n)||!We.nodeClass&&f(n)?!1:We.ownLast?(ur(n,function(n,t,r){return e=de.call(r,t),!1}),false!==e):(ur(n,function(n,t){e=t}),typeof e=="undefined"||de.call(n,e))}function ht(n){return Ye[n]}function vt(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ke.call(n)==L||!1 }function yt(n,t,e){var r=He(n),u=r.length;for(t=Z(t,e,3);u--&&(e=r[u],false!==t(n[e],e,n)););return n}function mt(n){var t=[];return ur(n,function(n,e){_t(n)&&t.push(e)}),t.sort()}function dt(n){for(var t=-1,e=He(n),r=e.length,u={};++te?Pe(0,o+e):e)||0,Je(n)?a=-1o&&(o=i)}}else t=!t&&jt(n)?r:y.createCallback(t,e,3),tr(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o -}function Bt(n,t,e,r){var u=3>arguments.length;if(t=Z(t,r,4),Je(n)){var o=-1,a=n.length;for(u&&(e=n[++o]);++oarguments.length;return t=Z(t,r,4),It(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o)}),e}function Pt(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return St(n,function(n){var e=Vt(++t);r[t]=r[e],r[e]=n}),r}function Rt(n,t,e){var r;if(t=y.createCallback(t,e,3),Je(n)){e=-1;for(var u=n.length;++eo&&(o=i)}}else t=!t&&jt(n)?r:y.createCallback(t,e,3),tr(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o +}function Dt(n,t,e,r){var u=3>arguments.length;if(t=Z(t,r,4),Je(n)){var o=-1,a=n.length;for(u&&(e=n[++o]);++oarguments.length;return t=Z(t,r,4),It(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o)}),e}function Pt(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return St(n,function(n){var e=Vt(++t);r[t]=r[e],r[e]=n}),r}function Rt(n,t,e){var r;if(t=y.createCallback(t,e,3),Je(n)){e=-1;for(var u=n.length;++e=w&&u===n;if(f){var c=o(i);c?(u=t,i=c):f=!1}for(;++ru(i,c)&&l.push(c);return f&&s(i),l}function $t(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=-1;for(t=y.createCallback(t,e,3);++or?Pe(0,u+r):r||0}else if(r)return r=zt(t,e),t[r]===e?r:-1; -return n(t,e,r)}function Tt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=y.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++t>>1,e(n[r])e?0:e);++t/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:N,variable:"",imports:{_:y}},Ie||(ct=function(n){if(bt(n)){c.prototype=n;var t=new c;c.prototype=null}return t||{}});var Ge=Oe?function(n,t){Q.value=t,Oe(n,"__bindData__",Q)}:c;We.argsClass||(vt=function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&de.call(n,"callee")||!1});var Je=Ae||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ke.call(n)==T||!1 -},Me=ft({a:"z",e:"[]",i:"if(!(B[typeof z]))return E",g:"E.push(n)"}),He=De?function(n){return bt(n)?We.enumPrototypes&&typeof n=="function"||We.nonEnumArgs&&n.length&&vt(n)?Me(n):De(n):[]}:Me,Ue={a:"g,e,K",i:"e=e&&typeof K=='undefined'?e:d(e,K,3)",b:"typeof u=='number'",v:He,g:"if(e(t[n],n,g)===false)return E"},Ve={a:"z,H,l",i:"var a=arguments,b=0,c=typeof l=='number'?2:a.length;while(++b":">",'"':""","'":"'"},Ye=dt(Xe),Ze=ue("("+He(Ye).join("|")+")","g"),nr=ue("["+He(Xe).join("")+"]","g"),tr=ft(Ue),er=ft(Ve,{i:Ve.i.replace(";",";if(c>3&&typeof a[c-2]=='function'){var e=d(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){e=a[--c]}"),g:"E[n]=e?e(E[n],t[n]):t[n]"}),rr=ft(Ve),ur=ft(Ue,Qe,{j:!1}),or=ft(Ue,Qe); -_t(/x/)&&(_t=function(n){return typeof n=="function"&&ke.call(n)==W});var ar=me?function(n){if(!n||ke.call(n)!=J||!We.argsClass&&vt(n))return!1;var t=n.valueOf,e=typeof t=="function"&&(e=me(t))&&me(e);return e?n==e||me(n)==e:gt(n)}:gt,ir=it(function(n,t,e){de.call(n,e)?n[e]++:n[e]=1}),lr=it(function(n,t,e){(de.call(n,e)?n[e]:n[e]=[]).push(t)}),fr=it(function(n,t,e){n[e]=t}),cr=At;ze&&rt&&typeof je=="function"&&(Mt=function(n){if(!_t(n))throw new ae;return je.apply(e,arguments)});var pr=8==Fe(x+"08")?Fe:function(n,t){return Fe(jt(n)?n.replace(B,""):n,t||0) +try{We.nodeClass=!(ke.call(document)==J&&!({toString:0}+""))}catch(o){We.nodeClass=!0}}(1),y.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:B,variable:"",imports:{_:y}},Ie||(ct=function(n){if(bt(n)){c.prototype=n;var t=new c;c.prototype=null}return t||{}});var Ge=Oe?function(n,t){Q.value=t,Oe(n,"__bindData__",Q)}:c;We.argsClass||(vt=function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&de.call(n,"callee")||!1});var Je=Ae||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ke.call(n)==T||!1 +},Me=ft({a:"z",e:"[]",i:"if(!(B[typeof z]))return E",g:"E.push(n)"}),He=Ne?function(n){return bt(n)?We.enumPrototypes&&typeof n=="function"||We.nonEnumArgs&&n.length&&vt(n)?Me(n):Ne(n):[]}:Me,Ue={a:"g,e,K",i:"e=e&&typeof K=='undefined'?e:d(e,K,3)",b:"typeof u=='number'",v:He,g:"if(e(t[n],n,g)===false)return E"},Ve={a:"z,H,l",i:"var a=arguments,b=0,c=typeof l=='number'?2:a.length;while(++b":">",'"':""","'":"'"},Ye=dt(Xe),Ze=ue("("+He(Ye).join("|")+")","g"),nr=ue("["+He(Xe).join("")+"]","g"),tr=ft(Ue),er=ft(Ve,{i:Ve.i.replace(";",";if(c>3&&typeof a[c-2]=='function'){var e=d(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){e=a[--c]}"),g:"E[n]=e?e(E[n],t[n]):t[n]"}),rr=ft(Ve),ur=ft(Ue,Qe,{j:!1}),or=ft(Ue,Qe); +_t(/x/)&&(_t=function(n){return typeof n=="function"&&ke.call(n)==W});var ar=me?function(n){if(!n||ke.call(n)!=J||!We.argsClass&&vt(n))return!1;var t=n.valueOf,e=typeof t=="function"&&(e=me(t))&&me(e);return e?n==e||me(n)==e:gt(n)}:gt,ir=it(function(n,t,e){de.call(n,e)?n[e]++:n[e]=1}),lr=it(function(n,t,e){(de.call(n,e)?n[e]:n[e]=[]).push(t)}),fr=it(function(n,t,e){n[e]=t}),cr=At;ze&&rt&&typeof je=="function"&&(Mt=function(n){if(!_t(n))throw new ae;return je.apply(e,arguments)});var pr=8==Fe(x+"08")?Fe:function(n,t){return Fe(jt(n)?n.replace(D,""):n,t||0) };return y.after=function(n,t){if(!_t(t))throw new ae;return function(){return 1>--n?t.apply(this,arguments):void 0}},y.assign=er,y.at=function(n){var t=arguments,e=-1,r=tt(t,!0,!1,1),t=t[2]&&t[2][t[1]]===n?1:r.length,u=Xt(t);for(We.unindexedChars&&jt(n)&&(n=n.split(""));++e=w&&o(a?r[a]:v)}n:for(;++f(m?t(m,y):c(v,y))){for(a=u,(m||v).push(y);--a;)if(m=l[a],0>(m?t(m,y):c(r[a],y)))continue n;h.push(y)}}for(;u--;)(m=l[u])&&s(m);return p(l),p(v),h},y.invert=dt,y.invoke=function(n,t){var e=Le.call(arguments,2),r=-1,u=typeof t=="function",o=n?n.length:0,a=Xt(typeof o=="number"?o:0);return St(n,function(n){a[++r]=(u?t:n[t]).apply(n,e)}),a},y.keys=He,y.map=At,y.max=Nt,y.memoize=function(n,t){function e(){var r=e.cache,u=t?t.apply(this,arguments):b+arguments[0]; +l[a]=c===n&&(y?y.length:0)>=w&&o(a?r[a]:v)}n:for(;++f(m?t(m,y):c(v,y))){for(a=u,(m||v).push(y);--a;)if(m=l[a],0>(m?t(m,y):c(r[a],y)))continue n;h.push(y)}}for(;u--;)(m=l[u])&&s(m);return p(l),p(v),h},y.invert=dt,y.invoke=function(n,t){var e=Le.call(arguments,2),r=-1,u=typeof t=="function",o=n?n.length:0,a=Xt(typeof o=="number"?o:0);return St(n,function(n){a[++r]=(u?t:n[t]).apply(n,e)}),a},y.keys=He,y.map=At,y.max=Bt,y.memoize=function(n,t){function e(){var r=e.cache,u=t?t.apply(this,arguments):b+arguments[0]; return de.call(r,u)?r[u]:r[u]=n.apply(this,arguments)}if(!_t(n))throw new ae;return e.cache={},e},y.merge=function(n){var t=arguments,e=2;if(!bt(n))return n;if("number"!=typeof t[2]&&(e=t.length),3r(a,e))&&(o[e]=n)}),o},y.once=function(n){var t,e;if(!_t(n))throw new ae;return function(){return t?e:(t=!0,e=n.apply(this,arguments),n=null,e)}},y.pairs=function(n){for(var t=-1,e=He(n),r=e.length,u=Xt(r);++te?Pe(0,r+e):Re(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},y.mixin=Ut,y.noConflict=function(){return e._=pe,this},y.parseInt=pr,y.random=Vt,y.reduce=Bt,y.reduceRight=Dt,y.result=function(n,t){if(n){var e=n[t];return _t(e)?n[t]():e}},y.runInContext=h,y.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:He(n).length},y.some=Rt,y.sortedIndex=zt,y.template=function(n,t,e){var r=y.templateSettings; -n=oe(n||""),e=rr({},e,r);var u,o=rr({},e.imports,r.imports),r=He(o),o=xt(o),i=0,l=e.interpolate||D,f="__p+='",l=ue((e.escape||D).source+"|"+l.source+"|"+(l===N?S:D).source+"|"+(e.evaluate||D).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(R,a),e&&(f+="'+__e("+e+")+'"),l&&(u=!0,f+="';"+l+";__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),f+="';\n",l=e=e.variable,l||(e="obj",f="with("+e+"){"+f+"}"),f=(u?f.replace(C,""):f).replace(E,"$1").replace(O,"$1;"),f="function("+e+"){"+(l?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}"; -try{var c=ne(r,"return "+f).apply(v,o)}catch(p){throw p.source=f,p}return t?c(t):(c.source=f,c)},y.unescape=function(n){return null==n?"":oe(n).replace(Ze,ht)},y.uniqueId=function(n){var t=++d;return oe(null==n?"":n)+t},y.all=kt,y.any=Rt,y.detect=Ot,y.findWhere=Ot,y.foldl=Bt,y.foldr=Dt,y.include=Ct,y.inject=Bt,or(y,function(n,t){y.prototype[t]||(y.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return be.apply(t,arguments),t=n.apply(y,t),e?new m(t,e):t})}),y.first=$t,y.last=function(n,t,e){var r=0,u=n?n.length:0; +},y.isEmpty=function(n){var t=!0;if(!n)return t;var e=ke.call(n),r=n.length;return e==T||e==H||(We.argsClass?e==L:vt(n))||e==J&&typeof r=="number"&&_t(n.splice)?!r:(or(n,function(){return t=!1}),t)},y.isEqual=function(n,t,e,r){return et(n,t,typeof e=="function"&&Z(e,r,2))},y.isFinite=function(n){return Be(n)&&!De(parseFloat(n))},y.isFunction=_t,y.isNaN=function(n){return wt(n)&&n!=+n},y.isNull=function(n){return null===n},y.isNumber=wt,y.isObject=bt,y.isPlainObject=ar,y.isRegExp=function(n){return n&&Y[typeof n]?ke.call(n)==M:!1 +},y.isString=jt,y.isUndefined=function(n){return typeof n=="undefined"},y.lastIndexOf=function(n,t,e){var r=n?n.length:0;for(typeof e=="number"&&(r=(0>e?Pe(0,r+e):Re(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},y.mixin=Ut,y.noConflict=function(){return e._=pe,this},y.parseInt=pr,y.random=Vt,y.reduce=Dt,y.reduceRight=Nt,y.result=function(n,t){if(n){var e=n[t];return _t(e)?n[t]():e}},y.runInContext=h,y.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:He(n).length},y.some=Rt,y.sortedIndex=zt,y.template=function(n,t,e){var r=y.templateSettings; +n=oe(n||""),e=rr({},e,r);var u,o=rr({},e.imports,r.imports),r=He(o),o=xt(o),i=0,l=e.interpolate||N,f="__p+='",l=ue((e.escape||N).source+"|"+l.source+"|"+(l===B?S:N).source+"|"+(e.evaluate||N).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(R,a),e&&(f+="'+__e("+e+")+'"),l&&(u=!0,f+="';"+l+";__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),f+="';\n",l=e=e.variable,l||(e="obj",f="with("+e+"){"+f+"}"),f=(u?f.replace(C,""):f).replace(E,"$1").replace(O,"$1;"),f="function("+e+"){"+(l?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}"; +try{var c=ne(r,"return "+f).apply(v,o)}catch(p){throw p.source=f,p}return t?c(t):(c.source=f,c)},y.unescape=function(n){return null==n?"":oe(n).replace(Ze,ht)},y.uniqueId=function(n){var t=++d;return oe(null==n?"":n)+t},y.all=kt,y.any=Rt,y.detect=Ot,y.findWhere=Ot,y.foldl=Dt,y.foldr=Nt,y.include=Ct,y.inject=Dt,or(y,function(n,t){y.prototype[t]||(y.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return be.apply(t,arguments),t=n.apply(y,t),e?new m(t,e):t})}),y.first=$t,y.last=function(n,t,e){var r=0,u=n?n.length:0; if(typeof t!="number"&&null!=t){var o=u;for(t=y.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:v;return g(n,Pe(0,u-r))},y.sample=function(n,t,e){var r=n?n.length:0;return typeof r!="number"?n=xt(n):We.unindexedChars&&jt(n)&&(n=n.split("")),null==t||e?n?n[Vt(r-1)]:v:(n=Pt(n),n.length=Re(Pe(0,t),n.length),n)},y.take=$t,y.head=$t,or(y,function(n,t){var e="sample"!==t;y.prototype[t]||(y.prototype[t]=function(t,r){var u=this.__chain__,o=n(this.__wrapped__,t,r);return u||null!=t&&(!r||e&&typeof t=="function")?new m(o,u):o })}),y.VERSION="2.2.1",y.prototype.chain=function(){return this.__chain__=!0,this},y.prototype.toString=function(){return oe(this.__wrapped__)},y.prototype.value=Qt,y.prototype.valueOf=Qt,tr(["join","pop","shift"],function(n){var t=ie[n];y.prototype[n]=function(){var n=this.__chain__,e=t.apply(this.__wrapped__,arguments);return n?new m(e,n):e}}),tr(["push","reverse","sort","unshift"],function(n){var t=ie[n];y.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),tr(["concat","slice","splice"],function(n){var t=ie[n]; -y.prototype[n]=function(){return new m(t.apply(this.__wrapped__,arguments),this.__chain__)}}),We.spliceObjects||tr(["pop","shift","splice"],function(n){var t=ie[n],e="splice"==n;y.prototype[n]=function(){var n=this.__chain__,r=this.__wrapped__,u=t.apply(r,arguments);return 0===r.length&&delete r[0],n||e?new m(u,n):u}}),y}var v,y=[],m=[],d=0,_={},b=+new Date+"",w=75,j=40,x=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",C=/\b__p\+='';/g,E=/\b(__p\+=)''\+/g,O=/(__e\(.*?\)|\b__t\))\+'';/g,S=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,I=/\w*$/,A=/^function[ \n\r\t]+\w/,N=/<%=([\s\S]+?)%>/g,B=RegExp("^["+x+"]*0+(?=.$)"),D=/($^)/,P=/\bthis\b/,R=/['\n\r\t\u2028\u2029\\]/g,F="Array Boolean Date Error Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),$="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),L="[object Arguments]",T="[object Array]",z="[object Boolean]",q="[object Date]",K="[object Error]",W="[object Function]",G="[object Number]",J="[object Object]",M="[object RegExp]",H="[object String]",U={}; +y.prototype[n]=function(){return new m(t.apply(this.__wrapped__,arguments),this.__chain__)}}),We.spliceObjects||tr(["pop","shift","splice"],function(n){var t=ie[n],e="splice"==n;y.prototype[n]=function(){var n=this.__chain__,r=this.__wrapped__,u=t.apply(r,arguments);return 0===r.length&&delete r[0],n||e?new m(u,n):u}}),y}var v,y=[],m=[],d=0,_={},b=+new Date+"",w=75,j=40,x=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",C=/\b__p\+='';/g,E=/\b(__p\+=)''\+/g,O=/(__e\(.*?\)|\b__t\))\+'';/g,S=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,I=/\w*$/,A=/^function[ \n\r\t]+\w/,B=/<%=([\s\S]+?)%>/g,D=RegExp("^["+x+"]*0+(?=.$)"),N=/($^)/,P=/\bthis\b/,R=/['\n\r\t\u2028\u2029\\]/g,F="Array Boolean Date Error Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),$="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),L="[object Arguments]",T="[object Array]",z="[object Boolean]",q="[object Date]",K="[object Error]",W="[object Function]",G="[object Number]",J="[object Object]",M="[object RegExp]",H="[object String]",U={}; U[W]=!1,U[L]=U[T]=U[z]=U[q]=U[G]=U[J]=U[M]=U[H]=!0;var V={leading:!1,maxWait:0,trailing:!1},Q={configurable:!1,enumerable:!1,value:null,writable:!1},X={a:"",b:null,c:"",d:"",e:"",v:null,g:"",h:null,support:null,i:"",j:!1},Y={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},Z={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},nt=Y[typeof window]&&window||this,tt=Y[typeof exports]&&exports&&!exports.nodeType&&exports,et=Y[typeof module]&&module&&!module.nodeType&&module,rt=et&&et.exports===tt&&tt,ut=Y[typeof global]&&global; !ut||ut.global!==ut&&ut.window!==ut||(nt=ut);var ot=h();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(nt._=ot, define(function(){return ot})):tt&&et?rt?(et.exports=ot)._=ot:tt._=ot:nt._=ot}).call(this); \ No newline at end of file diff --git a/dist/lodash.js b/dist/lodash.js index f3ce4a521b..c8448f3657 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -814,24 +814,30 @@ if (typeof func != 'function') { return identity; } - // exit early if there is no `thisArg` - if (typeof thisArg == 'undefined') { + // exit early for no `thisArg` or already bound by `Function#bind` + if (typeof thisArg == 'undefined' || !('prototype' in func)) { return func; } - var bindData = func.__bindData__ || (support.funcNames && !func.name); + var bindData = func.__bindData__; if (typeof bindData == 'undefined') { - var source = reThis && fnToString.call(func); - if (!support.funcNames && source && !reFuncName.test(source)) { - bindData = true; + if (support.funcNames) { + bindData = !func.name; } - if (support.funcNames || !bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = !support.funcDecomp || reThis.test(source); - setBindData(func, bindData); + bindData = bindData || !support.funcDecomp; + if (!bindData) { + var source = fnToString.call(func); + if (!support.funcNames) { + bindData = !reFuncName.test(source); + } + if (!bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = reThis.test(source); + setBindData(func, bindData); + } } } // exit early if there are no `this` references or `func` is bound - if (bindData !== true && (bindData && bindData[1] & 1)) { + if (bindData === false || (bindData !== true && bindData[1] & 1)) { return func; } switch (argCount) { @@ -1252,7 +1258,7 @@ isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; - if (bindData) { + if (typeof bindData == 'object') { if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } diff --git a/dist/lodash.min.js b/dist/lodash.min.js index 96e61e9b0f..bb22f71e23 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -9,23 +9,23 @@ for(var r=-1,u=V[typeof n]&&Ke(n),o=u?u.length:0;++r=b&&f===n,h=u||v?i():s;if(v){var g=o(h);g?(f=t,h=g):(v=!1,h=u?h:(c(h),s))}for(;++af(h,y))&&((u||v)&&h.push(y),s.push(g))}return v?(c(h.k),p(h)):u&&c(h),s}function it(n){return function(t,e,r){var u={};e=Y.createCallback(e,r,3),r=-1;var o=t?t.length:0;if(typeof o=="number")for(;++re?Re(0,o+e):e)||0,Pe(n)?a=-1o&&(o=i)}}else t=!t&&wt(n)?r:Y.createCallback(t,e,3),It(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function Rt(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Xt(r);++earguments.length;t=et(t,r,4);var o=-1,a=n.length;if(typeof a=="number")for(u&&(e=n[++o]);++oarguments.length;return t=et(t,r,4),Nt(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o)}),e}function Bt(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return It(n,function(n){var e=Jt(++t);r[t]=r[e],r[e]=n}),r}function $t(n,t,e){var r;t=Y.createCallback(t,e,3),e=-1; -var u=n?n.length:0;if(typeof u=="number")for(;++e=b&&u===n;if(l){var c=o(i);c?(u=t,i=c):l=!1}for(;++ru(i,c)&&f.push(c);return l&&p(i),f}function Tt(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=-1;for(t=Y.createCallback(t,e,3);++or?Re(0,u+r):r||0}else if(r)return r=zt(t,e),t[r]===e?r:-1;return n(t,e,r)}function qt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=Y.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++te?Re(0,o+e):e)||0,Pe(n)?a=-1o&&(o=i)}}else t=!t&&wt(n)?r:Y.createCallback(t,e,3),It(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function Rt(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Xt(r);++earguments.length;t=et(t,r,4);var o=-1,a=n.length;if(typeof a=="number")for(u&&(e=n[++o]);++oarguments.length;return t=et(t,r,4),Nt(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o) +}),e}function Bt(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return It(n,function(n){var e=Jt(++t);r[t]=r[e],r[e]=n}),r}function $t(n,t,e){var r;t=Y.createCallback(t,e,3),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++e=b&&u===n;if(l){var c=o(i);c?(u=t,i=c):l=!1}for(;++ru(i,c)&&f.push(c);return l&&p(i),f}function Tt(n,t,e){var r=0,u=n?n.length:0; +if(typeof t!="number"&&null!=t){var o=-1;for(t=Y.createCallback(t,e,3);++or?Re(0,u+r):r||0}else if(r)return r=zt(t,e),t[r]===e?r:-1;return n(t,e,r)}function qt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=Y.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++t/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:N,variable:"",imports:{_:Y}},Oe||(lt=function(n){if(bt(n)){l.prototype=n;var t=new l;l.prototype=null}return t||{}});var ze=xe?function(n,t){U.value=t,xe(n,"__bindData__",U)}:l,Pe=Ie||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&je.call(n)==$||!1},Ke=Se?function(n){return bt(n)?Se(n):[] diff --git a/dist/lodash.underscore.js b/dist/lodash.underscore.js index 35cafb5186..f00b3da767 100644 --- a/dist/lodash.underscore.js +++ b/dist/lodash.underscore.js @@ -385,8 +385,8 @@ if (typeof func != 'function') { return identity; } - // exit early if there is no `thisArg` - if (typeof thisArg == 'undefined') { + // exit early for no `thisArg` or already bound by `Function#bind` + if (typeof thisArg == 'undefined' || !('prototype' in func)) { return func; } switch (argCount) { diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index 54be961173..9b3256165b 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -3,7 +3,7 @@ * Lo-Dash 2.2.1 (Custom Build) lodash.com/license | Underscore.js 1.5.2 underscorejs.org/LICENSE * Build: `lodash underscore exports="amd,commonjs,global,node" -o ./dist/lodash.underscore.js` */ -;(function(){function n(n,r,t){t=(t||0)-1;for(var e=n?n.length:0;++te||typeof t=="undefined")return 1;if(te||typeof t=="undefined")return 1;if(tu(f,l))&&(t&&f.push(l),i.push(a))}return i}function c(n){return function(r,t,e){var u={};t=K(t,e,3),e=-1;var o=r?r.length:0; diff --git a/lodash.js b/lodash.js index 94bd6447cf..f62561ee3e 100644 --- a/lodash.js +++ b/lodash.js @@ -1106,24 +1106,30 @@ if (typeof func != 'function') { return identity; } - // exit early if there is no `thisArg` - if (typeof thisArg == 'undefined') { + // exit early for no `thisArg` or already bound by `Function#bind` + if (typeof thisArg == 'undefined' || !('prototype' in func)) { return func; } - var bindData = func.__bindData__ || (support.funcNames && !func.name); + var bindData = func.__bindData__; if (typeof bindData == 'undefined') { - var source = reThis && fnToString.call(func); - if (!support.funcNames && source && !reFuncName.test(source)) { - bindData = true; + if (support.funcNames) { + bindData = !func.name; } - if (support.funcNames || !bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = !support.funcDecomp || reThis.test(source); - setBindData(func, bindData); + bindData = bindData || !support.funcDecomp; + if (!bindData) { + var source = fnToString.call(func); + if (!support.funcNames) { + bindData = !reFuncName.test(source); + } + if (!bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = reThis.test(source); + setBindData(func, bindData); + } } } // exit early if there are no `this` references or `func` is bound - if (bindData !== true && (bindData && bindData[1] & 1)) { + if (bindData === false || (bindData !== true && bindData[1] & 1)) { return func; } switch (argCount) { @@ -1544,7 +1550,7 @@ isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; - if (bindData) { + if (typeof bindData == 'object') { if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } diff --git a/test/test.js b/test/test.js index 2574dcee17..1fe31f18a6 100644 --- a/test/test.js +++ b/test/test.js @@ -625,7 +625,7 @@ strictEqual(_.isEqual(object, clone), true); if (_.isObject(object)) { - notEqual(clone, object); + notStrictEqual(clone, object); } else { strictEqual(clone, object); } @@ -640,7 +640,7 @@ test('`_.' + methodName + '` should clone problem JScript properties (test in IE < 9)', 2, function() { deepEqual(func(shadowedObject), shadowedObject); - notEqual(func(shadowedObject), shadowedObject); + notStrictEqual(func(shadowedObject), shadowedObject); }); test('`_.' + methodName + '` should pass the correct `callback` arguments', 1, function() { @@ -809,6 +809,47 @@ callback.apply(null, expected); deepEqual(args, expected); }); + + test('should return the passed function if already bound with `Function#bind`', 1, function() { + function a() {} + + if (Function.prototype.bind) { + var bound = a.bind(); + strictEqual(_.createCallback(bound, {}), bound); + } + else { + skipTest(); + } + }); + + test('should return the passed function when there is no `this` reference', 2, function() { + function a() {} + function b() { return this.b; } + + if (_.support.funcDecomp) { + strictEqual(_.createCallback(a, {}), a); + notStrictEqual(_.createCallback(b, {}), b); + } + else { + skipTest(2); + } + }); + + test('should only write `__bindData__` to named functions', 2, function() { + function a() {}; + var b = function() {}; + + if (_.support.funcNames || _.support.funcDecomp) { + _.createCallback(a, {}); + ok('__bindData__' in a) + + _.createCallback(b, {}); + ok(!('__bindData__' in b)); + } + else { + skipTest(2); + } + }); }()); /*--------------------------------------------------------------------------*/ @@ -4272,7 +4313,7 @@ result[key] = this[key]; }, null, object); - notEqual(actual, object); + notStrictEqual(actual, object); deepEqual(actual, object); }); }); From 613237727d8710b3451cf271e8cb04465c4272cf Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Oct 2013 22:36:43 -0700 Subject: [PATCH 003/189] Update path to perf-ui.js in perf/index.html. [ci skip] --- perf/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perf/index.html b/perf/index.html index 554895c474..2c559a334e 100644 --- a/perf/index.html +++ b/perf/index.html @@ -32,7 +32,7 @@ - + From 624e4bca40effe1f52f932ff4759cbcd479ac14e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Oct 2013 23:17:06 -0700 Subject: [PATCH 004/189] Tweak `__bindData__` detection in `createBound`. --- dist/lodash.compat.js | 2 +- dist/lodash.compat.min.js | 2 +- dist/lodash.js | 2 +- dist/lodash.min.js | 24 ++++++++++++------------ lodash.js | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index 037022e151..0b76e46f7f 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -1534,7 +1534,7 @@ isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; - if (typeof bindData == 'object') { + if (bindData && bindData !== true) { if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index fae5d45252..cceb342f84 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -12,7 +12,7 @@ if(l==L&&(l=J),c==L&&(c=J),l!=c)return!1;switch(l){case z:case q:return+n==+t;case G:return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case M:case H:return n==oe(t)}if(c=l==T,!c){if(de.call(n,"__wrapped__")||de.call(t,"__wrapped__"))return et(n.__wrapped__||n,t.__wrapped__||t,e,r,u,o);if(l!=J||!We.nodeClass&&(f(n)||f(t)))return!1;var l=!We.argsObject&&vt(n)?re:n.constructor,s=!We.argsObject&&vt(t)?re:t.constructor;if(l!=s&&!(_t(l)&&l instanceof l&&_t(s)&&s instanceof s))return!1}for(s=!u,u||(u=i()),o||(o=i()),l=u.length;l--;)if(u[l]==n)return o[l]==t; var g=0,a=!0;if(u.push(n),o.push(t),c){if(l=n.length,g=t.length,a=g==n.length,!a&&!r)return a;for(;g--;)if(c=l,s=t[g],r)for(;c--&&!(a=et(n[c],s,e,r,u,o)););else if(!(a=et(n[g],s,e,r,u,o)))break;return a}return ur(t,function(t,i,l){return de.call(l,i)?(g++,a=de.call(n,i)&&et(n[i],t,e,r,u,o)):void 0}),a&&!r&&ur(n,function(n,t,e){return de.call(e,t)?a=-1<--g:void 0}),s&&(p(u),p(o)),a}function ut(n,t,e,r,u){(Je(t)?St:or)(t,function(t,o){var a,i,l=t,f=n[o];if(t&&((i=Je(t))||ar(t))){for(l=r.length;l--;)if(a=r[l]==t){f=u[l]; break}if(!a){var c;e&&(l=e(f,t),c=typeof l!="undefined")&&(f=l),c||(f=i?Je(f)?f:[]:ar(f)?f:{}),r.push(t),u.push(f),c||ut(f,t,e,r,u)}}else e&&(l=e(f,t),typeof l=="undefined"&&(l=t)),typeof l!="undefined"&&(f=l);n[o]=f})}function at(e,r,u){var a=-1,l=st(),f=e?e.length:0,c=[],g=!r&&f>=w&&l===n,h=u||g?i():c;if(g){var v=o(h);v?(l=t,h=v):(g=!1,h=u?h:(p(h),c))}for(;++al(h,y))&&((u||g)&&h.push(y),c.push(v))}return g?(p(h.k),s(h)):u&&p(h),c}function it(n){return function(t,e,r){var u={}; -if(e=y.createCallback(e,r,3),Je(t)){r=-1;for(var o=t.length;++rk;k++)r+="n='"+e.h[k]+"';if((!(r&&x[n])&&m.call(t,n))",e.j||(r+="||(!x[n]&&t[n]!==A[n])"),r+="){"+e.g+"}";r+="}"}return(e.b||We.nonEnumArgs)&&(r+="}"),r+=e.c+";return E",n("d,j,k,m,o,p,q,s,v,A,B,y,I,J,L",t+r+"}")(Z,K,le,de,_,vt,Je,jt,X.f,fe,Y,Ke,H,ce,ke) diff --git a/dist/lodash.js b/dist/lodash.js index c8448f3657..ab9e02ca0e 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -1258,7 +1258,7 @@ isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; - if (typeof bindData == 'object') { + if (bindData && bindData !== true) { if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } diff --git a/dist/lodash.min.js b/dist/lodash.min.js index bb22f71e23..6537afd074 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -14,18 +14,18 @@ if(!u)return o;var a=arguments,i=0,f=typeof e=="number"?2:a.length;if(3=b&&f===n,h=u||v?i():s;if(v){var g=o(h);g?(f=t,h=g):(v=!1,h=u?h:(c(h),s))}for(;++af(h,y))&&((u||v)&&h.push(y),s.push(g))}return v?(c(h.k),p(h)):u&&c(h),s}function it(n){return function(t,e,r){var u={};e=Y.createCallback(e,r,3),r=-1;var o=t?t.length:0;if(typeof o=="number")for(;++re?Re(0,o+e):e)||0,Pe(n)?a=-1o&&(o=i)}}else t=!t&&wt(n)?r:Y.createCallback(t,e,3),It(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function Rt(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Xt(r);++earguments.length;t=et(t,r,4);var o=-1,a=n.length;if(typeof a=="number")for(u&&(e=n[++o]);++oarguments.length;return t=et(t,r,4),Nt(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o) -}),e}function Bt(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return It(n,function(n){var e=Jt(++t);r[t]=r[e],r[e]=n}),r}function $t(n,t,e){var r;t=Y.createCallback(t,e,3),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++e=b&&u===n;if(l){var c=o(i);c?(u=t,i=c):l=!1}for(;++ru(i,c)&&f.push(c);return l&&p(i),f}function Tt(n,t,e){var r=0,u=n?n.length:0; -if(typeof t!="number"&&null!=t){var o=-1;for(t=Y.createCallback(t,e,3);++or?Re(0,u+r):r||0}else if(r)return r=zt(t,e),t[r]===e?r:-1;return n(t,e,r)}function qt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=Y.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++te?Re(0,o+e):e)||0,Pe(n)?a=-1o&&(o=i)}}else t=!t&&wt(n)?r:Y.createCallback(t,e,3),It(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function Rt(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Xt(r);++earguments.length;t=et(t,r,4);var o=-1,a=n.length;if(typeof a=="number")for(u&&(e=n[++o]);++oarguments.length;return t=et(t,r,4),Nt(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o)}),e}function Bt(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return It(n,function(n){var e=Jt(++t);r[t]=r[e],r[e]=n}),r}function $t(n,t,e){var r;t=Y.createCallback(t,e,3),e=-1; +var u=n?n.length:0;if(typeof u=="number")for(;++e=b&&u===n;if(l){var c=o(i);c?(u=t,i=c):l=!1}for(;++ru(i,c)&&f.push(c);return l&&p(i),f}function Tt(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=-1;for(t=Y.createCallback(t,e,3);++or?Re(0,u+r):r||0}else if(r)return r=zt(t,e),t[r]===e?r:-1;return n(t,e,r)}function qt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=Y.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++t/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:N,variable:"",imports:{_:Y}},Oe||(lt=function(n){if(bt(n)){l.prototype=n;var t=new l;l.prototype=null}return t||{}});var ze=xe?function(n,t){U.value=t,xe(n,"__bindData__",U)}:l,Pe=Ie||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&je.call(n)==$||!1},Ke=Se?function(n){return bt(n)?Se(n):[] diff --git a/lodash.js b/lodash.js index f62561ee3e..a0adc2f440 100644 --- a/lodash.js +++ b/lodash.js @@ -1550,7 +1550,7 @@ isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; - if (typeof bindData == 'object') { + if (bindData && bindData !== true) { if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } From ba5e512d10b241b35075edecb2f963ce78c1db25 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Oct 2013 23:21:47 -0700 Subject: [PATCH 005/189] Ensure `_.template` supports single line comments in "evaluate" delimiters in minified builds. [closes #361] --- dist/lodash.compat.min.js | 2 +- dist/lodash.min.js | 2 +- dist/lodash.underscore.min.js | 2 +- test/test.js | 7 ++++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index cceb342f84..6b70f9e73b 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -47,7 +47,7 @@ return a},y.tap=function(n,t){return t(n),n},y.throttle=function(n,t,e){var r=!0 }),r},y.findLastIndex=function(n,t,e){var r=n?n.length:0;for(t=y.createCallback(t,e,3);r--;)if(t(n[r],r,n))return r;return-1},y.findLastKey=function(n,t,e){var r;return t=y.createCallback(t,e,3),yt(n,function(n,e,u){return t(n,e,u)?(r=e,!1):void 0}),r},y.has=function(n,t){return n?de.call(n,t):!1},y.identity=Ht,y.indexOf=Lt,y.isArguments=vt,y.isArray=Je,y.isBoolean=function(n){return true===n||false===n||ke.call(n)==z},y.isDate=function(n){return n?typeof n=="object"&&ke.call(n)==q:!1},y.isElement=function(n){return n?1===n.nodeType:!1 },y.isEmpty=function(n){var t=!0;if(!n)return t;var e=ke.call(n),r=n.length;return e==T||e==H||(We.argsClass?e==L:vt(n))||e==J&&typeof r=="number"&&_t(n.splice)?!r:(or(n,function(){return t=!1}),t)},y.isEqual=function(n,t,e,r){return et(n,t,typeof e=="function"&&Z(e,r,2))},y.isFinite=function(n){return Be(n)&&!De(parseFloat(n))},y.isFunction=_t,y.isNaN=function(n){return wt(n)&&n!=+n},y.isNull=function(n){return null===n},y.isNumber=wt,y.isObject=bt,y.isPlainObject=ar,y.isRegExp=function(n){return n&&Y[typeof n]?ke.call(n)==M:!1 },y.isString=jt,y.isUndefined=function(n){return typeof n=="undefined"},y.lastIndexOf=function(n,t,e){var r=n?n.length:0;for(typeof e=="number"&&(r=(0>e?Pe(0,r+e):Re(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},y.mixin=Ut,y.noConflict=function(){return e._=pe,this},y.parseInt=pr,y.random=Vt,y.reduce=Dt,y.reduceRight=Nt,y.result=function(n,t){if(n){var e=n[t];return _t(e)?n[t]():e}},y.runInContext=h,y.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:He(n).length},y.some=Rt,y.sortedIndex=zt,y.template=function(n,t,e){var r=y.templateSettings; -n=oe(n||""),e=rr({},e,r);var u,o=rr({},e.imports,r.imports),r=He(o),o=xt(o),i=0,l=e.interpolate||N,f="__p+='",l=ue((e.escape||N).source+"|"+l.source+"|"+(l===B?S:N).source+"|"+(e.evaluate||N).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(R,a),e&&(f+="'+__e("+e+")+'"),l&&(u=!0,f+="';"+l+";__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),f+="';\n",l=e=e.variable,l||(e="obj",f="with("+e+"){"+f+"}"),f=(u?f.replace(C,""):f).replace(E,"$1").replace(O,"$1;"),f="function("+e+"){"+(l?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}"; +n=oe(n||""),e=rr({},e,r);var u,o=rr({},e.imports,r.imports),r=He(o),o=xt(o),i=0,l=e.interpolate||N,f="__p+='",l=ue((e.escape||N).source+"|"+l.source+"|"+(l===B?S:N).source+"|"+(e.evaluate||N).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(R,a),e&&(f+="'+__e("+e+")+'"),l&&(u=!0,f+="';"+l+";\n__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),f+="';",l=e=e.variable,l||(e="obj",f="with("+e+"){"+f+"}"),f=(u?f.replace(C,""):f).replace(E,"$1").replace(O,"$1;"),f="function("+e+"){"+(l?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}"; try{var c=ne(r,"return "+f).apply(v,o)}catch(p){throw p.source=f,p}return t?c(t):(c.source=f,c)},y.unescape=function(n){return null==n?"":oe(n).replace(Ze,ht)},y.uniqueId=function(n){var t=++d;return oe(null==n?"":n)+t},y.all=kt,y.any=Rt,y.detect=Ot,y.findWhere=Ot,y.foldl=Dt,y.foldr=Nt,y.include=Ct,y.inject=Dt,or(y,function(n,t){y.prototype[t]||(y.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return be.apply(t,arguments),t=n.apply(y,t),e?new m(t,e):t})}),y.first=$t,y.last=function(n,t,e){var r=0,u=n?n.length:0; if(typeof t!="number"&&null!=t){var o=u;for(t=y.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:v;return g(n,Pe(0,u-r))},y.sample=function(n,t,e){var r=n?n.length:0;return typeof r!="number"?n=xt(n):We.unindexedChars&&jt(n)&&(n=n.split("")),null==t||e?n?n[Vt(r-1)]:v:(n=Pt(n),n.length=Re(Pe(0,t),n.length),n)},y.take=$t,y.head=$t,or(y,function(n,t){var e="sample"!==t;y.prototype[t]||(y.prototype[t]=function(t,r){var u=this.__chain__,o=n(this.__wrapped__,t,r);return u||null!=t&&(!r||e&&typeof t=="function")?new m(o,u):o })}),y.VERSION="2.2.1",y.prototype.chain=function(){return this.__chain__=!0,this},y.prototype.toString=function(){return oe(this.__wrapped__)},y.prototype.value=Qt,y.prototype.valueOf=Qt,tr(["join","pop","shift"],function(n){var t=ie[n];y.prototype[n]=function(){var n=this.__chain__,e=t.apply(this.__wrapped__,arguments);return n?new m(e,n):e}}),tr(["push","reverse","sort","unshift"],function(n){var t=ie[n];y.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),tr(["concat","slice","splice"],function(n){var t=ie[n]; diff --git a/dist/lodash.min.js b/dist/lodash.min.js index 6537afd074..736cf6e9c3 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -45,7 +45,7 @@ return a},Y.tap=function(n,t){return t(n),n},Y.throttle=function(n,t,e){var r=!0 }),r},Y.findLastIndex=function(n,t,e){var r=n?n.length:0;for(t=Y.createCallback(t,e,3);r--;)if(t(n[r],r,n))return r;return-1},Y.findLastKey=function(n,t,e){var r;return t=Y.createCallback(t,e,3),gt(n,function(n,e,u){return t(n,e,u)?(r=e,!1):void 0}),r},Y.has=function(n,t){return n?ye.call(n,t):!1},Y.identity=Gt,Y.indexOf=Wt,Y.isArguments=ht,Y.isArray=Pe,Y.isBoolean=function(n){return true===n||false===n||je.call(n)==F},Y.isDate=function(n){return n?typeof n=="object"&&je.call(n)==T:!1},Y.isElement=function(n){return n?1===n.nodeType:!1 },Y.isEmpty=function(n){var t=!0;if(!n)return t;var e=je.call(n),r=n.length;return e==$||e==K||e==B||e==z&&typeof r=="number"&&_t(n.splice)?!r:(y(n,function(){return t=!1}),t)},Y.isEqual=function(n,t,e,r){return ut(n,t,typeof e=="function"&&et(e,r,2))},Y.isFinite=function(n){return Ne(n)&&!Ee(parseFloat(n))},Y.isFunction=_t,Y.isNaN=function(n){return dt(n)&&n!=+n},Y.isNull=function(n){return null===n},Y.isNumber=dt,Y.isObject=bt,Y.isPlainObject=g,Y.isRegExp=function(n){return n?typeof n=="object"&&je.call(n)==P:!1 },Y.isString=wt,Y.isUndefined=function(n){return typeof n=="undefined"},Y.lastIndexOf=function(n,t,e){var r=n?n.length:0;for(typeof e=="number"&&(r=(0>e?Re(0,r+e):Ae(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},Y.mixin=Ht,Y.noConflict=function(){return e._=le,this},Y.parseInt=Qe,Y.random=Jt,Y.reduce=At,Y.reduceRight=Dt,Y.result=function(n,t){if(n){var e=n[t];return _t(e)?n[t]():e}},Y.runInContext=v,Y.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Ke(n).length},Y.some=$t,Y.sortedIndex=zt,Y.template=function(n,t,e){var r=Y.templateSettings; -n=oe(n||""),e=G({},e,r);var u,o=G({},e.imports,r.imports),r=Ke(o),o=jt(o),i=0,f=e.interpolate||S,l="__p+='",f=ue((e.escape||S).source+"|"+f.source+"|"+(f===N?C:S).source+"|"+(e.evaluate||S).source+"|$","g");n.replace(f,function(t,e,r,o,f,c){return r||(r=o),l+=n.slice(i,c).replace(A,a),e&&(l+="'+__e("+e+")+'"),f&&(u=!0,l+="';"+f+";__p+='"),r&&(l+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),l+="';\n",f=e=e.variable,f||(e="obj",l="with("+e+"){"+l+"}"),l=(u?l.replace(j,""):l).replace(k,"$1").replace(x,"$1;"),l="function("+e+"){"+(f?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}"; +n=oe(n||""),e=G({},e,r);var u,o=G({},e.imports,r.imports),r=Ke(o),o=jt(o),i=0,f=e.interpolate||S,l="__p+='",f=ue((e.escape||S).source+"|"+f.source+"|"+(f===N?C:S).source+"|"+(e.evaluate||S).source+"|$","g");n.replace(f,function(t,e,r,o,f,c){return r||(r=o),l+=n.slice(i,c).replace(A,a),e&&(l+="'+__e("+e+")+'"),f&&(u=!0,l+="';"+f+";\n__p+='"),r&&(l+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t}),l+="';",f=e=e.variable,f||(e="obj",l="with("+e+"){"+l+"}"),l=(u?l.replace(j,""):l).replace(k,"$1").replace(x,"$1;"),l="function("+e+"){"+(f?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}"; try{var c=ne(r,"return "+l).apply(h,o)}catch(p){throw p.source=l,p}return t?c(t):(c.source=l,c)},Y.unescape=function(n){return null==n?"":oe(n).replace(Ue,vt)},Y.uniqueId=function(n){var t=++m;return oe(null==n?"":n)+t},Y.all=xt,Y.any=$t,Y.detect=Ot,Y.findWhere=Ot,Y.foldl=At,Y.foldr=Dt,Y.include=kt,Y.inject=At,y(Y,function(n,t){Y.prototype[t]||(Y.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return _e.apply(t,arguments),t=n.apply(Y,t),e?new nt(t,e):t})}),Y.first=Tt,Y.last=function(n,t,e){var r=0,u=n?n.length:0; if(typeof t!="number"&&null!=t){var o=u;for(t=Y.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:h;return s(n,Re(0,u-r))},Y.sample=function(n,t,e){var r=n?n.length:0;return typeof r!="number"&&(n=jt(n)),null==t||e?n?n[Jt(r-1)]:h:(n=Bt(n),n.length=Ae(Re(0,t),n.length),n)},Y.take=Tt,Y.head=Tt,y(Y,function(n,t){var e="sample"!==t;Y.prototype[t]||(Y.prototype[t]=function(t,r){var u=this.__chain__,o=n(this.__wrapped__,t,r);return u||null!=t&&(!r||e&&typeof t=="function")?new nt(o,u):o })}),Y.VERSION="2.2.1",Y.prototype.chain=function(){return this.__chain__=!0,this},Y.prototype.toString=function(){return oe(this.__wrapped__)},Y.prototype.value=Qt,Y.prototype.valueOf=Qt,It(["join","pop","shift"],function(n){var t=ie[n];Y.prototype[n]=function(){var n=this.__chain__,e=t.apply(this.__wrapped__,arguments);return n?new nt(e,n):e}}),It(["push","reverse","sort","unshift"],function(n){var t=ie[n];Y.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),It(["concat","slice","splice"],function(n){var t=ie[n]; diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index 9b3256165b..1a4a7a6276 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -32,7 +32,7 @@ o in n&&(u[o]=n[o])}return u},u.pluck=D,u.range=function(n,r,t){n=+n||0,t=+t||1, },u.wrap=function(n,r){if(!j(r))throw new TypeError;return function(){var t=[n];return Sr.apply(t,arguments),r.apply(this,t)}},u.zip=function(){for(var n=-1,r=q(D(arguments,"length")),t=Array(0>r?0:r);++nt?$r(0,e+t):Ir(t,e-1))+1);e--;)if(n[e]===r)return e;return-1},u.mixin=X,u.noConflict=function(){return gr._=jr,this},u.random=Y,u.reduce=M,u.reduceRight=$,u.result=function(n,r){if(n){var t=n[r];return j(t)?n[r]():t}},u.size=function(n){var r=n?n.length:0;return typeof r=="number"?r:Hr(n).length -},u.some=W,u.sortedIndex=G,u.template=function(n,r,e){var o=u,i=o.templateSettings;n=(n||"")+"",e=_({},e,i);var f=0,a="__p+='",i=e.variable;n.replace(RegExp((e.escape||er).source+"|"+(e.interpolate||er).source+"|"+(e.evaluate||er).source+"|$","g"),function(r,e,u,o,i){return a+=n.slice(f,i).replace(ur,t),e&&(a+="'+_.escape("+e+")+'"),o&&(a+="';"+o+";__p+='"),u&&(a+="'+((__t=("+u+"))==null?'':__t)+'"),f=i+r.length,r}),a+="';\n",i||(i="obj",a="with("+i+"||{}){"+a+"}"),a="function("+i+"){var __t,__p='',__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+a+"return __p}"; +},u.some=W,u.sortedIndex=G,u.template=function(n,r,e){var o=u,i=o.templateSettings;n=(n||"")+"",e=_({},e,i);var f=0,a="__p+='",i=e.variable;n.replace(RegExp((e.escape||er).source+"|"+(e.interpolate||er).source+"|"+(e.evaluate||er).source+"|$","g"),function(r,e,u,o,i){return a+=n.slice(f,i).replace(ur,t),e&&(a+="'+_.escape("+e+")+'"),o&&(a+="';"+o+";\n__p+='"),u&&(a+="'+((__t=("+u+"))==null?'':__t)+'"),f=i+r.length,r}),a+="';",i||(i="obj",a="with("+i+"||{}){"+a+"}"),a="function("+i+"){var __t,__p='',__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+a+"return __p}"; try{var l=Function("_","return "+a)(o)}catch(c){throw c.source=a,c}return r?l(r):(l.source=a,l)},u.unescape=function(n){return null==n?"":(n+"").replace(Lr,g)},u.uniqueId=function(n){var r=++nr+"";return n?n+r:r},u.all=S,u.any=W,u.detect=N,u.findWhere=function(n,r){return z(n,r,!0)},u.foldl=M,u.foldr=$,u.include=O,u.inject=M,u.first=P,u.last=function(n,r,t){var e=0,u=n?n.length:0;if(typeof r!="number"&&null!=r){var o=u;for(r=K(r,t,3);o--&&r(n[o],o,n);)e++}else if(e=r,null==e||t)return n?n[u-1]:Z; return zr.call(n,$r(0,u-e))},u.sample=function(n,r,t){var e=n?n.length:0;return typeof e!="number"&&(n=A(n)),null==r||t?n?n[Y(e-1)]:Z:(n=I(n),n.length=Ir($r(0,r),n.length),n)},u.take=P,u.head=P,X(u),u.VERSION="2.2.1",u.prototype.chain=function(){return this.__chain__=!0,this},u.prototype.value=function(){return this.__wrapped__},R("pop push reverse shift sort splice unshift".split(" "),function(n){var r=br[n];u.prototype[n]=function(){var n=this.__wrapped__;return r.apply(n,arguments),Ur.spliceObjects||0!==n.length||delete n[0],this }}),R(["concat","join","slice"],function(n){var r=br[n];u.prototype[n]=function(){var n=r.apply(this.__wrapped__,arguments);return this.__chain__&&(n=new o(n),n.__chain__=!0),n}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(gr._=u, define(function(){return u})):yr&&mr?_r?(mr.exports=u)._=u:yr._=u:gr._=u}).call(this); \ No newline at end of file diff --git a/test/test.js b/test/test.js index 1fe31f18a6..6f6ec1879d 100644 --- a/test/test.js +++ b/test/test.js @@ -3975,12 +3975,17 @@ strictEqual(compiled({}), '1'); }); - test('should coerce `text` argument to a string', function() { + test('should coerce `text` argument to a string', 1, function() { var data = { 'a': 1 }, object = { 'toString': function() { return '<%= a %>'; } }; strictEqual(_.template(object, data), '1'); }); + + test('should support single line comments in "evaluate" delimiters (test production builds)', 1, function() { + var compiled = _.template('<% // comment %><% if (value) { %>yap<% } else { %>nope<% } %>'); + equal(compiled({ 'value': true }), 'yap'); + }); }()); /*--------------------------------------------------------------------------*/ From 61f1290beac13c3b799f7deb3b472a946b658f57 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Oct 2013 23:57:58 -0700 Subject: [PATCH 006/189] Update vendor/curl.js to v0.8.2. --- vendor/curl/dist/curl-kitchen-sink/curl.js | 88 +++++++++++----------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/vendor/curl/dist/curl-kitchen-sink/curl.js b/vendor/curl/dist/curl-kitchen-sink/curl.js index 63ae45cd98..01337d10e7 100644 --- a/vendor/curl/dist/curl-kitchen-sink/curl.js +++ b/vendor/curl/dist/curl-kitchen-sink/curl.js @@ -1,48 +1,48 @@ (function(){/* MIT License (c) copyright 2010-2013 B Cavalier & J Hann MIT (c) copyright 2010-2013 B Cavalier & J Hann */ -(function(d){function l(){}function k(b,e){return 0==U.call(b).indexOf("[object "+e)}function n(b){return b&&"/"==b.charAt(b.length-1)?b.substr(0,b.length-1):b}function h(b,e){var m,g,x,P;m=1;g=b;"."==g.charAt(0)&&(x=!0,g=g.replace(V,function(b,e,g,x){g&&m++;return x||""}));if(x){x=e.split("/");P=x.length-m;if(0>P)return b;x.splice(P,m);return x.concat(g||[]).join("/")}return g}function p(b){var e=b.indexOf("!");return{h:b.substr(e+1),e:0<=e&&b.substr(0,e)}}function v(){}function r(b,e){v.prototype= -b||Q;var m=new v;v.prototype=Q;for(var g in e)m[g]=e[g];return m}function z(){function b(b,e,m){g.push([b,e,m])}function e(b,e){for(var m,x=0;m=g[x++];)(m=m[b])&&m(e)}var m,g,x;m=this;g=[];x=function(m,f){b=m?function(b){b&&b(f)}:function(b,e){e&&e(f)};x=l;e(m?0:1,f);e=l;g=G};this.j=function(e,g,x){b(e,g,x);return m};this.g=function(b){m.I=b;x(!0,b)};this.d=function(b){m.Aa=b;x(!1,b)};this.G=function(b){e(2,b)}}function y(b){return b instanceof z||b instanceof t}function q(b,e,m,g){y(b)?b.j(e,m,g): -e(b)}function w(b,e,m){var g;return function(){0<=--b&&e&&(g=e.apply(G,arguments));0==b&&m&&m(g);return g}}function c(){var b,e;b=[].slice.call(arguments);k(b[0],"Object")&&(e=b.shift(),e=a(e));return new t(b[0],b[1],b[2],e)}function a(b,e,m){var g,x,a;if(b&&(u.V(b),f=u.b(b),"preloads"in b&&(g=new t(b.preloads,G,m,J,!0),u.C(function(){J=g})),a=(a=b.main)&&String(a).split(W)))return x=new z,x.j(e,m),b=a[1]?function(){new t([a[1]],x.g,x.d)}:x.d,new t([a[0]],x.g,b),x}function t(b,e,m,g,x){var s;s=u.k(f, -G,[].concat(b),x);this.then=this.j=b=function(b,e){q(s,function(e){b&&b.apply(G,e)},function(b){if(e)e(b);else throw b;});return this};this.next=function(b,e,g){return new t(b,e,g,s)};this.config=a;(e||m)&&b(e,m);u.C(function(){q(x||J,function(){q(g,function(){u.A(s)},m)})})}function A(b){var e,m;e=b.id;e==G&&(K!==G?K={M:"Multiple anonymous defines encountered"}:(e=u.ia())||(K=b));if(e!=G){m=E[e];e in E||(m=u.m(e,f),m=u.J(m.b,e),E[e]=m);if(!y(m))throw Error("duplicate define: "+e);m.na=!1;u.K(m,b)}} -function C(){var b=u.fa(arguments);A(b)}var f,B,F,H=d.document,D=H&&(H.head||H.getElementsByTagName("head")[0]),R=D&&D.getElementsByTagName("base")[0]||null,L={},M={},I={},s="addEventListener"in d?{}:{loaded:1,complete:1},Q={},U=Q.toString,G,E={},N={},J=!1,K,T=/^\/|^[^:]+:\/\//,V=/(\.)(\.?)(?:$|\/([^\.\/]+.*)?)/g,X=/\/\*[\s\S]*?\*\/|\/\/.*?[\n\r]/g,Y=/require\s*\(\s*(["'])(.*?[^\\])\1\s*\)|[^\\]?(["'])/g,W=/\s*,\s*/,S,u;u={t:function(b,e,m){var g;b=h(b,e);if("."==b.charAt(0))return b;g=p(b);b=(e= -g.e)||g.h;b in m.c&&(b=m.c[b].q||b);e&&(0>e.indexOf("/")&&!(e in m.c)&&(b=n(m.T)+"/"+e),b=b+"!"+g.h);return b},k:function(b,e,m,g){function x(e,g){var m,a;m=u.t(e,f.id,b);if(!g)return m;a=p(m);if(!a.e)return m;m=E[a.e];a.h="normalize"in m?m.normalize(a.h,x,f.b)||"":x(a.h);return a.e+"!"+a.h}function a(e,m,s){var c;c=m&&function(b){m.apply(G,b)};if(k(e,"String")){if(c)throw Error("require(id, callback) not allowed");s=x(e,!0);e=E[s];if(!(s in E))throw Error("Module not resolved: "+s);return(s=y(e)&& -e.a)||e}q(u.A(u.k(b,f.id,e,g)),c,s)}var f;f=new z;f.id=e||"";f.ja=g;f.L=m;f.b=b;f.s=a;a.toUrl=function(e){return u.m(x(e,!0),b).url};f.t=x;return f},J:function(b,e,m){var g,x,a;g=u.k(b,e,G,m);x=g.g;a=w(1,function(b){g.w=b;try{return u.aa(g)}catch(e){g.d(e)}});g.g=function(b){q(m||J,function(){x(E[g.id]=N[g.url]=a(b))})};g.N=function(b){q(m||J,function(){g.a&&(a(b),g.G(M))})};return g},Z:function(b,e,m,g){return u.k(b,m,G,g)},ha:function(b){return b.s},P:function(b){return b.a||(b.a={})},ga:function(b){var e= -b.B;e||(e=b.B={id:b.id,uri:u.Q(b),exports:u.P(b),config:function(){return b.b}},e.a=e.exports);return e},Q:function(b){return b.url||(b.url=u.u(b.s.toUrl(b.id),b.b))},V:function(b){var e,m,g,a,f;e="curl";m="define";g=a=d;if(b&&(f=b.overwriteApi||b.xa,e=b.apiName||b.pa||e,g=b.apiContext||b.oa||g,m=b.defineName||b.ta||m,a=b.defineContext||b.sa||a,B&&k(B,"Function")&&(d.curl=B),B=null,F&&k(F,"Function")&&(d.define=F),F=null,!f)){if(g[e]&&g[e]!=c)throw Error(e+" already exists");if(a[m]&&a[m]!=C)throw Error(m+ -" already exists");}g[e]=c;a[m]=C},b:function(b){function e(b,e){var m,g,f,c,d;for(d in b){f=b[d];k(f,"String")&&(f={path:b[d]});f.name=f.name||d;c=a;g=p(n(f.name));m=g.h;if(g=g.e)c=s[g],c||(c=s[g]=r(a),c.c=r(a.c),c.f=[]),delete b[d];g=f;var l=e,q=void 0;g.path=n(g.path||g.location||"");l&&(q=g.main||"./main","."==q.charAt(0)||(q="./"+q),g.q=h(q,g.name+"/"));g.b=g.config;g.b&&(g.b=r(a,g.b));g.W=m.split("/").length;m?(c.c[m]=g,c.f.push(m)):c.n=u.U(f.path,a)}}function m(b){var e=b.c;b.S=RegExp("^("+ -b.f.sort(function(b,g){return e[g].W-e[b].W}).join("|").replace(/\/|\./g,"\\$&")+")(?=\\/|$)");delete b.f}var g,a,s,c;"baseUrl"in b&&(b.n=b.baseUrl);"main"in b&&(b.q=b.main);"preloads"in b&&(b.ya=b.preloads);"pluginPath"in b&&(b.T=b.pluginPath);if("dontAddFileExt"in b||b.l)b.l=RegExp(b.dontAddFileExt||b.l);g=f;a=r(g,b);a.c=r(g.c);s=b.plugins||{};a.plugins=r(g.plugins);a.F=r(g.F,b.F);a.D=r(g.D,b.D);a.f=[];e(b.packages,!0);e(b.paths,!1);for(c in s)b=u.t(c+"!","",a),a.plugins[b.substr(0,b.length-1)]= -s[c];s=a.plugins;for(c in s)if(s[c]=r(a,s[c]),b=s[c].f)s[c].f=b.concat(a.f),m(s[c]);for(c in g.c)a.c.hasOwnProperty(c)||a.f.push(c);m(a);return a},m:function(b,e){var a,g,c,s;a=e.c;c=T.test(b)?b:b.replace(e.S,function(b){g=a[b]||{};s=g.b;return g.path||""});return{b:s||f,url:u.U(c,e)}},U:function(b,e){var a=e.n;return a&&!T.test(b)?n(a)+"/"+b:b},u:function(b,e){return b+((e||f).l.test(b)?"":".js")},p:function(b,e,a){var g=H.createElement("script");g.onload=g.onreadystatechange=function(a){a=a||d.event; -if("load"==a.type||s[g.readyState])delete I[b.id],g.onload=g.onreadystatechange=g.onerror="",e()};g.onerror=function(){a(Error("Syntax or http error: "+b.url))};g.type=b.r||"text/javascript";g.charset="utf-8";g.async=!b.R;g.src=b.url;I[b.id]=g;D.insertBefore(g,R);return g},O:function(b){var e=[],a;("string"==typeof b?b:b.toSource?b.toSource():b.toString()).replace(X,"").replace(Y,function(b,f,c,s){s?a=a==s?G:a:a||e.push(c);return""});return e},fa:function(b){var e,a,g,f,c,s;c=b.length;g=b[c-1];f= -k(g,"Function")?g.length:-1;2==c?k(b[0],"Array")?a=b[0]:e=b[0]:3==c&&(e=b[0],a=b[1]);!a&&0P)return b;x.splice(P,m);return x.concat(h||[]).join("/")}return h}function p(b){var d=b.indexOf("!");return{h:b.substr(d+1),e:0<=d&&b.substr(0,d)}}function v(){}function s(b,d){v.prototype= +b||Q;var m=new v;v.prototype=Q;for(var h in d)m[h]=d[h];return m}function z(){function b(b,d,m){h.push([b,d,m])}function d(b,d){for(var m,x=0;m=h[x++];)(m=m[b])&&m(d)}var m,h,x;m=this;h=[];x=function(m,g){b=m?function(b){b&&b(g)}:function(b,d){d&&d(g)};x=l;d(m?0:1,g);d=l;h=G};this.j=function(d,h,x){b(d,h,x);return m};this.g=function(b){m.I=b;x(!0,b)};this.d=function(b){m.Aa=b;x(!1,b)};this.G=function(b){d(2,b)}}function y(b){return b instanceof z||b instanceof t}function q(b,d,m,h){y(b)?b.j(d,m,h): +d(b)}function w(b,d,m){var h;return function(){0<=--b&&d&&(h=d.apply(G,arguments));0==b&&m&&m(h);return h}}function c(){var b,d;b=[].slice.call(arguments);k(b[0],"Object")&&(d=b.shift(),d=a(d));return new t(b[0],b[1],b[2],d)}function a(b,d,m){var h,x,a;if(b&&(u.V(b),g=u.b(b),"preloads"in b&&(h=new t(b.preloads,G,m,J,!0),u.C(function(){J=h})),a=(a=b.main)&&String(a).split(W)))return x=new z,x.j(d,m),b=a[1]?function(){new t([a[1]],x.g,x.d)}:x.d,new t([a[0]],x.g,b),x}function t(b,d,m,h,x){var r;r=u.k(g, +G,[].concat(b),x);this.then=this.j=b=function(b,d){q(r,function(d){b&&b.apply(G,d)},function(b){if(d)d(b);else throw b;});return this};this.next=function(b,d,h){return new t(b,d,h,r)};this.config=a;(d||m)&&b(d,m);u.C(function(){q(x||J,function(){q(h,function(){u.A(r)},m)})})}function A(b){var d,m;d=b.id;d==G&&(K!==G?K={M:"Multiple anonymous defines encountered"}:(d=u.ia())||(K=b));if(d!=G){m=E[d];d in E||(m=u.m(d,g),m=u.J(m.b,d),E[d]=m);if(!y(m))throw Error("duplicate define: "+d);m.na=!1;u.K(m,b)}} +function C(){var b=u.fa(arguments);A(b)}var g,B,F,H=e.document,D=H&&(H.head||H.getElementsByTagName("head")[0]),R=D&&D.getElementsByTagName("base")[0]||null,L={},M={},I={},r="addEventListener"in e?{}:{loaded:1,complete:1},Q={},U=Q.toString,G,E={},N={},J=!1,K,T=/^\/|^[^:]+:\/\//,V=/(\.)(\.?)(?:$|\/([^\.\/]+.*)?)/g,X=/\/\*[\s\S]*?\*\/|\/\/.*?[\n\r]/g,Y=/require\s*\(\s*(["'])(.*?[^\\])\1\s*\)|[^\\]?(["'])/g,W=/\s*,\s*/,S,u;u={t:function(b,d,m){var h;b=f(b,d);if("."==b.charAt(0))return b;h=p(b);b=(d= +h.e)||h.h;b in m.c&&(b=m.c[b].q||b);d&&(0>d.indexOf("/")&&!(d in m.c)&&(b=n(m.T)+"/"+d),b=b+"!"+h.h);return b},k:function(b,d,m,h){function x(d,h){var m,a;m=u.t(d,g.id,b);if(!h)return m;a=p(m);if(!a.e)return m;m=E[a.e];a.h="normalize"in m?m.normalize(a.h,x,g.b)||"":x(a.h);return a.e+"!"+a.h}function a(d,m,r){var c;c=m&&function(b){m.apply(G,b)};if(k(d,"String")){if(c)throw Error("require(id, callback) not allowed");r=x(d,!0);d=E[r];if(!(r in E))throw Error("Module not resolved: "+r);return(r=y(d)&& +d.a)||d}q(u.A(u.k(b,g.id,d,h)),c,r)}var g;g=new z;g.id=d||"";g.ja=h;g.L=m;g.b=b;g.s=a;a.toUrl=function(d){return u.m(x(d,!0),b).url};g.t=x;return g},J:function(b,d,m){var h,x,a;h=u.k(b,d,G,m);x=h.g;a=w(1,function(b){h.w=b;try{return u.aa(h)}catch(d){h.d(d)}});h.g=function(b){q(m||J,function(){x(E[h.id]=N[h.url]=a(b))})};h.N=function(b){q(m||J,function(){h.a&&(a(b),h.G(M))})};return h},Z:function(b,d,m,h){return u.k(b,m,G,h)},ha:function(b){return b.s},P:function(b){return b.a||(b.a={})},ga:function(b){var d= +b.B;d||(d=b.B={id:b.id,uri:u.Q(b),exports:u.P(b),config:function(){return b.b}},d.a=d.exports);return d},Q:function(b){return b.url||(b.url=u.u(b.s.toUrl(b.id),b.b))},V:function(b){var d,m,h,a,g;d="curl";m="define";h=a=e;if(b&&(g=b.overwriteApi||b.xa,d=b.apiName||b.pa||d,h=b.apiContext||b.oa||h,m=b.defineName||b.ta||m,a=b.defineContext||b.sa||a,B&&k(B,"Function")&&(e.curl=B),B=null,F&&k(F,"Function")&&(e.define=F),F=null,!g)){if(h[d]&&h[d]!=c)throw Error(d+" already exists");if(a[m]&&a[m]!=C)throw Error(m+ +" already exists");}h[d]=c;a[m]=C},b:function(b){function d(b,d){var m,h,g,c,e;for(e in b){g=b[e];k(g,"String")&&(g={path:b[e]});g.name=g.name||e;c=a;h=p(n(g.name));m=h.h;if(h=h.e)c=r[h],c||(c=r[h]=s(a),c.c=s(a.c),c.f=[]),delete b[e];h=g;var l=d,q=void 0;h.path=n(h.path||h.location||"");l&&(q=h.main||"./main","."==q.charAt(0)||(q="./"+q),h.q=f(q,h.name+"/"));h.b=h.config;h.b&&(h.b=s(a,h.b));h.W=m.split("/").length;m?(c.c[m]=h,c.f.push(m)):c.n=u.U(g.path,a)}}function m(b){var d=b.c;b.S=RegExp("^("+ +b.f.sort(function(b,h){return d[h].W-d[b].W}).join("|").replace(/\/|\./g,"\\$&")+")(?=\\/|$)");delete b.f}var h,a,r,c;"baseUrl"in b&&(b.n=b.baseUrl);"main"in b&&(b.q=b.main);"preloads"in b&&(b.ya=b.preloads);"pluginPath"in b&&(b.T=b.pluginPath);if("dontAddFileExt"in b||b.l)b.l=RegExp(b.dontAddFileExt||b.l);h=g;a=s(h,b);a.c=s(h.c);r=b.plugins||{};a.plugins=s(h.plugins);a.F=s(h.F,b.F);a.D=s(h.D,b.D);a.f=[];d(b.packages,!0);d(b.paths,!1);for(c in r)b=u.t(c+"!","",a),a.plugins[b.substr(0,b.length-1)]= +r[c];r=a.plugins;for(c in r)if(r[c]=s(a,r[c]),b=r[c].f)r[c].f=b.concat(a.f),m(r[c]);for(c in h.c)a.c.hasOwnProperty(c)||a.f.push(c);m(a);return a},m:function(b,d){var a,h,c,r;a=d.c;c=T.test(b)?b:b.replace(d.S,function(b){h=a[b]||{};r=h.b;return h.path||""});return{b:r||g,url:u.U(c,d)}},U:function(b,d){var a=d.n;return a&&!T.test(b)?n(a)+"/"+b:b},u:function(b,d){return b+((d||g).l.test(b)?"":".js")},p:function(b,d,a){var h=H.createElement("script");h.onload=h.onreadystatechange=function(a){a=a||e.event; +if("load"==a.type||r[h.readyState])delete I[b.id],h.onload=h.onreadystatechange=h.onerror="",d()};h.onerror=function(){a(Error("Syntax or http error: "+b.url))};h.type=b.r||"text/javascript";h.charset="utf-8";h.async=!b.R;h.src=b.url;I[b.id]=h;D.insertBefore(h,R);return h},O:function(b){var d=[],a;("string"==typeof b?b:b.toSource?b.toSource():b.toString()).replace(X,"").replace(Y,function(b,g,c,r){r?a=a==r?G:a:a||d.push(c);return""});return d},fa:function(b){var d,a,h,g,c,r;c=b.length;h=b[c-1];g= +k(h,"Function")?h.length:-1;2==c?k(b[0],"Array")?a=b[0]:d=b[0]:3==c&&(d=b[0],a=b[1]);!a&&0p.status?l(p.responseText):h(Error("fetchText() failed. status: "+p.statusText)))};p.send(null)}});define("curl/plugin/text",["./_fetchText"],function(d){function l(d){throw d;}return{normalize:function(d,l){return d?l(d.split("!")[0]):d},load:function(k,n,h){d(n.toUrl(k),h,h.error||l)},cramPlugin:"../cram/text"}}); -define("curl/plugin/async",function(){return{load:function(d,l,k){function n(h){"function"==typeof k.error&&k.error(h)}l([d],function(h){"function"==typeof h.j?h.j(function(d){0==arguments.length&&(d=h);k(d)},n):k(h)},k.error||function(h){throw h;})},analyze:function(d,l,k){k(d)}}}); -(function(d){function l(){var a;a=f[A]("link");a.rel="stylesheet";a.type="text/css";return a}function k(a,c){a.onload=function(){I.load=I.load||!0;c()}}function n(a,c){a.onerror=function(){I.error=I.error||!0;c()}}function h(a,c,f){D.push({url:a,X:c,$:function(){f(Error(M))}});(a=v())&&p(a)}function p(a){var c,f;c=D.shift();f=a.styleSheet;c?(a.onload=function(){c.X(c.la);p(a)},a.onerror=function(){c.$();p(a)},c.la=f.imports[f.addImport(c.url)]):(a.onload=a.onerror=t,H.push(a))}function v(){var a; -a=H.shift();!a&&F.lengthp.status?l(p.responseText):f(Error("fetchText() failed. status: "+p.statusText)))};p.send(null)}});define("curl/plugin/text",["./_fetchText"],function(e){function l(e){throw e;}return{load:function(k,n,f){e(n.toUrl(k),f,f.error||l)},cramPlugin:"../cram/text"}}); +define("curl/plugin/async",function(){return{load:function(e,l,k){function n(f){"function"==typeof k.error&&k.error(f)}l([e],function(f){"function"==typeof f.j?f.j(function(e){0==arguments.length&&(e=f);k(e)},n):k(f)},k.error||function(f){throw f;})},analyze:function(e,l,k){k(e)}}}); +(function(e){function l(){var a;a=g[A]("link");a.rel="stylesheet";a.type="text/css";return a}function k(a,c){a.onload=function(){I.load=I.load||!0;c()}}function n(a,c){a.onerror=function(){I.error=I.error||!0;c()}}function f(a,c,g){D.push({url:a,X:c,$:function(){g(Error(M))}});(a=v())&&p(a)}function p(a){var c,g;c=D.shift();g=a.styleSheet;c?(a.onload=function(){c.X(c.la);p(a)},a.onerror=function(){c.$();p(a)},c.la=g.imports[g.addImport(c.url)]):(a.onload=a.onerror=t,H.push(a))}function v(){var a; +a=H.shift();!a&&F.length Date: Mon, 7 Oct 2013 23:49:03 -0700 Subject: [PATCH 007/189] Add Underscore's "Array" method category tests to test/test.js. --- test/test.js | 299 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 264 insertions(+), 35 deletions(-) diff --git a/test/test.js b/test/test.js index 6f6ec1879d..9e4117e337 100644 --- a/test/test.js +++ b/test/test.js @@ -687,6 +687,17 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.compact'); + + (function() { + test('should filter falsey values', 1, function() { + var array = ['0', '1', '2']; + deepEqual(_.compact(falsey.concat(array)), array); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.contains'); (function() { @@ -1110,6 +1121,14 @@ QUnit.module('lodash.difference'); (function() { + test('should return the difference of the given arrays', 2, function() { + var actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10]); + deepEqual(actual, [1, 3, 4]); + + actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10], [8, 4]); + deepEqual(actual, [1, 3]); + }); + test('should work with large arrays', 1, function() { var array1 = _.range(largeArraySize), array2 = array1.slice(), @@ -1305,13 +1324,13 @@ }); test('should return an empty array when `n` < `1`', 3, function() { - _.each([0, -1, -2], function(n) { + _.forEach([0, -1, -2], function(n) { deepEqual(_.first(array, n), []); }); }); test('should return all elements when `n` >= `array.length`', 2, function() { - _.each([3, 4], function(n) { + _.forEach([3, 4], function(n) { deepEqual(_.first(array, n), array.slice()); }); }); @@ -1393,6 +1412,11 @@ test('should work with a string for `callback`', 1, function() { deepEqual(_.first(objects, 'b'), objects.slice(0, 2)); }); + + test('should be aliases as `_.head` and `_.take`', 2, function() { + strictEqual(_.head, _.first); + strictEqual(_.take, _.first); + }); }()); /*--------------------------------------------------------------------------*/ @@ -1492,6 +1516,27 @@ var actual = _.flatten([[], [[]], [[], [[[]]]]]); deepEqual(actual, []); }); + + test('should flatten nested arrays', 1, function() { + var array = [1, [2], [3, [[4]]]], + expected = [1, 2, 3, 4]; + + deepEqual(_.flatten(array), expected); + }); + + test('should support shallow flattening nested arrays', 1, function() { + var array = [1, [2], [3, [4]]], + expected = [1, 2, 3, [4]]; + + deepEqual(_.flatten(array, true), expected); + }); + + test('should support shallow flattening arrays of other arrays', 1, function() { + var array = [[1], [2], [3], [[4]]], + expected = [1, 2, 3, [4]]; + + deepEqual(_.flatten(array, true), expected); + }); }(1, 2, 3)); /*--------------------------------------------------------------------------*/ @@ -1868,6 +1913,18 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.has'); + + (function() { + test('should return `false` for primitives', 9, function() { + _.forEach(falsey.concat(1, 'a'), function(value) { + strictEqual(_.has(value, 'valueOf'), false); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.indexBy'); (function() { @@ -1915,23 +1972,19 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.has'); - - (function() { - test('should return `false` for primitives', 9, function() { - _.forEach(falsey.concat(1, 'a'), function(value) { - strictEqual(_.has(value, 'valueOf'), false); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.indexOf'); (function() { var array = [1, 2, 3, 1, 2, 3]; + test('should return the index of the first matched value', 1, function() { + equal(_.indexOf(array, 3), 2); + }); + + test('should return `-1` for an unmatched value', 1, function() { + equal(_.indexOf(array, 4), -1); + }); + test('should work with a positive `fromIndex`', 1, function() { equal(_.indexOf(array, 1, 2), 3); }); @@ -2061,13 +2114,17 @@ { 'a': 2, 'b': 2 } ]; - test('should accept a falsey `array` argument', 7, function() { - _.forEach(falsey, function(index, value) { + test('should accept a falsey `array` argument', 1, function() { + var actual = [], + expected = _.map(falsey, function() { return []; }); + + _.forEach(falsey, function(value, index) { try { - var actual = index ? _.initial(value) : _.initial(); + actual.push(index ? _.initial(value) : _.initial()); } catch(e) { } - deepEqual(actual, []); - }) + }); + + deepEqual(actual, expected); }); test('should exclude last element', 1, function() { @@ -2083,13 +2140,13 @@ }); test('should return all elements when `n` < `1`', 3, function() { - _.each([0, -1, -2], function(n) { + _.forEach([0, -1, -2], function(n) { deepEqual(_.initial(array, n), array.slice()); }); }); test('should return an empty array when `n` >= `array.length`', 2, function() { - _.each([3, 4], function(n) { + _.forEach([3, 4], function(n) { deepEqual(_.initial(array, n), []); }); }); @@ -2138,6 +2195,33 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.intersection'); + + (function() { + test('should return the intersection of the given arrays', 1, function() { + var actual = _.intersection([1, 3, 2], [101, 2, 1, 10], [2, 1]); + deepEqual(actual, [1, 2]); + }); + + test('should return an array of unique values', 1, function() { + var actual = _.intersection([1, 1, 3, 2, 2], [101, 2, 2, 1, 101], [2, 1, 1]); + deepEqual(actual, [1, 2]); + }); + + test('should return a wrapped value when chaining', 2, function() { + if (!isNpm) { + var actual = _([1, 3, 2]).intersection([101, 2, 1, 10]); + ok(actual instanceof _); + deepEqual(actual.value(), [1, 2]); + } + else { + skipTest(2); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.invoke'); (function() { @@ -2512,13 +2596,13 @@ }); test('should return an empty array when `n` < `1`', 3, function() { - _.each([0, -1, -2], function(n) { + _.forEach([0, -1, -2], function(n) { deepEqual(_.last(array, n), []); }); }); test('should return all elements when `n` >= `array.length`', 2, function() { - _.each([3, 4], function(n) { + _.forEach([3, 4], function(n) { deepEqual(_.last(array, n), array.slice()); }); }); @@ -2609,6 +2693,14 @@ (function() { var array = [1, 2, 3, 1, 2, 3]; + test('should return the index of the last matched value', 1, function() { + equal(_.lastIndexOf(array, 3), 5); + }); + + test('should return `-1` for an unmatched value', 1, function() { + equal(_.lastIndexOf(array, 4), -1); + }); + test('should work with a positive `fromIndex`', 1, function() { strictEqual(_.lastIndexOf(array, 1, 2), 0); }); @@ -2637,6 +2729,29 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('indexOf methods'); + + (function() { + _.forEach(['indexOf', 'lastIndexOf'], function(methodName) { + var func = _[methodName]; + + test('`_.' + methodName + '` should accept a falsey `array` argument', 1, function() { + var actual = [], + expected = _.map(falsey, function() { return -1; }); + + _.forEach(falsey, function(value, index) { + try { + actual.push(index ? func(value) : func()); + } catch(e) { } + }); + + deepEqual(actual, expected); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.map'); (function() { @@ -3264,6 +3379,31 @@ (function() { var func = _.range; + test('should work when passing a single `end` argument', 1, function() { + deepEqual(_.range(4), [0, 1, 2, 3]); + }); + + test('should work when passing `start` and `end` arguments', 1, function() { + deepEqual(_.range(1, 5), [1, 2, 3, 4]); + }); + + test('should work when passing `start`, `end`, and `step` arguments', 1, function() { + deepEqual(_.range(1, 20, 5), [0, 5, 10, 15]); + }); + + test('should support a `step` of `0`', 1, function() { + deepEqual(_.range(1, 4, 0), [1, 1, 1]); + }); + + test('should work when passing `step` larger than `end`', 1, function() { + deepEqual(_.range(1, 5, 20), [1]); + }); + + test('should work when passing a negative `step` argument', 2, function() { + deepEqual(_.range(0, -4, -1), [0, -1, -2, -3]); + deepEqual(_.range(21, 10, -3), [21, 18, 15, 12]); + }); + test('should treat falsey `start` arguments as `0`', 13, function() { _.forEach(falsey, function(value, index) { if (index) { @@ -3279,10 +3419,6 @@ var actual = [func('0',1), func('1'), func(0, 1, '1')]; deepEqual(actual, [[0], [0], [0]]); }); - - test('should support a `step` of `0`', 1, function() { - deepEqual(_.range(1, 4, 0), [1, 1, 1]); - }); }()); /*--------------------------------------------------------------------------*/ @@ -3468,13 +3604,13 @@ }); test('should return all elements when `n` < `1`', 3, function() { - _.each([0, -1, -2], function(n) { + _.forEach([0, -1, -2], function(n) { deepEqual(_.rest(array, n), [1, 2, 3]); }); }); test('should return an empty array when `n` >= `array.length`', 2, function() { - _.each([3, 4], function(n) { + _.forEach([3, 4], function(n) { deepEqual(_.rest(array, n), []); }); }); @@ -3523,6 +3659,11 @@ test('should work with a string for `callback`', 1, function() { deepEqual(_.rest(objects, 'b'), objects.slice(-1)); }); + + test('should be aliases as `_.drop` and `_.tail`', 2, function() { + strictEqual(_.drop, _.rest); + strictEqual(_.tail, _.rest); + }); }()); /*--------------------------------------------------------------------------*/ @@ -3566,13 +3707,13 @@ }); test('should return an empty array when `n` < `1`', 3, function() { - _.each([0, -1, -2], function(n) { + _.forEach([0, -1, -2], function(n) { deepEqual(_.sample(array, n), []); }); }); test('should return all elements when `n` >= `array.length`', 2, function() { - _.each([3, 4], function(n) { + _.forEach([3, 4], function(n) { deepEqual(_.sample(array, n).sort(), array.slice()); }); }); @@ -4355,6 +4496,16 @@ QUnit.module('lodash.union'); (function() { + test('should return the union of the given arrays', 1, function() { + var actual = _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); + deepEqual(actual, [1, 2, 3, 101, 10]); + }); + + test('should not flatten nested arrays', 1, function() { + var actual = _.union([1, 2, 3], [1, [4]], [2, [5]]); + deepEqual(actual, [1, 2, 3, [4], [5]]); + }); + test('should produce correct results when provided a falsey `array` argument', 1, function() { var expected = [1, 2, 3], actual = _.union(null, expected); @@ -4372,6 +4523,34 @@ QUnit.module('lodash.uniq'); (function() { + var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; + + test('should return unique values of an unsorted array', 1, function() { + var array = [2, 3, 1, 2, 3, 1]; + deepEqual(_.uniq(array), [2, 3, 1]); + }); + + test('should return unique values of a sorted array', 1, function() { + var array = [1, 1, 2, 2, 3]; + deepEqual(_.uniq(array), [1, 2, 3]); + }); + + test('should work with a `callback`', 1, function() { + var actual = _.uniq(objects, false, function(object) { + return object.a; + }); + + deepEqual(actual, objects.slice(0, 3)); + }); + + test('should work with a `callback` without specifying `isSorted`', 1, function() { + var actual = _.uniq(objects, function(object) { + return object.a; + }); + + deepEqual(actual, objects.slice(0, 3)); + }); + test('should support the `thisArg` argument', 1, function() { var actual = _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); @@ -4506,6 +4685,26 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.without'); + + (function() { + test('should use strict equality to determine the values to reject', 2, function() { + var object1 = { 'a': 1 }, + object2 = { 'b': 2 }, + array = [object1, object2]; + + deepEqual(_.without(array, { 'a': 1 }), array); + deepEqual(_.without(array, object1), [object2]); + }); + + test('should remove all occurrences of each value from an array', 1, function() { + var array = [1, 2, 3, 1, 2, 3]; + deepEqual(_.without(array, 1, 2), [3, 3]); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.zip'); (function() { @@ -4551,7 +4750,7 @@ deepEqual(actual, [['moe', 30, undefined], ['larry', 40, false]]); }); - test('should correctly consume it\'s output', 1, function() { + test('should support consuming it\'s return value', 1, function() { var expected = [['moe', 'larry'], [30, 40]]; deepEqual(_.zip(_.zip(_.zip(_.zip(expected)))), expected); }); @@ -4562,9 +4761,39 @@ QUnit.module('lodash.zipObject'); (function() { + var object = { 'moe': 30, 'larry': 40 }, + array = [['moe', 30], ['larry', 40]]; + test('should skip falsey elements in a given two dimensional array', 1, function() { - var actual = _.zipObject([['a', 1], ['b', 2]].concat(falsey)); - deepEqual(actual, { 'a': 1, 'b': 2 }); + var actual = _.zipObject(array.concat(falsey)); + deepEqual(actual, object); + }); + + test('should zip together key/value arrays into an object', 1, function() { + var actual = _.zipObject(['moe', 'larry'], [30, 40]); + deepEqual(actual, object); + }); + + test('should accept a two dimensional array', 1, function() { + var actual = _.zipObject(array); + deepEqual(actual, object); + }); + + test('should accept a falsey `array` argument', 1, function() { + var actual = [], + expected = _.map(falsey, function() { return {}; }); + + _.forEach(falsey, function(value, index) { + try { + actual.push(index ? _.zipObject(value) : _.zipObject()); + } catch(e) { } + }); + + deepEqual(actual, expected); + }); + + test('should support consuming the return value of `_.pairs`', 1, function() { + deepEqual(_.zipObject(_.pairs(object)), object); }); }()); @@ -4949,7 +5178,7 @@ }); // skip tests for missing methods of modularized builds - _.each(['runInContext', 'tap'], function(methodName) { + _.forEach(['runInContext', 'tap'], function(methodName) { if (!_[methodName]) { skipTest(); } From e7320e7bd3878e84637319d3bd72ba746e148ce9 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Oct 2013 23:49:58 -0700 Subject: [PATCH 008/189] Fix typo in `_.range` doc example. --- lodash.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lodash.js b/lodash.js index a0adc2f440..97261c26d2 100644 --- a/lodash.js +++ b/lodash.js @@ -4765,17 +4765,17 @@ * @returns {Array} Returns a new range array. * @example * - * _.range(10); - * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + * _.range(4); + * // => [0, 1, 2, 3] * - * _.range(1, 11); - * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * _.range(1, 5); + * // => [1, 2, 3, 4] * - * _.range(0, 30, 5); - * // => [0, 5, 10, 15, 20, 25] + * _.range(0, 20, 5); + * // => [0, 5, 10, 15] * - * _.range(0, -10, -1); - * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] + * _.range(0, -4, -1); + * // => [0, -1, -2, -3] * * _.range(1, 4, 0); * // => [1, 1, 1] From d7ae0105c3886b4cf2567da88b68c5de3ef2f723 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Oct 2013 23:52:15 -0700 Subject: [PATCH 009/189] Fix typo in `_.range` test. --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index 9e4117e337..ec9d5733b4 100644 --- a/test/test.js +++ b/test/test.js @@ -3388,7 +3388,7 @@ }); test('should work when passing `start`, `end`, and `step` arguments', 1, function() { - deepEqual(_.range(1, 20, 5), [0, 5, 10, 15]); + deepEqual(_.range(0, 20, 5), [0, 5, 10, 15]); }); test('should support a `step` of `0`', 1, function() { From ce64c8e7d1af122676f8cb1bde3312efb497237b Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 8 Oct 2013 00:37:45 -0700 Subject: [PATCH 010/189] Update tested Chrome version in readme. [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a2abc5321..4fb20d09ca 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ The full changelog for this release is available on our [wiki](https://github.co ## Support -Tested in Chrome 5~29, Firefox 2~24, IE 6-10, Opera 9.25~16, Safari 3-6, Node.js 0.6.8-0.10.20, Narwhal 0.3.2, PhantomJS 1.9.2, RingoJS 0.9, & Rhino 1.7RC5. +Tested in Chrome 5~30, Firefox 2~24, IE 6-10, Opera 9.25~16, Safari 3-6, Node.js 0.6.8-0.10.20, Narwhal 0.3.2, PhantomJS 1.9.2, RingoJS 0.9, & Rhino 1.7RC5. ## Installation & usage From 253642a85e710b193006d07e7d3b88552e0dea2b Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 8 Oct 2013 19:33:59 -0700 Subject: [PATCH 011/189] Cleanup `_.throttle` return statement. --- lodash.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lodash.js b/lodash.js index 97261c26d2..10f00666c0 100644 --- a/lodash.js +++ b/lodash.js @@ -5809,8 +5809,7 @@ debounceOptions.maxWait = wait; debounceOptions.trailing = trailing; - var result = debounce(func, wait, debounceOptions); - return result; + return debounce(func, wait, debounceOptions); } /** From dfae413afc5c97b7d619c30c76c93e8cf43616dd Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Oct 2013 21:52:04 -0700 Subject: [PATCH 012/189] Move more Underscore tests into test/test.js. --- test/test.js | 504 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 448 insertions(+), 56 deletions(-) diff --git a/test/test.js b/test/test.js index ec9d5733b4..263714b8eb 100644 --- a/test/test.js +++ b/test/test.js @@ -739,6 +739,10 @@ strictEqual(_.contains(collection, 'd'), false); }); }); + + test('should be aliased', 1, function() { + strictEqual(_.include, _.contains); + }); }(1, 2, 3, 1, 2, 3)); /*--------------------------------------------------------------------------*/ @@ -1175,6 +1179,10 @@ test('should return `false` as soon as the `callback` result is falsey', 1, function() { strictEqual(_.every([true, null, true], _.identity), false); }); + + test('should be aliased', 1, function() { + strictEqual(_.all, _.every); + }); }()); /*--------------------------------------------------------------------------*/ @@ -1249,12 +1257,16 @@ QUnit.module('lodash.filter'); (function() { - test('should not modify the resulting value from within `callback`', 1, function() { - var actual = _.filter([0], function(num, index, array) { - return (array[index] = 1); + test('should return elements the `callback` returns truey for', 1, function() { + var actual = _.filter([1, 2, 3], function(num) { + return num % 2; }); - deepEqual(actual, [0]); + deepEqual(actual, [1, 3]); + }); + + test('should be aliased', 1, function() { + strictEqual(_.select, _.filter); }); }()); @@ -1299,6 +1311,12 @@ test('should work with a string for `callback`', 1, function() { strictEqual(func(objects, 'b'), expected[3]); }); + + if (methodName == 'find') { + test('should be aliased', 1, function() { + strictEqual(_.detect, func); + }); + } }); }()); @@ -1413,7 +1431,7 @@ deepEqual(_.first(objects, 'b'), objects.slice(0, 2)); }); - test('should be aliases as `_.head` and `_.take`', 2, function() { + test('should be aliased', 2, function() { strictEqual(_.head, _.first); strictEqual(_.take, _.first); }); @@ -1546,35 +1564,6 @@ _.forEach(['forEach', 'forEachRight'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should return the collection', 1, function() { - var collection = [1, 2, 3]; - equal(func(collection, Boolean), collection); - }); - - test('`_.' + methodName + '` should return the existing wrapper when chaining', 1, function() { - if (!isNpm) { - var wrapper = _([1, 2, 3]); - equal(wrapper[methodName](Boolean), wrapper); - } - else { - skipTest(); - } - }); - - test('`_.' + methodName + '` should support the `thisArg` argument', 2, function() { - var actual; - - function callback(num, index) { - actual = this[index]; - } - - func([1], callback, [2]); - equal(actual, 2); - - func({ 'a': 1 }, callback, { 'a': 2 }); - equal(actual, 2); - }); - _.forEach({ 'literal': 'abc', 'object': Object('abc') @@ -1598,6 +1587,14 @@ } }); }); + + test('`_.' + methodName + '` should be aliased', 1, function() { + if (methodName == 'forEach') { + strictEqual(_.each, _.forEach); + } else { + strictEqual(_.eachRight, _.forEachRight); + } + }); }); /*--------------------------------------------------------------------------*/ @@ -1648,6 +1645,143 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('iteration methods'); + + (function() { + var methods = [ + 'every', + 'filter', + 'forEach', + 'forEachRight', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight', + 'map', + 'reject', + 'some' + ]; + + var boolMethods = [ + 'every', + 'some' + ]; + + var forInMethods = [ + 'forIn', + 'forInRight' + ]; + + var iterationMethods = [ + 'forEach', + 'forEachRight', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight' + ] + + var objectMethods = [ + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight' + ]; + + var rightMethods = [ + 'forEachRight', + 'forInRight', + 'forOwnRight' + ]; + + _.forEach(methods, function(methodName) { + var array = [1, 2, 3], + func = _[methodName]; + + test('`_.' + methodName + '` should pass the correct `callback` arguments', 1, function() { + var args, + expected = [1, 0, array]; + + func(array, function() { + args || (args = slice.call(arguments)); + }); + + if (_.contains(rightMethods, methodName)) { + expected[0] = 3; + expected[1] = 2; + } + if (_.contains(objectMethods, methodName)) { + expected[1] += ''; + } + deepEqual(args, expected); + }); + + test('`_.' + methodName + '` should support the `thisArg` argument', 2, function() { + var actual; + + function callback(num, index) { + actual = this[index]; + } + + func([1], callback, [2]); + equal(actual, 2); + + func({ 'a': 1 }, callback, { 'a': 2 }); + equal(actual, 2); + }); + }); + + _.forEach(_.difference(methods, boolMethods), function(methodName) { + var array = [1, 2, 3], + func = _[methodName]; + + test('`_.' + methodName + '` should return a wrapped value when chaining', 1, function() { + if (!isNpm) { + var actual = _(array)[methodName](Boolean); + ok(actual instanceof _); + } + else { + skipTest(); + } + }); + }); + + _.forEach(_.difference(methods, forInMethods), function(methodName) { + var array = [1, 2, 3], + func = _[methodName]; + + test('`_.' + methodName + '` iterates over own properties of objects', 1, function() { + function Foo() { this.a = 1; } + Foo.prototype.b = 2; + + var keys = []; + func(new Foo, function(value, key) { keys.push(key); }); + deepEqual(keys, ['a']); + }); + }); + + _.forEach(iterationMethods, function(methodName) { + var array = [1, 2, 3], + func = _[methodName]; + + test('`_.' + methodName + '` should return the collection', 1, function() { + equal(func(array, Boolean), array); + }); + + test('`_.' + methodName + '` should return the existing wrapper when chaining', 1, function() { + if (!isNpm) { + var wrapper = _(array); + equal(wrapper[methodName](Boolean), wrapper); + } + else { + skipTest(); + } + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('collection iteration bugs'); _.forEach(['forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight'], function(methodName) { @@ -1773,6 +1907,7 @@ test('`_.' + methodName + '` should pass the correct `callback` arguments', 2, function() { var args; + func({ 'a': 1 }, { 'a': 2 }, function() { args || (args = slice.call(arguments)); }); @@ -2755,9 +2890,41 @@ QUnit.module('lodash.map'); (function() { - test('should return the correct result when iterating an object', 1, function() { + var array = [1, 2, 3]; + + test('should pass the correct `callback` arguments', 1, function() { + var args; + + _.map(array, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, [1, 0, array]); + }); + + test('should support the `thisArg` argument', 2, function() { + function callback(num, index) { + return this[index]; + } + + var actual = _.map([1], callback, [2]); + equal(actual, 2); + + actual = _.map({ 'a': 1 }, callback, { 'a': 2 }); + equal(actual, 2); + }); + + test('should iterate over own properties of objects', 1, function() { + function Foo() { this.a = 1; } + Foo.prototype.b = 2; + + var keys = _.map(new Foo, function(value, key) { return key; }); + deepEqual(keys, ['a']); + }); + + test('should work on an object with no `callback`', 1, function() { var actual = _.map({ 'a': 1, 'b': 2, 'c': 3 }); - deepEqual(actual, [1, 2, 3]); + deepEqual(actual, array); }); test('should handle object arguments with non-numeric length properties', 1, function() { @@ -2769,6 +2936,45 @@ skipTest(); } }); + + test('should return a wrapped value when chaining', 1, function() { + if (!isNpm) { + ok(_(array).map(Boolean) instanceof _); + } + else { + skipTest(); + } + }); + + test('should treat a nodelist as an array-like object', 1, function() { + if (document) { + var actual = _.map(document.getElementsByTagName('body'), function(element) { + return element.nodeName.toLowerCase(); + }); + + deepEqual(actual, ['body']); + } + else { + skipTest(); + } + }); + + test('should accept a falsey `array` argument', 1, function() { + var actual = [], + expected = _.map(falsey, function() { return []; }); + + _.forEach(falsey, function(value, index) { + try { + actual.push(index ? _.map(value) : _.map()); + } catch(e) { } + }); + + deepEqual(actual, expected); + }); + + test('should be aliased', 1, function() { + strictEqual(_.collect, _.map); + }); }()); /*--------------------------------------------------------------------------*/ @@ -3426,10 +3632,22 @@ QUnit.module('lodash.reduce'); (function() { - test('should pass the correct `callback` arguments', 1, function() { - var args, - array = [1, 2, 3]; + var array = [1, 2, 3]; + test('should use the first element of a collection as the default `accumulator`', 1, function() { + strictEqual(_.reduce(array), 1); + }); + + test('should pass the correct `callback` arguments when iterating an array', 2, function() { + var args; + + _.reduce(array, function() { + args || (args = slice.call(arguments)); + }, 0); + + deepEqual(args, [0, 1, 0, array]); + + args = null; _.reduce(array, function() { args || (args = slice.call(arguments)); }); @@ -3437,6 +3655,33 @@ deepEqual(args, [1, 2, 1, array]); }); + test('should pass the correct `callback` arguments when iterating an object', 2, function() { + var args, + object = { 'a': 1, 'b': 2 }, + firstKey = _.first(_.keys(object)); + + var expected = firstKey == 'a' + ? [0, 1, 'a', object] + : [0, 2, 'b', object]; + + _.reduce(object, function() { + args || (args = slice.call(arguments)); + }, 0); + + deepEqual(args, expected); + + args = null; + expected = firstKey == 'a' + ? [1, 2, 'b', object] + : [2, 1, 'a', object]; + + _.reduce(object, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, expected); + }); + _.forEach({ 'literal': 'abc', 'object': Object('abc') @@ -3454,6 +3699,11 @@ equal(actual, 'abc'); }); }); + + test('should be aliased', 2, function() { + strictEqual(_.foldl, _.reduce); + strictEqual(_.inject, _.reduce); + }); }()); /*--------------------------------------------------------------------------*/ @@ -3461,10 +3711,22 @@ QUnit.module('lodash.reduceRight'); (function() { - test('should pass the correct `callback` arguments when iterating an array', 1, function() { - var args, - array = [1, 2, 3]; + var array = [1, 2, 3]; + + test('should use the last element of a collection as the default `accumulator`', 1, function() { + equal(_.reduceRight(array), 3); + }); + + test('should pass the correct `callback` arguments when iterating an array', 2, function() { + var args; + + _.reduceRight(array, function() { + args || (args = slice.call(arguments)); + }, 0); + + deepEqual(args, [0, 3, 2, array]); + args = null; _.reduceRight(array, function() { args || (args = slice.call(arguments)); }); @@ -3472,12 +3734,23 @@ deepEqual(args, [3, 2, 1, array]); }); - test('should pass the correct `callback` arguments when iterating an object', 1, function() { + test('should pass the correct `callback` arguments when iterating an object', 2, function() { var args, object = { 'a': 1, 'b': 2 }, - lastKey = _.keys(object).pop(); + lastKey = _.last(_.keys(object)); var expected = lastKey == 'b' + ? [0, 2, 'b', object] + : [0, 1, 'a', object]; + + _.reduceRight(object, function() { + args || (args = slice.call(arguments)); + }, 0); + + deepEqual(args, expected); + + args = null; + expected = lastKey == 'b' ? [2, 1, 'a', object] : [1, 2, 'b', object]; @@ -3505,8 +3778,115 @@ equal(actual, 'cba'); }); }); + + test('should be aliased', 1, function() { + strictEqual(_.foldr, _.reduceRight); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('reduce methods'); + + _.forEach(['reduce', 'reduceRight'], function(methodName) { + var array = [1, 2, 3], + empties = [[]].concat(falsey.slice(1)), + func = _[methodName], + noop = function() {}; + + test('`_.' + methodName + '` should reduce a collection to a single value', 1, function() { + var actual = func(['a', 'b', 'c'], function(accumulator, value) { + return accumulator + value; + }, ''); + + equal(actual, methodName == 'reduce' ? 'abc' : 'cba'); + }); + + test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() { + var actual = func(array, function(sum, num, index) { + return sum + this[index]; + }, 0, array); + + deepEqual(actual, 6); + }); + + test('`_.' + methodName + '` should return an unwrapped value when chaining', 1, function() { + if (!isNpm) { + var actual = _(array)[methodName](function(sum, num) { + return sum + num; + }); + + equal(actual, 6); + } + else { + skipTest(); + } + }); + + test('`_.' + methodName + '` should support empty or falsey collections without an initial `accumulator` value', 1, function() { + var actual = [], + expected = _.map(empties, function() { return undefined; }); + + _.forEach(empties, function(value) { + try { + actual.push(func(value, noop)); + } catch(e) { } + }); + + deepEqual(actual, expected); + }); + + test('`_.' + methodName + '` should support empty or falsey collections with an initial `accumulator` value', 1, function() { + var actual = [], + expected = _.map(empties, function() { return 'x'; }); + + _.forEach(empties, function(value) { + try { + actual.push(func(value, noop, 'x')); + } catch(e) { } + }); + + deepEqual(actual, expected); + }); + + test('`_.' + methodName + '` should handle an initial `accumulator` value of `undefined`', 1, function() { + var actual = func([], noop, undefined); + strictEqual(actual, undefined); + }); + }); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.reject'); + + (function() { + test('should return elements the `callback` returns falsey for', 1, function() { + var actual = _.reject([1, 2, 3], function(num) { + return num % 2; + }); + + deepEqual(actual, [2]); + }); }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('filter methods'); + + _.forEach(['filter', 'reject'], function(methodNames) { + var func = _[methodNames]; + + test('`_.' + methodNames + '` should not modify the resulting value from within `callback`', 1, function() { + var actual = func([0], function(num, index, array) { + array[index] = 1; + return methodNames == 'filter'; + }); + + deepEqual(actual, [0]); + }); + }); + /*--------------------------------------------------------------------------*/ QUnit.module('lodash.remove'); @@ -3586,13 +3966,17 @@ { 'a': 0, 'b': 0 } ]; - test('should accept a falsey `array` argument', 7, function() { - _.forEach(falsey, function(index, value) { + test('should accept a falsey `array` argument', 1, function() { + var actual = [], + expected = _.map(falsey, function() { return []; }); + + _.forEach(falsey, function(value, index) { try { - var actual = index ? _.rest(value) : _.rest(); + actual.push(index ? _.rest(value) : _.rest()); } catch(e) { } - deepEqual(actual, []); - }) + }); + + deepEqual(actual, expected); }); test('should exclude the first element', 1, function() { @@ -3660,7 +4044,7 @@ deepEqual(_.rest(objects, 'b'), objects.slice(-1)); }); - test('should be aliases as `_.drop` and `_.tail`', 2, function() { + test('should be aliased', 2, function() { strictEqual(_.drop, _.rest); strictEqual(_.tail, _.rest); }); @@ -3805,13 +4189,17 @@ (function() { var args = arguments; - test('should accept a falsey `object` argument', 7, function() { - _.forEach(falsey, function(index, value) { + test('should accept a falsey `object` argument', 1, function() { + var actual = [], + expected = _.map(falsey, function() { return 0; }); + + _.forEach(falsey, function(value, index) { try { - var actual = index ? _.size(value) : _.size(); + actual.push(index ? _.size(value) : _.size()); } catch(e) { } - strictEqual(actual, 0); - }) + }); + + deepEqual(actual, expected); }); test('should work with jQuery/MooTools DOM query collections', 1, function() { @@ -3852,6 +4240,10 @@ test('should return `true` as soon as the `callback` result is truey', 1, function() { strictEqual(_.some([null, true, null], _.identity), true); }); + + test('should be aliased', 1, function() { + strictEqual(_.any, _.some); + }); }()); /*--------------------------------------------------------------------------*/ @@ -5178,7 +5570,7 @@ }); // skip tests for missing methods of modularized builds - _.forEach(['runInContext', 'tap'], function(methodName) { + _.forEach(['noConflict', 'runInContext', 'tap'], function(methodName) { if (!_[methodName]) { skipTest(); } From a03a7dcb4ade472d9429b908d78fa328c25544ee Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 10 Oct 2013 22:27:32 -0700 Subject: [PATCH 013/189] Update vendor/backbone to v1.1.0. --- vendor/backbone/backbone.js | 270 ++++++++++++++-------------- vendor/backbone/test/collection.js | 269 ++++++++++++++++++++++----- vendor/backbone/test/environment.js | 64 +++---- vendor/backbone/test/events.js | 29 ++- vendor/backbone/test/model.js | 32 ++-- vendor/backbone/test/noconflict.js | 4 +- vendor/backbone/test/router.js | 123 ++++++++++++- vendor/backbone/test/sync.js | 10 +- vendor/backbone/test/view.js | 38 +--- 9 files changed, 569 insertions(+), 270 deletions(-) diff --git a/vendor/backbone/backbone.js b/vendor/backbone/backbone.js index 3512d42fb4..f7783c2c19 100644 --- a/vendor/backbone/backbone.js +++ b/vendor/backbone/backbone.js @@ -1,6 +1,7 @@ -// Backbone.js 1.0.0 +// Backbone.js 1.1.0 -// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc. +// (c) 2010-2011 Jeremy Ashkenas, DocumentCloud Inc. +// (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Backbone may be freely distributed under the MIT license. // For all details and documentation: // http://backbonejs.org @@ -34,7 +35,7 @@ } // Current version of the library. Keep in sync with `package.json`. - Backbone.VERSION = '1.0.0'; + Backbone.VERSION = '1.1.0'; // Require Underscore, if we're on the server, and it's not already present. var _ = root._; @@ -52,7 +53,7 @@ }; // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option - // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and + // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and // set a `X-Http-Method-Override` header. Backbone.emulateHTTP = false; @@ -111,7 +112,6 @@ this._events = {}; return this; } - names = name ? [name] : _.keys(this._events); for (i = 0, l = names.length; i < l; i++) { name = names[i]; @@ -151,14 +151,15 @@ // Tell this object to stop listening to either specific events ... or // to every object it's currently listening to. stopListening: function(obj, name, callback) { - var listeners = this._listeners; - if (!listeners) return this; - var deleteListener = !name && !callback; - if (typeof name === 'object') callback = this; - if (obj) (listeners = {})[obj._listenerId] = obj; - for (var id in listeners) { - listeners[id].off(name, callback, this); - if (deleteListener) delete this._listeners[id]; + var listeningTo = this._listeningTo; + if (!listeningTo) return this; + var remove = !name && !callback; + if (!callback && typeof name === 'object') callback = this; + if (obj) (listeningTo = {})[obj._listenId] = obj; + for (var id in listeningTo) { + obj = listeningTo[id]; + obj.off(name, callback, this); + if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; } return this; } @@ -215,10 +216,10 @@ // listening to. _.each(listenMethods, function(implementation, method) { Events[method] = function(obj, name, callback) { - var listeners = this._listeners || (this._listeners = {}); - var id = obj._listenerId || (obj._listenerId = _.uniqueId('l')); - listeners[id] = obj; - if (typeof name === 'object') callback = this; + var listeningTo = this._listeningTo || (this._listeningTo = {}); + var id = obj._listenId || (obj._listenId = _.uniqueId('l')); + listeningTo[id] = obj; + if (!callback && typeof name === 'object') callback = this; obj[implementation](name, callback, this); return this; }; @@ -243,24 +244,18 @@ // Create a new model with the specified attributes. A client id (`cid`) // is automatically generated and assigned for you. var Model = Backbone.Model = function(attributes, options) { - var defaults; var attrs = attributes || {}; options || (options = {}); this.cid = _.uniqueId('c'); this.attributes = {}; - _.extend(this, _.pick(options, modelOptions)); + if (options.collection) this.collection = options.collection; if (options.parse) attrs = this.parse(attrs, options) || {}; - if (defaults = _.result(this, 'defaults')) { - attrs = _.defaults({}, attrs, defaults); - } + attrs = _.defaults({}, attrs, _.result(this, 'defaults')); this.set(attrs, options); this.changed = {}; this.initialize.apply(this, arguments); }; - // A list of options to be attached directly to the model, if provided. - var modelOptions = ['url', 'urlRoot', 'collection']; - // Attach all inheritable methods to the Model prototype. _.extend(Model.prototype, Events, { @@ -456,13 +451,16 @@ (attrs = {})[key] = val; } - // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`. - if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false; - options = _.extend({validate: true}, options); - // Do not persist invalid models. - if (!this._validate(attrs, options)) return false; + // If we're not waiting and attributes exist, save acts as + // `set(attr).save(null, opts)` with validation. Otherwise, check if + // the model will be valid when the attributes, if any, are set. + if (attrs && !options.wait) { + if (!this.set(attrs, options)) return false; + } else { + if (!this._validate(attrs, options)) return false; + } // Set temporary attributes if `{wait: true}`. if (attrs && options.wait) { @@ -563,7 +561,7 @@ attrs = _.extend({}, this.attributes, attrs); var error = this.validationError = this.validate(attrs, options) || null; if (!error) return true; - this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error})); + this.trigger('invalid', this, error, _.extend(options, {validationError: error})); return false; } @@ -596,7 +594,6 @@ // its models in sort order, as they're added and removed. var Collection = Backbone.Collection = function(models, options) { options || (options = {}); - if (options.url) this.url = options.url; if (options.model) this.model = options.model; if (options.comparator !== void 0) this.comparator = options.comparator; this._reset(); @@ -606,7 +603,7 @@ // Default options for `Collection#set`. var setOptions = {add: true, remove: true, merge: true}; - var addOptions = {add: true, merge: false, remove: false}; + var addOptions = {add: true, remove: false}; // Define the Collection's inheritable methods. _.extend(Collection.prototype, Events, { @@ -632,16 +629,17 @@ // Add a model, or list of models to the set. add: function(models, options) { - return this.set(models, _.defaults(options || {}, addOptions)); + return this.set(models, _.extend({merge: false}, options, addOptions)); }, // Remove a model, or a list of models from the set. remove: function(models, options) { - models = _.isArray(models) ? models.slice() : [models]; + var singular = !_.isArray(models); + models = singular ? [models] : _.clone(models); options || (options = {}); var i, l, index, model; for (i = 0, l = models.length; i < l; i++) { - model = this.get(models[i]); + model = models[i] = this.get(models[i]); if (!model) continue; delete this._byId[model.id]; delete this._byId[model.cid]; @@ -654,7 +652,7 @@ } this._removeReference(model); } - return this; + return singular ? models[0] : models; }, // Update a collection by `set`-ing a new list of models, adding new ones, @@ -662,31 +660,45 @@ // already exist in the collection, as necessary. Similar to **Model#set**, // the core operation for updating the data contained by the collection. set: function(models, options) { - options = _.defaults(options || {}, setOptions); + options = _.defaults({}, options, setOptions); if (options.parse) models = this.parse(models, options); - if (!_.isArray(models)) models = models ? [models] : []; - var i, l, model, attrs, existing, sort; + var singular = !_.isArray(models); + models = singular ? (models ? [models] : []) : _.clone(models); + var i, l, id, model, attrs, existing, sort; var at = options.at; + var targetModel = this.model; var sortable = this.comparator && (at == null) && options.sort !== false; var sortAttr = _.isString(this.comparator) ? this.comparator : null; var toAdd = [], toRemove = [], modelMap = {}; + var add = options.add, merge = options.merge, remove = options.remove; + var order = !sortable && add && remove ? [] : false; // Turn bare objects into model references, and prevent invalid models // from being added. for (i = 0, l = models.length; i < l; i++) { - if (!(model = this._prepareModel(models[i], options))) continue; + attrs = models[i]; + if (attrs instanceof Model) { + id = model = attrs; + } else { + id = attrs[targetModel.prototype.idAttribute]; + } // If a duplicate is found, prevent it from being added and // optionally merge it into the existing model. - if (existing = this.get(model)) { - if (options.remove) modelMap[existing.cid] = true; - if (options.merge) { - existing.set(model.attributes, options); + if (existing = this.get(id)) { + if (remove) modelMap[existing.cid] = true; + if (merge) { + attrs = attrs === model ? model.attributes : attrs; + if (options.parse) attrs = existing.parse(attrs, options); + existing.set(attrs, options); if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; } + models[i] = existing; - // This is a new model, push it to the `toAdd` list. - } else if (options.add) { + // If this is a new, valid model, push it to the `toAdd` list. + } else if (add) { + model = models[i] = this._prepareModel(attrs, options); + if (!model) continue; toAdd.push(model); // Listen to added models' events, and index models for lookup by @@ -695,10 +707,11 @@ this._byId[model.cid] = model; if (model.id != null) this._byId[model.id] = model; } + if (order) order.push(existing || model); } // Remove nonexistent models if appropriate. - if (options.remove) { + if (remove) { for (i = 0, l = this.length; i < l; ++i) { if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); } @@ -706,29 +719,35 @@ } // See if sorting is needed, update `length` and splice in new models. - if (toAdd.length) { + if (toAdd.length || (order && order.length)) { if (sortable) sort = true; this.length += toAdd.length; if (at != null) { - splice.apply(this.models, [at, 0].concat(toAdd)); + for (i = 0, l = toAdd.length; i < l; i++) { + this.models.splice(at + i, 0, toAdd[i]); + } } else { - push.apply(this.models, toAdd); + if (order) this.models.length = 0; + var orderedModels = order || toAdd; + for (i = 0, l = orderedModels.length; i < l; i++) { + this.models.push(orderedModels[i]); + } } } // Silently sort the collection if appropriate. if (sort) this.sort({silent: true}); - if (options.silent) return this; - - // Trigger `add` events. - for (i = 0, l = toAdd.length; i < l; i++) { - (model = toAdd[i]).trigger('add', model, this, options); + // Unless silenced, it's time to fire all appropriate add/sort events. + if (!options.silent) { + for (i = 0, l = toAdd.length; i < l; i++) { + (model = toAdd[i]).trigger('add', model, this, options); + } + if (sort || (order && order.length)) this.trigger('sort', this, options); } - - // Trigger `sort` if the collection was sorted. - if (sort) this.trigger('sort', this, options); - return this; + + // Return the added (or merged) model (or models). + return singular ? models[0] : models; }, // When you have more items than you want to add or remove individually, @@ -742,16 +761,14 @@ } options.previousModels = this.models; this._reset(); - this.add(models, _.extend({silent: true}, options)); + models = this.add(models, _.extend({silent: true}, options)); if (!options.silent) this.trigger('reset', this, options); - return this; + return models; }, // Add a model to the end of the collection. push: function(model, options) { - model = this._prepareModel(model, options); - this.add(model, _.extend({at: this.length}, options)); - return model; + return this.add(model, _.extend({at: this.length}, options)); }, // Remove a model from the end of the collection. @@ -763,9 +780,7 @@ // Add a model to the beginning of the collection. unshift: function(model, options) { - model = this._prepareModel(model, options); - this.add(model, _.extend({at: 0}, options)); - return model; + return this.add(model, _.extend({at: 0}, options)); }, // Remove a model from the beginning of the collection. @@ -776,14 +791,14 @@ }, // Slice out a sub-array of models from the collection. - slice: function(begin, end) { - return this.models.slice(begin, end); + slice: function() { + return slice.apply(this.models, arguments); }, // Get a model from the set by id. get: function(obj) { if (obj == null) return void 0; - return this._byId[obj.id != null ? obj.id : obj.cid || obj]; + return this._byId[obj.id] || this._byId[obj.cid] || this._byId[obj]; }, // Get the model at the given index. @@ -827,16 +842,6 @@ return this; }, - // Figure out the smallest index at which a model should be inserted so as - // to maintain order. - sortedIndex: function(model, value, context) { - value || (value = this.comparator); - var iterator = _.isFunction(value) ? value : function(model) { - return model.get(value); - }; - return _.sortedIndex(this.models, model, iterator, context); - }, - // Pluck an attribute from each model in the collection. pluck: function(attr) { return _.invoke(this.models, 'get', attr); @@ -869,7 +874,7 @@ if (!options.wait) this.add(model, options); var collection = this; var success = options.success; - options.success = function(resp) { + options.success = function(model, resp, options) { if (options.wait) collection.add(model, options); if (success) success(model, resp, options); }; @@ -903,14 +908,12 @@ if (!attrs.collection) attrs.collection = this; return attrs; } - options || (options = {}); + options = options ? _.clone(options) : {}; options.collection = this; var model = new this.model(attrs, options); - if (!model._validate(attrs, options)) { - this.trigger('invalid', this, attrs, options); - return false; - } - return model; + if (!model.validationError) return model; + this.trigger('invalid', this, model.validationError, options); + return false; }, // Internal method to sever a model's ties to a collection. @@ -942,8 +945,8 @@ 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', - 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf', - 'isEmpty', 'chain']; + 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle', + 'lastIndexOf', 'isEmpty', 'chain']; // Mix in each Underscore method as a proxy to `Collection#models`. _.each(methods, function(method) { @@ -982,7 +985,8 @@ // if an existing element is not provided... var View = Backbone.View = function(options) { this.cid = _.uniqueId('view'); - this._configure(options || {}); + options || (options = {}); + _.extend(this, _.pick(options, viewOptions)); this._ensureElement(); this.initialize.apply(this, arguments); this.delegateEvents(); @@ -1001,7 +1005,7 @@ tagName: 'div', // jQuery delegate for element lookup, scoped to DOM elements within the - // current view. This should be prefered to global lookups where possible. + // current view. This should be preferred to global lookups where possible. $: function(selector) { return this.$el.find(selector); }, @@ -1041,7 +1045,7 @@ // // { // 'mousedown .title': 'edit', - // 'click .button': 'save' + // 'click .button': 'save', // 'click .open': function(e) { ... } // } // @@ -1079,16 +1083,6 @@ return this; }, - // Performs the initial configuration of a View with a set of options. - // Keys with special meaning *(e.g. model, collection, id, className)* are - // attached directly to the view. See `viewOptions` for an exhaustive - // list. - _configure: function(options) { - if (this.options) options = _.extend({}, _.result(this, 'options'), options); - _.extend(this, _.pick(options, viewOptions)); - this.options = options; - }, - // Ensure that the View has a DOM element to render into. // If `this.el` is a string, pass it through `$()`, take the first // matching element, and re-assign it to `el`. Otherwise, create @@ -1174,8 +1168,7 @@ // If we're sending a `PATCH` request, and we're in an old Internet Explorer // that still has ActiveX enabled by default, override jQuery to use that // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8. - if (params.type === 'PATCH' && window.ActiveXObject && - !(window.external && window.external.msActiveXFilteringEnabled)) { + if (params.type === 'PATCH' && noXhrPatch) { params.xhr = function() { return new ActiveXObject("Microsoft.XMLHTTP"); }; @@ -1187,6 +1180,8 @@ return xhr; }; + var noXhrPatch = typeof window !== 'undefined' && !!window.ActiveXObject && !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent); + // Map from CRUD to HTTP for our default `Backbone.sync` implementation. var methodMap = { 'create': 'POST', @@ -1275,7 +1270,7 @@ _routeToRegExp: function(route) { route = route.replace(escapeRegExp, '\\$&') .replace(optionalParam, '(?:$1)?') - .replace(namedParam, function(match, optional){ + .replace(namedParam, function(match, optional) { return optional ? match : '([^\/]+)'; }) .replace(splatParam, '(.*?)'); @@ -1325,6 +1320,9 @@ // Cached regex for removing a trailing slash. var trailingSlash = /\/$/; + // Cached regex for stripping urls of hash and query. + var pathStripper = /[?#].*$/; + // Has the history handling already been started? History.started = false; @@ -1349,7 +1347,7 @@ if (this._hasPushState || !this._wantsHashChange || forcePushState) { fragment = this.location.pathname; var root = this.root.replace(trailingSlash, ''); - if (!fragment.indexOf(root)) fragment = fragment.substr(root.length); + if (!fragment.indexOf(root)) fragment = fragment.slice(root.length); } else { fragment = this.getHash(); } @@ -1365,7 +1363,7 @@ // Figure out the initial configuration. Do we need an iframe? // Is pushState desired ... is it available? - this.options = _.extend({}, {root: '/'}, this.options, options); + this.options = _.extend({root: '/'}, this.options, options); this.root = this.options.root; this._wantsHashChange = this.options.hashChange !== false; this._wantsPushState = !!this.options.pushState; @@ -1398,19 +1396,25 @@ var loc = this.location; var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root; - // If we've started off with a route from a `pushState`-enabled browser, - // but we're currently in a browser that doesn't support it... - if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) { - this.fragment = this.getFragment(null, true); - this.location.replace(this.root + this.location.search + '#' + this.fragment); - // Return immediately as browser will do redirect to new url - return true; + // Transition from hashChange to pushState or vice versa if both are + // requested. + if (this._wantsHashChange && this._wantsPushState) { + + // If we've started off with a route from a `pushState`-enabled + // browser, but we're currently in a browser that doesn't support it... + if (!this._hasPushState && !atRoot) { + this.fragment = this.getFragment(null, true); + this.location.replace(this.root + this.location.search + '#' + this.fragment); + // Return immediately as browser will do redirect to new url + return true; + + // Or if we've started out with a hash-based route, but we're currently + // in a browser where it could be `pushState`-based instead... + } else if (this._hasPushState && atRoot && loc.hash) { + this.fragment = this.getHash().replace(routeStripper, ''); + this.history.replaceState({}, document.title, this.root + this.fragment + loc.search); + } - // Or if we've started out with a hash-based route, but we're currently - // in a browser where it could be `pushState`-based instead... - } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) { - this.fragment = this.getHash().replace(routeStripper, ''); - this.history.replaceState({}, document.title, this.root + this.fragment + loc.search); } if (!this.options.silent) return this.loadUrl(); @@ -1439,21 +1443,20 @@ } if (current === this.fragment) return false; if (this.iframe) this.navigate(current); - this.loadUrl() || this.loadUrl(this.getHash()); + this.loadUrl(); }, // Attempt to load the current URL fragment. If a route succeeds with a // match, returns `true`. If no defined routes matches the fragment, // returns `false`. - loadUrl: function(fragmentOverride) { - var fragment = this.fragment = this.getFragment(fragmentOverride); - var matched = _.any(this.handlers, function(handler) { + loadUrl: function(fragment) { + fragment = this.fragment = this.getFragment(fragment); + return _.any(this.handlers, function(handler) { if (handler.route.test(fragment)) { handler.callback(fragment); return true; } }); - return matched; }, // Save a fragment into the hash history, or replace the URL state if the @@ -1465,11 +1468,18 @@ // you wish to modify the current URL without adding an entry to the history. navigate: function(fragment, options) { if (!History.started) return false; - if (!options || options === true) options = {trigger: options}; - fragment = this.getFragment(fragment || ''); + if (!options || options === true) options = {trigger: !!options}; + + var url = this.root + (fragment = this.getFragment(fragment || '')); + + // Strip the fragment of the query and hash for matching. + fragment = fragment.replace(pathStripper, ''); + if (this.fragment === fragment) return; this.fragment = fragment; - var url = this.root + fragment; + + // Don't include a trailing slash on the root. + if (fragment === '' && url !== '/') url = url.slice(0, -1); // If pushState is available, we use it to set the fragment as a real URL. if (this._hasPushState) { @@ -1492,7 +1502,7 @@ } else { return this.location.assign(url); } - if (options.trigger) this.loadUrl(fragment); + if (options.trigger) return this.loadUrl(fragment); }, // Update the hash location, either replacing the current entry, or adding @@ -1560,7 +1570,7 @@ }; // Wrap an optional error callback with a fallback error event. - var wrapError = function (model, options) { + var wrapError = function(model, options) { var error = options.error; options.error = function(resp) { if (error) error(model, resp, options); diff --git a/vendor/backbone/test/collection.js b/vendor/backbone/test/collection.js index d068b39613..748d7bba0f 100644 --- a/vendor/backbone/test/collection.js +++ b/vendor/backbone/test/collection.js @@ -1,12 +1,10 @@ -$(document).ready(function() { +(function() { var a, b, c, d, e, col, otherCol; - module("Backbone.Collection", _.extend(new Environment, { + module("Backbone.Collection", { setup: function() { - Environment.prototype.setup.apply(this, arguments); - a = new Backbone.Model({id: 3, label: 'a'}); b = new Backbone.Model({id: 2, label: 'b'}); c = new Backbone.Model({id: 1, label: 'c'}); @@ -16,7 +14,7 @@ $(document).ready(function() { otherCol = new Backbone.Collection(); } - })); + }); test("new and sort", 9, function() { var counter = 0; @@ -87,7 +85,7 @@ $(document).ready(function() { equal(col2.get(model.clone()), col2.first()); }); - test("update index when id changes", 3, function() { + test("update index when id changes", 4, function() { var col = new Backbone.Collection(); col.add([ {id : 0, name : 'one'}, @@ -95,9 +93,10 @@ $(document).ready(function() { ]); var one = col.get(0); equal(one.get('name'), 'one'); - one.set({id : 101}); + col.on('change:name', function (model) { ok(this.get(model)); }); + one.set({name: 'dalmatians', id : 101}); equal(col.get(0), null); - equal(col.get(101).get('name'), 'one'); + equal(col.get(101).get('name'), 'dalmatians'); }); test("at", 1, function() { @@ -226,13 +225,13 @@ $(document).ready(function() { }); test("add with parse and merge", function() { - var Model = Backbone.Model.extend({ - parse: function (data) { - return data.model; - } - }); var collection = new Backbone.Collection(); - collection.model = Model; + collection.parse = function(attrs) { + return _.map(attrs, function(model) { + if (model.model) return model.model; + return model; + }); + }; collection.add({id: 1}); collection.add({model: {id: 1, name: 'Alf'}}, {parse: true, merge: true}); equal(collection.first().get('name'), 'Alf'); @@ -288,6 +287,39 @@ $(document).ready(function() { equal(otherRemoved, null); }); + test("add and remove return values", 13, function() { + var Even = Backbone.Model.extend({ + validate: function(attrs) { + if (attrs.id % 2 !== 0) return "odd"; + } + }); + var col = new Backbone.Collection; + col.model = Even; + + var list = col.add([{id: 2}, {id: 4}], {validate: true}); + equal(list.length, 2); + ok(list[0] instanceof Backbone.Model); + equal(list[1], col.last()); + equal(list[1].get('id'), 4); + + list = col.add([{id: 3}, {id: 6}], {validate: true}); + equal(col.length, 3); + equal(list[0], false); + equal(list[1].get('id'), 6); + + var result = col.add({id: 6}); + equal(result.cid, list[1].cid); + + result = col.remove({id: 6}); + equal(col.length, 2); + equal(result.id, 6); + + list = col.remove([{id: 2}, {id: 8}]); + equal(col.length, 1); + equal(list[0].get('id'), 2); + equal(list[1], null); + }); + test("shift and pop", 2, function() { var col = new Backbone.Collection([{a: 'a'}, {b: 'b'}, {c: 'c'}]); equal(col.shift().get('a'), 'a'); @@ -438,7 +470,7 @@ $(document).ready(function() { equal(model.collection, collection); }); - test("create with validate:true enforces validation", 2, function() { + test("create with validate:true enforces validation", 3, function() { var ValidatingModel = Backbone.Model.extend({ validate: function(attrs) { return "fail"; @@ -448,7 +480,8 @@ $(document).ready(function() { model: ValidatingModel }); var col = new ValidatingCollection(); - col.on('invalid', function (collection, attrs, options) { + col.on('invalid', function (collection, error, options) { + equal(error, "fail"); equal(options.validationError, 'fail'); }); equal(col.create({"foo":"bar"}, {validate:true}), false); @@ -502,7 +535,7 @@ $(document).ready(function() { equal(coll.findWhere({a: 4}), void 0); }); - test("Underscore methods", 13, function() { + test("Underscore methods", 14, function() { equal(col.map(function(model){ return model.get('label'); }).join(' '), 'a b c d'); equal(col.any(function(model){ return model.id === 100; }), false); equal(col.any(function(model){ return model.id === 0; }), true); @@ -520,18 +553,7 @@ $(document).ready(function() { .map(function(o){ return o.id * 2; }) .value(), [4, 0]); - }); - - test("sortedIndex", function () { - var model = new Backbone.Model({key: 2}); - var collection = new (Backbone.Collection.extend({ - comparator: 'key' - }))([model, {key: 1}]); - equal(collection.sortedIndex(model), 1); - equal(collection.sortedIndex(model, 'key'), 1); - equal(collection.sortedIndex(model, function (model) { - return model.get('key'); - }), 1); + deepEqual(col.difference([c, d]), [a, b]); }); test("reset", 12, function() { @@ -920,6 +942,20 @@ $(document).ready(function() { strictEqual(c.length, 0); }); + test("set with many models does not overflow the stack", function() { + var n = 150000; + var collection = new Backbone.Collection(); + var models = []; + for (var i = 0; i < n; i++) { + models.push({id: i}); + } + collection.set(models); + equal(collection.length, n); + collection.reset(); + collection.set(models, {at: 0}); + equal(collection.length, n); + }); + test("set with only cids", 3, function() { var m1 = new Backbone.Model; var m2 = new Backbone.Model; @@ -963,17 +999,33 @@ $(document).ready(function() { equal(col.first().get('key'), 'other'); col.set({id: 1, other: 'value'}); - equal(col.first().get('key'), 'value'); + equal(col.first().get('key'), 'other'); equal(col.length, 1); }); - test("`set` and model level `parse`", function() { + test('merge without mutation', function () { var Model = Backbone.Model.extend({ - parse: function (res) { return res.model; } + initialize: function (attrs, options) { + if (attrs.child) { + this.set('child', new Model(attrs.child, options), options); + } + } }); + var Collection = Backbone.Collection.extend({model: Model}); + var data = [{id: 1, child: {id: 2}}]; + var collection = new Collection(data); + equal(collection.first().id, 1); + collection.set(data); + equal(collection.first().id, 1); + collection.set([{id: 2, child: {id: 2}}].concat(data)); + deepEqual(collection.pluck('id'), [2, 1]); + }); + + test("`set` and model level `parse`", function() { + var Model = Backbone.Model.extend({}); var Collection = Backbone.Collection.extend({ model: Model, - parse: function (res) { return res.models; } + parse: function (res) { return _.pluck(res.models, 'model'); } }); var model = new Model({id: 1}); var collection = new Collection(model); @@ -996,6 +1048,25 @@ $(document).ready(function() { collection.set({}, {parse: true}); }); + test('`set` matches input order in the absence of a comparator', function () { + var one = new Backbone.Model({id: 1}); + var two = new Backbone.Model({id: 2}); + var three = new Backbone.Model({id: 3}); + var collection = new Backbone.Collection([one, two, three]); + collection.set([{id: 3}, {id: 2}, {id: 1}]); + deepEqual(collection.models, [three, two, one]); + collection.set([{id: 1}, {id: 2}]); + deepEqual(collection.models, [one, two]); + collection.set([two, three, one]); + deepEqual(collection.models, [two, three, one]); + collection.set([{id: 1}, {id: 2}], {remove: false}); + deepEqual(collection.models, [two, three, one]); + collection.set([{id: 1}, {id: 2}, {id: 3}], {merge: false}); + deepEqual(collection.models, [one, two, three]); + collection.set([three, two, one, {id: 4}], {add: false}); + deepEqual(collection.models, [one, two, three]); + }); + test("#1894 - Push should not trigger a sort", 0, function() { var Collection = Backbone.Collection.extend({ comparator: 'id', @@ -1006,6 +1077,13 @@ $(document).ready(function() { new Collection().push({id: 1}); }); + test("#2428 - push duplicate models, return the correct one", 1, function() { + var col = new Backbone.Collection; + var model1 = col.push({id: 101}); + var model2 = col.push({id: 101}) + ok(model2.cid == model1.cid); + }); + test("`set` with non-normal id", function() { var Collection = Backbone.Collection.extend({ model: Backbone.Model.extend({idAttribute: '_id'}) @@ -1081,20 +1159,119 @@ $(document).ready(function() { collection.add(collection.models, {merge: true}); // don't sort }); - test("Attach options to collection.", 3, function() { - var url = '/somewhere'; - var model = new Backbone.Model; - var comparator = function(){}; + test("Attach options to collection.", 2, function() { + var model = new Backbone.Model; + var comparator = function(){}; - var collection = new Backbone.Collection([], { - url: url, - model: model, - comparator: comparator - }); + var collection = new Backbone.Collection([], { + model: model, + comparator: comparator + }); - strictEqual(collection.url, url); - ok(collection.model === model); - ok(collection.comparator === comparator); + ok(collection.model === model); + ok(collection.comparator === comparator); }); -}); + test("`add` overrides `set` flags", function () { + var collection = new Backbone.Collection(); + collection.once('add', function (model, collection, options) { + collection.add({id: 2}, options); + }); + collection.set({id: 1}); + equal(collection.length, 2); + }); + + test("#2606 - Collection#create, success arguments", 1, function() { + var collection = new Backbone.Collection; + collection.url = 'test'; + collection.create({}, { + success: function(model, resp, options) { + strictEqual(resp, 'response'); + } + }); + this.ajaxSettings.success('response'); + }); + + test("#2612 - nested `parse` works with `Collection#set`", function() { + + var Job = Backbone.Model.extend({ + constructor: function() { + this.items = new Items(); + Backbone.Model.apply(this, arguments); + }, + parse: function(attrs) { + this.items.set(attrs.items, {parse: true}); + return _.omit(attrs, 'items'); + } + }); + + var Item = Backbone.Model.extend({ + constructor: function() { + this.subItems = new Backbone.Collection(); + Backbone.Model.apply(this, arguments); + }, + parse: function(attrs) { + this.subItems.set(attrs.subItems, {parse: true}); + return _.omit(attrs, 'subItems'); + } + }); + + var Items = Backbone.Collection.extend({ + model: Item + }); + + var data = { + name: 'JobName', + id: 1, + items: [{ + id: 1, + name: 'Sub1', + subItems: [ + {id: 1, subName: 'One'}, + {id: 2, subName: 'Two'} + ] + }, { + id: 2, + name: 'Sub2', + subItems: [ + {id: 3, subName: 'Three'}, + {id: 4, subName: 'Four'} + ] + }] + }; + + var newData = { + name: 'NewJobName', + id: 1, + items: [{ + id: 1, + name: 'NewSub1', + subItems: [ + {id: 1,subName: 'NewOne'}, + {id: 2,subName: 'NewTwo'} + ] + }, { + id: 2, + name: 'NewSub2', + subItems: [ + {id: 3,subName: 'NewThree'}, + {id: 4,subName: 'NewFour'} + ] + }] + }; + + var job = new Job(data, {parse: true}); + equal(job.get('name'), 'JobName'); + equal(job.items.at(0).get('name'), 'Sub1'); + equal(job.items.length, 2); + equal(job.items.get(1).subItems.get(1).get('subName'), 'One'); + equal(job.items.get(2).subItems.get(3).get('subName'), 'Three'); + job.set(job.parse(newData, {parse: true})); + equal(job.get('name'), 'NewJobName'); + equal(job.items.at(0).get('name'), 'NewSub1'); + equal(job.items.length, 2); + equal(job.items.get(1).subItems.get(1).get('subName'), 'NewOne'); + equal(job.items.get(2).subItems.get(3).get('subName'), 'NewThree'); + }); + +})(); diff --git a/vendor/backbone/test/environment.js b/vendor/backbone/test/environment.js index 54aa2c4071..996884bbe0 100644 --- a/vendor/backbone/test/environment.js +++ b/vendor/backbone/test/environment.js @@ -1,45 +1,35 @@ (function() { - var Environment = this.Environment = function(){}; - - _.extend(Environment.prototype, { - - ajax: Backbone.ajax, - - sync: Backbone.sync, - - emulateHTTP: Backbone.emulateHTTP, - - emulateJSON: Backbone.emulateJSON, - - setup: function() { - var env = this; - - // Capture ajax settings for comparison. - Backbone.ajax = function(settings) { - env.ajaxSettings = settings; + var sync = Backbone.sync; + var ajax = Backbone.ajax; + var emulateHTTP = Backbone.emulateHTTP; + var emulateJSON = Backbone.emulateJSON; + + QUnit.testStart(function() { + var env = this.config.current.testEnvironment; + + // Capture ajax settings for comparison. + Backbone.ajax = function(settings) { + env.ajaxSettings = settings; + }; + + // Capture the arguments to Backbone.sync for comparison. + Backbone.sync = function(method, model, options) { + env.syncArgs = { + method: method, + model: model, + options: options }; + sync.apply(this, arguments); + }; - // Capture the arguments to Backbone.sync for comparison. - Backbone.sync = function(method, model, options) { - env.syncArgs = { - method: method, - model: model, - options: options - }; - env.sync.apply(this, arguments); - }; - }, - - teardown: function() { - this.syncArgs = null; - this.ajaxSettings = null; - Backbone.sync = this.sync; - Backbone.ajax = this.ajax; - Backbone.emulateHTTP = this.emulateHTTP; - Backbone.emulateJSON = this.emulateJSON; - } + }); + QUnit.testDone(function() { + Backbone.sync = sync; + Backbone.ajax = ajax; + Backbone.emulateHTTP = emulateHTTP; + Backbone.emulateJSON = emulateJSON; }); })(); diff --git a/vendor/backbone/test/events.js b/vendor/backbone/test/events.js index 1aa746ccee..9f6878e432 100644 --- a/vendor/backbone/test/events.js +++ b/vendor/backbone/test/events.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +(function() { module("Backbone.Events"); @@ -152,6 +152,31 @@ $(document).ready(function() { e.trigger("foo"); }); + test("stopListening cleans up references", 4, function() { + var a = _.extend({}, Backbone.Events); + var b = _.extend({}, Backbone.Events); + var fn = function() {}; + a.listenTo(b, 'all', fn).stopListening(); + equal(_.size(a._listeningTo), 0); + a.listenTo(b, 'all', fn).stopListening(b); + equal(_.size(a._listeningTo), 0); + a.listenTo(b, 'all', fn).stopListening(null, 'all'); + equal(_.size(a._listeningTo), 0); + a.listenTo(b, 'all', fn).stopListening(null, null, fn); + equal(_.size(a._listeningTo), 0); + }); + + test("listenTo and stopListening cleaning up references", 2, function() { + var a = _.extend({}, Backbone.Events); + var b = _.extend({}, Backbone.Events); + a.listenTo(b, 'all', function(){ ok(true); }); + b.trigger('anything'); + a.listenTo(b, 'other', function(){ ok(false); }); + a.stopListening(b, 'other'); + a.stopListening(b, 'all'); + equal(_.keys(a._listeningTo).length, 0); + }); + test("listenTo with empty callback doesn't throw an error", 1, function(){ var e = _.extend({}, Backbone.Events); e.listenTo(e, "foo", null); @@ -449,4 +474,4 @@ $(document).ready(function() { equal(obj, obj.stopListening()); }); -}); +})(); diff --git a/vendor/backbone/test/model.js b/vendor/backbone/test/model.js index 3b196c48ec..ec1ba54af1 100644 --- a/vendor/backbone/test/model.js +++ b/vendor/backbone/test/model.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +(function() { var proxy = Backbone.Model.extend(); var klass = Backbone.Collection.extend({ @@ -6,10 +6,9 @@ $(document).ready(function() { }); var doc, collection; - module("Backbone.Model", _.extend(new Environment, { + module("Backbone.Model", { setup: function() { - Environment.prototype.setup.apply(this, arguments); doc = new proxy({ id : '1-the-tempest', title : "The Tempest", @@ -20,7 +19,7 @@ $(document).ready(function() { collection.add(doc); } - })); + }); test("initialize", 3, function() { var Model = Backbone.Model.extend({ @@ -111,13 +110,6 @@ $(document).ready(function() { equal(model.url(), '/nested/1/collection/2'); }); - test('url and urlRoot are directly attached if passed in the options', 2, function () { - var model = new Backbone.Model({a: 1}, {url: '/test'}); - var model2 = new Backbone.Model({a: 2}, {urlRoot: '/test2'}); - equal(model.url, '/test'); - equal(model2.urlRoot, '/test2'); - }); - test("underscore methods", 5, function() { var model = new Backbone.Model({ 'foo': 'a', 'bar': 'b', 'baz': 'c' }); var model2 = model.clone(); @@ -712,6 +704,22 @@ $(document).ready(function() { ok(this.syncArgs.model === model); }); + test("save without `wait` doesn't set invalid attributes", function () { + var model = new Backbone.Model(); + model.validate = function () { return 1; } + model.save({a: 1}); + equal(model.get('a'), void 0); + }); + + test("save doesn't validate twice", function () { + var model = new Backbone.Model(); + var times = 0; + model.sync = function () {}; + model.validate = function () { ++times; } + model.save({}); + equal(times, 1); + }); + test("`hasChanged` for falsey keys", 2, function() { var model = new Backbone.Model(); model.set({x: true}, {silent: true}); @@ -1099,4 +1107,4 @@ $(document).ready(function() { model.set({a: true}); }); -}); +})(); diff --git a/vendor/backbone/test/noconflict.js b/vendor/backbone/test/noconflict.js index a0e55cac2b..ac4324d021 100644 --- a/vendor/backbone/test/noconflict.js +++ b/vendor/backbone/test/noconflict.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +(function() { module("Backbone.noConflict"); @@ -9,4 +9,4 @@ $(document).ready(function() { equal(window.Backbone, noconflictBackbone, 'Backbone is still pointing to the original Backbone'); }); -}); +})(); diff --git a/vendor/backbone/test/router.js b/vendor/backbone/test/router.js index e6e1b3d6ea..296546e4df 100644 --- a/vendor/backbone/test/router.js +++ b/vendor/backbone/test/router.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +(function() { var router = null; var location = null; @@ -75,6 +75,8 @@ $(document).ready(function() { "counter": "counter", "search/:query": "search", "search/:query/p:page": "search", + "charñ": "charUTF", + "char%C3%B1": "charEscaped", "contacts": "contacts", "contacts/new": "newContact", "contacts/:id": "loadContact", @@ -103,11 +105,19 @@ $(document).ready(function() { this.count++; }, - search : function(query, page) { + search: function(query, page) { this.query = query; this.page = page; }, + charUTF: function() { + this.charType = 'UTF'; + }, + + charEscaped: function() { + this.charType = 'escaped'; + }, + contacts: function(){ this.contact = 'index'; }, @@ -204,6 +214,10 @@ $(document).ready(function() { equal(router.page, '20'); }); + test("reports matched route via nagivate", 1, function() { + ok(Backbone.history.navigate('search/manhattan/p20', true)); + }); + test("route precedence via navigate", 6, function(){ // check both 0.9.x and backwards-compatibility options _.each([ { trigger: true }, true ], function( options ){ @@ -349,6 +363,13 @@ $(document).ready(function() { equal(lastRoute, 'search'); }); + test("#2666 - Hashes with UTF8 in them.", 2, function() { + Backbone.history.navigate('charñ', {trigger: true}); + equal(router.charType, 'UTF'); + Backbone.history.navigate('char%C3%B1', {trigger: true}); + equal(router.charType, 'escaped'); + }); + test("#1185 - Use pathname when hashChange is not wanted.", 1, function() { Backbone.history.stop(); location.replace('http://example.com/path/name#hash'); @@ -609,4 +630,100 @@ $(document).ready(function() { deepEqual({home: "root", index: "index.html", show: "show", search: "search"}, router.routes); }); -}); + test("#2538 - hashChange to pushState only if both requested.", 0, function() { + Backbone.history.stop(); + location.replace('http://example.com/root?a=b#x/y'); + Backbone.history = _.extend(new Backbone.History, { + location: location, + history: { + pushState: function(){}, + replaceState: function(){ ok(false); } + } + }); + Backbone.history.start({ + root: 'root', + pushState: true, + hashChange: false + }); + }); + + test('No hash fallback.', 0, function() { + Backbone.history.stop(); + Backbone.history = _.extend(new Backbone.History, { + location: location, + history: { + pushState: function(){}, + replaceState: function(){} + } + }); + + var Router = Backbone.Router.extend({ + routes: { + hash: function() { ok(false); } + } + }); + var router = new Router; + + location.replace('http://example.com/'); + Backbone.history.start({ + pushState: true, + hashChange: false + }); + location.replace('http://example.com/nomatch#hash'); + Backbone.history.checkUrl(); + }); + + test('#2656 - No trailing slash on root.', 1, function() { + Backbone.history.stop(); + Backbone.history = _.extend(new Backbone.History, { + location: location, + history: { + pushState: function(state, title, url){ + strictEqual(url, '/root'); + } + } + }); + location.replace('http://example.com/root/path'); + Backbone.history.start({pushState: true, root: 'root'}); + Backbone.history.navigate(''); + }); + + test('#2656 - No trailing slash on root.', 1, function() { + Backbone.history.stop(); + Backbone.history = _.extend(new Backbone.History, { + location: location, + history: { + pushState: function(state, title, url) { + strictEqual(url, '/'); + } + } + }); + location.replace('http://example.com/path'); + Backbone.history.start({pushState: true}); + Backbone.history.navigate(''); + }); + + test('#2765 - Fragment matching sans query/hash.', 2, function() { + Backbone.history.stop(); + Backbone.history = _.extend(new Backbone.History, { + location: location, + history: { + pushState: function(state, title, url) { + strictEqual(url, '/path?query#hash'); + } + } + }); + + var Router = Backbone.Router.extend({ + routes: { + path: function() { ok(true); } + } + }); + var router = new Router; + + location.replace('http://example.com/'); + Backbone.history.start({pushState: true}); + Backbone.history.navigate('path?query#hash', true); + }); + +})(); diff --git a/vendor/backbone/test/sync.js b/vendor/backbone/test/sync.js index 8fddb47fa2..d54a7963be 100644 --- a/vendor/backbone/test/sync.js +++ b/vendor/backbone/test/sync.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +(function() { var Library = Backbone.Collection.extend({ url : function() { return '/library'; } @@ -11,20 +11,18 @@ $(document).ready(function() { length : 123 }; - module("Backbone.sync", _.extend(new Environment, { + module("Backbone.sync", { setup : function() { - Environment.prototype.setup.apply(this, arguments); library = new Library; library.create(attrs, {wait: false}); }, teardown: function() { - Environment.prototype.teardown.apply(this, arguments); Backbone.emulateHTTP = false; } - })); + }); test("read", 4, function() { library.fetch(); @@ -209,4 +207,4 @@ $(document).ready(function() { strictEqual(this.ajaxSettings.beforeSend(xhr), false); }); -}); +})(); diff --git a/vendor/backbone/test/view.js b/vendor/backbone/test/view.js index 58a87718dc..65eee25dbd 100644 --- a/vendor/backbone/test/view.js +++ b/vendor/backbone/test/view.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +(function() { var view; @@ -14,13 +14,10 @@ $(document).ready(function() { }); - test("constructor", 6, function() { + test("constructor", 3, function() { equal(view.el.id, 'test-view'); equal(view.el.className, 'test-view'); equal(view.el.other, void 0); - equal(view.options.id, 'test-view'); - equal(view.options.className, 'test-view'); - equal(view.options.other, 'non-special-option'); }); test("jQuery", 1, function() { @@ -156,30 +153,6 @@ $(document).ready(function() { strictEqual(new View().el.id, 'id'); }); - test("with options function", 3, function() { - var View1 = Backbone.View.extend({ - options: function() { - return { - title: 'title1', - acceptText: 'confirm' - }; - } - }); - - var View2 = View1.extend({ - options: function() { - return _.extend(View1.prototype.options.call(this), { - title: 'title2', - fixed: true - }); - } - }); - - strictEqual(new View2().options.title, 'title2'); - strictEqual(new View2().options.acceptText, 'confirm'); - strictEqual(new View2().options.fixed, true); - }); - test("with attributes", 2, function() { var View = Backbone.View.extend({ attributes: { @@ -319,7 +292,7 @@ $(document).ready(function() { view.collection.trigger('x'); }); - test("Provide function for el.", 1, function() { + test("Provide function for el.", 2, function() { var View = Backbone.View.extend({ el: function() { return "

"; @@ -327,7 +300,8 @@ $(document).ready(function() { }); var view = new View; - ok(view.$el.is('p:has(a)')); + ok(view.$el.is('p')); + ok(view.$el.has('a')); }); test("events passed in options", 2, function() { @@ -354,4 +328,4 @@ $(document).ready(function() { equal(counter, 4); }); -}); +})(); From 7b7d5118d638e1bf9614c73c0566755ece74a9e3 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 11 Oct 2013 23:39:27 -0700 Subject: [PATCH 014/189] Add more Underscore "Collections" unit tests to test/test.js. --- test/test.js | 113 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 4 deletions(-) diff --git a/test/test.js b/test/test.js index 263714b8eb..79ab4150ca 100644 --- a/test/test.js +++ b/test/test.js @@ -138,6 +138,9 @@ /** Used to pass falsey values to methods */ var falsey = [, '', 0, false, NaN, null, undefined]; + /** Used to pass empty values to methods */ + var empties = [[]].concat(falsey.slice(1)); + /** Used as the size when optimizations are enabled for large arrays */ var largeArraySize = 75; @@ -708,6 +711,14 @@ 'a string': '123123' }, function(collection, key) { + test('should work with ' + key + ' and return `true` for matched values', 1, function() { + strictEqual(_.contains(collection, 3), true); + }); + + test('should work with ' + key + ' and return `false` for unmatched values', 1, function() { + strictEqual(_.contains(collection, 4), false); + }); + test('should work with ' + key + ' and a positive `fromIndex`', 1, function() { strictEqual(_.contains(collection, 1, 2), true); }); @@ -727,6 +738,15 @@ strictEqual(_.contains(collection, 1, -6), true); strictEqual(_.contains(collection, 2, -8), true); }); + + test('should work with ' + key + ' and return an unwrapped value when chaining', 1, function() { + if (!isNpm) { + strictEqual(_(collection).contains(3), true); + } + else { + skipTest(); + } + }); }); _.forEach({ @@ -1176,13 +1196,39 @@ QUnit.module('lodash.every'); (function() { - test('should return `false` as soon as the `callback` result is falsey', 1, function() { + test('should return `true` for empty or falsey collections', 1, function() { + var actual = [], + expected = _.map(empties, function() { return true; }); + + _.forEach(empties, function(value) { + try { + actual.push(_.every(value, _.identity)); + } catch(e) { } + }); + + deepEqual(actual, expected); + }); + + test('should return `true` if the callback returns truey for all elements in the collection', 1, function() { + strictEqual(_.every([true, 1, 'x'], _.identity), true); + }); + + test('should return `false` as soon as the callback result is falsey', 1, function() { strictEqual(_.every([true, null, true], _.identity), false); }); + test('should work with collections of `undefined` values (test in IE < 9)', 1, function() { + strictEqual(_.every([undefined, undefined, undefined], _.identity), false); + }); + test('should be aliased', 1, function() { strictEqual(_.all, _.every); }); + + test('should use `_.identity` when no callback is provided', 2, function() { + strictEqual(_.every([0]), false); + strictEqual(_.every([1]), true); + }); }()); /*--------------------------------------------------------------------------*/ @@ -1312,6 +1358,19 @@ strictEqual(func(objects, 'b'), expected[3]); }); + test('should return `' + expected[1] + '` for empty or falsey collections', 1, function() { + var actual = [], + expecting = _.map(empties, function() { return expected[1]; }); + + _.forEach(empties, function(value) { + try { + actual.push(func(value, { 'a': 3 })); + } catch(e) { } + }); + + deepEqual(actual, expecting); + }); + if (methodName == 'find') { test('should be aliased', 1, function() { strictEqual(_.detect, func); @@ -1847,7 +1906,7 @@ _.forEach(['assign', 'defaults', 'merge'], function(methodName) { var func = _[methodName]; - test('should return the existing wrapper when chaining', 1, function() { + test('`_.' + methodName + '` should return the existing wrapper when chaining', 1, function() { if (!isNpm) { var wrapper = _({ 'a': 1 }); equal(wrapper[methodName]({ 'b': 2 }), wrapper); @@ -1857,7 +1916,6 @@ } }); - test('`_.' + methodName + '` should assign problem JScript properties (test in IE < 9)', 1, function() { var object = { 'constructor': '0', @@ -2360,6 +2418,19 @@ QUnit.module('lodash.invoke'); (function() { + test('should invoke a methods on each element of a collection', 1, function() { + var actual = _.invoke(['a', 'b', 'c'], 'toUpperCase'); + deepEqual(actual, ['A', 'B', 'C']); + }); + + test('should work with a function `methodName` argument', 1, function() { + var actual = _.invoke(['a', 'b', 'c'], function() { + return this.toUpperCase(); + }); + + deepEqual(actual, ['A', 'B', 'C']); + }); + test('should work with an object for `collection`', 1, function() { var object = { 'a': 1, 'b': 2, 'c': 3 }; deepEqual(_.invoke(object, 'toFixed', 1), ['1.0', '2.0', '3.0']); @@ -3480,6 +3551,13 @@ QUnit.module('lodash.pluck'); (function() { + test('should return an array of property values from each element of a collection', 1, function() { + var objects = [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }], + actual = _.pluck(objects, 'name'); + + deepEqual(actual, ['moe', 'larry']); + }); + test('should work with an object for `collection`', 1, function() { var object = { 'a': [1], 'b': [1, 2], 'c': [1, 2, 3] }; deepEqual(_.pluck(object, 'length'), [1, 2, 3]); @@ -3790,7 +3868,6 @@ _.forEach(['reduce', 'reduceRight'], function(methodName) { var array = [1, 2, 3], - empties = [[]].concat(falsey.slice(1)), func = _[methodName], noop = function() {}; @@ -4237,6 +4314,29 @@ QUnit.module('lodash.some'); (function() { + test('should return `false` for empty or falsey collections', 1, function() { + var actual = [], + expected = _.map(empties, function() { return false; }); + + _.forEach(empties, function(value) { + try { + actual.push(_.some(value, _.identity)); + } catch(e) { } + }); + + deepEqual(actual, expected); + }); + + test('should return `true` if the callback returns truey for any element in the collection', 2, function() { + strictEqual(_.some([false, 1, ''], _.identity), true); + strictEqual(_.some([null, 'x', 0], _.identity), true); + }); + + test('should return `false` if the callback returns falsey for all elements in the collection', 2, function() { + strictEqual(_.some([false, false, false], _.identity), false); + strictEqual(_.some([null, 0, ''], _.identity), false); + }); + test('should return `true` as soon as the `callback` result is truey', 1, function() { strictEqual(_.some([null, true, null], _.identity), true); }); @@ -4244,6 +4344,11 @@ test('should be aliased', 1, function() { strictEqual(_.any, _.some); }); + + test('should use `_.identity` when no callback is provided', 2, function() { + strictEqual(_.some([0, 1]), true); + strictEqual(_.some([0, 0]), false); + }); }()); /*--------------------------------------------------------------------------*/ From d01284d1470d8acc5d212470e20412670879f04d Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 11 Oct 2013 23:47:44 -0700 Subject: [PATCH 015/189] Changes stooges to flintstones and add doc examples to `_.findIndex`, `_.findLastIndex`, `_.findKey`, and `_.findLastKey` for "_.pluck" and "_.where" shorthands. [closes #362] --- lodash.js | 525 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 303 insertions(+), 222 deletions(-) diff --git a/lodash.js b/lodash.js index 10f00666c0..114c8b7a0a 100644 --- a/lodash.js +++ b/lodash.js @@ -1960,16 +1960,16 @@ * @returns {Object} Returns the destination object. * @example * - * _.assign({ 'name': 'moe' }, { 'age': 40 }); - * // => { 'name': 'moe', 'age': 40 } + * _.assign({ 'name': 'fred' }, { 'age': 40 }); + * // => { 'name': 'fred', 'age': 40 } * * var defaults = _.partialRight(_.assign, function(a, b) { * return typeof a == 'undefined' ? b : a; * }); * - * var food = { 'name': 'apple' }; - * defaults(food, { 'name': 'banana', 'type': 'fruit' }); - * // => { 'name': 'apple', 'type': 'fruit' } + * var person = { 'name': 'barney' }; + * defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * // => { 'name': 'barney', 'employer': 'slate' } */ var assign = createIterator(defaultsIteratorOptions, { 'top': @@ -2001,17 +2001,17 @@ * @returns {*} Returns the cloned value. * @example * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * var shallow = _.clone(stooges); - * shallow[0] === stooges[0]; + * var shallow = _.clone(characters); + * shallow[0] === characters[0]; * // => true * - * var deep = _.clone(stooges, true); - * deep[0] === stooges[0]; + * var deep = _.clone(characters, true); + * deep[0] === characters[0]; * // => false * * _.mixin({ @@ -2055,13 +2055,13 @@ * @returns {*} Returns the deep cloned value. * @example * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * var deep = _.cloneDeep(stooges); - * deep[0] === stooges[0]; + * var deep = _.cloneDeep(characters); + * deep[0] === characters[0]; * // => false * * var view = { @@ -2096,9 +2096,9 @@ * @returns {Object} Returns the destination object. * @example * - * var food = { 'name': 'apple' }; - * _.defaults(food, { 'name': 'banana', 'type': 'fruit' }); - * // => { 'name': 'apple', 'type': 'fruit' } + * var person = { 'name': 'barney' }; + * _.defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * // => { 'name': 'barney', 'employer': 'slate' } */ var defaults = createIterator(defaultsIteratorOptions); @@ -2106,6 +2106,13 @@ * This method is like `_.findIndex` except that it returns the key of the * first element that passes the callback check, instead of the element itself. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Objects @@ -2117,10 +2124,24 @@ * @returns {string|undefined} Returns the key of the found element, else `undefined`. * @example * - * _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) { - * return num % 2 == 0; + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true }, + * { 'name': 'pebbles', 'age': 1, 'blocked': false } + * ]; + * + * _.findKey(characters, function(chr) { + * return chr.age < 40; * }); - * // => 'b' (property order is not guaranteed across environments) + * // => 'barney' (property order is not guaranteed across environments) + * + * // using "_.where" callback shorthand + * _.findKey(characters, { 'age': 1 }); + * // => 'pebbles' + * + * // using "_.pluck" callback shorthand + * _.findKey(characters, 'blocked'); + * // => 'fred' */ function findKey(object, callback, thisArg) { var result; @@ -2138,6 +2159,13 @@ * This method is like `_.findKey` except that it iterates over elements * of a `collection` in the opposite order. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Objects @@ -2149,10 +2177,24 @@ * @returns {string|undefined} Returns the key of the found element, else `undefined`. * @example * - * _.findLastKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) { - * return num % 2 == 1; + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': true }, + * { 'name': 'fred', 'age': 40, 'blocked': false }, + * { 'name': 'pebbles', 'age': 1, 'blocked': true } + * ]; + * + * _.findLastKey(characters, function(chr) { + * return chr.age < 40; * }); - * // => returns `c`, assuming `_.findKey` returns `a` + * // => returns `pebbles`, assuming `_.findKey` returns `barney` + * + * // using "_.where" callback shorthand + * _.findLastKey(characters, { 'age': 40 }); + * // => 'fred' + * + * // using "_.pluck" callback shorthand + * _.findLastKey(characters, 'blocked'); + * // => 'pebbles' */ function findLastKey(object, callback, thisArg) { var result; @@ -2351,8 +2393,8 @@ * @returns {Object} Returns the created inverted object. * @example * - * _.invert({ 'first': 'moe', 'second': 'larry' }); - * // => { 'moe': 'first', 'larry': 'second' } + * _.invert({ 'first': 'fred', 'second': 'barney' }); + * // => { 'fred': 'first', 'barney': 'second' } */ function invert(object) { var index = -1, @@ -2475,13 +2517,13 @@ * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * - * var moe = { 'name': 'moe', 'age': 40 }; - * var copy = { 'name': 'moe', 'age': 40 }; + * var fred = { 'name': 'fred', 'age': 40 }; + * var copy = { 'name': 'fred', 'age': 40 }; * - * moe == copy; + * fred == copy; * // => false * - * _.isEqual(moe, copy); + * _.isEqual(fred, copy); * // => true * * var words = ['hello', 'goodbye']; @@ -2663,18 +2705,18 @@ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. * @example * - * function Stooge(name, age) { + * function Person(name, age) { * this.name = name; * this.age = age; * } * - * _.isPlainObject(new Stooge('moe', 40)); + * _.isPlainObject(new Person('fred', 40)); * // => false * * _.isPlainObject([1, 2, 3]); * // => false * - * _.isPlainObject({ 'name': 'moe', 'age': 40 }); + * _.isPlainObject({ 'name': 'fred', 'age': 40 }); * // => true */ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { @@ -2699,7 +2741,7 @@ * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`. * @example * - * _.isRegExp(/moe/); + * _.isRegExp(/fred/); * // => true */ function isRegExp(value) { @@ -2716,7 +2758,7 @@ * @returns {boolean} Returns `true` if the `value` is a string, else `false`. * @example * - * _.isString('moe'); + * _.isString('fred'); * // => true */ function isString(value) { @@ -2760,21 +2802,21 @@ * @example * * var names = { - * 'stooges': [ - * { 'name': 'moe' }, - * { 'name': 'larry' } + * 'characters': [ + * { 'name': 'barney' }, + * { 'name': 'fred' } * ] * }; * * var ages = { - * 'stooges': [ - * { 'age': 40 }, - * { 'age': 50 } + * 'characters': [ + * { 'age': 36 }, + * { 'age': 40 } * ] * }; * * _.merge(names, ages); - * // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] } + * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] } * * var food = { * 'fruits': ['apple'], @@ -2839,13 +2881,13 @@ * @returns {Object} Returns an object without the omitted properties. * @example * - * _.omit({ 'name': 'moe', 'age': 40 }, 'age'); - * // => { 'name': 'moe' } + * _.omit({ 'name': 'fred', 'age': 40 }, 'age'); + * // => { 'name': 'fred' } * - * _.omit({ 'name': 'moe', 'age': 40 }, function(value) { + * _.omit({ 'name': 'fred', 'age': 40 }, function(value) { * return typeof value == 'number'; * }); - * // => { 'name': 'moe' } + * // => { 'name': 'fred' } */ function omit(object, callback, thisArg) { var indexOf = getIndexOf(), @@ -2879,8 +2921,8 @@ * @returns {Array} Returns new array of key-value pairs. * @example * - * _.pairs({ 'moe': 30, 'larry': 40 }); - * // => [['moe', 30], ['larry', 40]] (property order is not guaranteed across environments) + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments) */ function pairs(object) { var index = -1, @@ -2914,13 +2956,13 @@ * @returns {Object} Returns an object composed of the picked properties. * @example * - * _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name'); - * // => { 'name': 'moe' } + * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name'); + * // => { 'name': 'fred' } * - * _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) { + * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) { * return key.charAt(0) != '_'; * }); - * // => { 'name': 'moe' } + * // => { 'name': 'fred' } */ function pick(object, callback, thisArg) { var result = {}; @@ -3042,8 +3084,8 @@ * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); * // => ['a', 'c', 'e'] * - * _.at(['moe', 'larry', 'curly'], 0, 2); - * // => ['moe', 'curly'] + * _.at(['fred', 'barney', 'pebbles'], 0, 2); + * // => ['fred', 'pebbles'] */ function at(collection) { var args = arguments, @@ -3082,10 +3124,10 @@ * _.contains([1, 2, 3], 1, 2); * // => false * - * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); + * _.contains({ 'name': 'fred', 'age': 40 }, 'fred'); * // => true * - * _.contains('curly', 'ur'); + * _.contains('pebbles', 'ur'); * // => true */ function contains(collection, target, fromIndex) { @@ -3175,17 +3217,17 @@ * _.every([true, 1, null, 'yes'], Boolean); * // => false * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * * // using "_.pluck" callback shorthand - * _.every(stooges, 'age'); + * _.every(characters, 'age'); * // => true * * // using "_.where" callback shorthand - * _.every(stooges, { 'age': 50 }); + * _.every(characters, { 'age': 36 }); * // => false */ function every(collection, callback, thisArg) { @@ -3236,18 +3278,18 @@ * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [2, 4, 6] * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } * ]; * * // using "_.pluck" callback shorthand - * _.filter(food, 'organic'); - * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] + * _.filter(characters, 'blocked'); + * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] * * // using "_.where" callback shorthand - * _.filter(food, { 'type': 'fruit' }); - * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] + * _.filter(characters, { 'age': 36 }); + * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] */ function filter(collection, callback, thisArg) { var result = []; @@ -3297,24 +3339,24 @@ * @returns {*} Returns the found element, else `undefined`. * @example * - * _.find([1, 2, 3, 4], function(num) { - * return num % 2 == 0; - * }); - * // => 2 - * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'banana', 'organic': true, 'type': 'fruit' }, - * { 'name': 'beet', 'organic': false, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true }, + * { 'name': 'pebbles', 'age': 1, 'blocked': false } * ]; * + * _.find(characters, function(chr) { + * return chr.age < 40; + * }); + * // => { 'name': 'barney', 'age': 36, 'blocked': false } + * * // using "_.where" callback shorthand - * _.find(food, { 'type': 'vegetable' }); - * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' } + * _.find(characters, { 'age': 1 }); + * // => { 'name': 'pebbles', 'age': 1, 'blocked': false } * * // using "_.pluck" callback shorthand - * _.find(food, 'organic'); - * // => { 'name': 'banana', 'organic': true, 'type': 'fruit' } + * _.find(characters, 'blocked'); + * // => { 'name': 'fred', 'age': 40, 'blocked': true } */ function find(collection, callback, thisArg) { callback = lodash.createCallback(callback, thisArg, 3); @@ -3529,7 +3571,7 @@ * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); }); * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } * - * _.indexBy(stooges, function(key) { this.fromCharCode(key.code); }, String); + * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String); * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } */ var indexBy = createAggregator(function(result, value, key) { @@ -3601,14 +3643,14 @@ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); * // => [3, 6, 9] (property order is not guaranteed across environments) * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * * // using "_.pluck" callback shorthand - * _.map(stooges, 'name'); - * // => ['moe', 'larry'] + * _.map(characters, 'name'); + * // => ['fred', 'barney'] */ function map(collection, callback, thisArg) { var index = -1, @@ -3656,17 +3698,17 @@ * _.max([4, 2, 8, 6]); * // => 8 * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * _.max(stooges, function(stooge) { return stooge.age; }); - * // => { 'name': 'larry', 'age': 50 }; + * _.max(characters, function(stooge) { return stooge.age; }); + * // => { 'name': 'barney', 'age': 36 }; * * // using "_.pluck" callback shorthand - * _.max(stooges, 'age'); - * // => { 'name': 'larry', 'age': 50 }; + * _.max(characters, 'age'); + * // => { 'name': 'barney', 'age': 36 }; */ function max(collection, callback, thisArg) { var computed = -Infinity, @@ -3726,17 +3768,17 @@ * _.min([4, 2, 8, 6]); * // => 2 * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * _.min(stooges, function(stooge) { return stooge.age; }); - * // => { 'name': 'moe', 'age': 40 }; + * _.min(characters, function(stooge) { return stooge.age; }); + * // => { 'name': 'fred', 'age': 40 }; * * // using "_.pluck" callback shorthand - * _.min(stooges, 'age'); - * // => { 'name': 'moe', 'age': 40 }; + * _.min(characters, 'age'); + * // => { 'name': 'fred', 'age': 40 }; */ function min(collection, callback, thisArg) { var computed = Infinity, @@ -3769,7 +3811,7 @@ } /** - * Retrieves the value of a specified property from all elements in the `collection`. + * Retrieves the value of a specified property from all elements in the collection. * * @static * @memberOf _ @@ -3780,13 +3822,13 @@ * @returns {Array} Returns a new array of property values. * @example * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * _.pluck(stooges, 'name'); - * // => ['moe', 'larry'] + * _.pluck(characters, 'name'); + * // => ['fred', 'barney'] */ var pluck = map; @@ -3899,18 +3941,18 @@ * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [1, 3, 5] * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } * ]; * * // using "_.pluck" callback shorthand - * _.reject(food, 'organic'); - * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] + * _.reject(characters, 'blocked'); + * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] * * // using "_.where" callback shorthand - * _.reject(food, { 'type': 'fruit' }); - * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] + * _.reject(characters, { 'age': 40 }); + * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] */ function reject(collection, callback, thisArg) { callback = lodash.createCallback(callback, thisArg, 3); @@ -3997,7 +4039,7 @@ * _.size({ 'one': 1, 'two': 2, 'three': 3 }); * // => 3 * - * _.size('curly'); + * _.size('pebbles'); * // => 5 */ function size(collection) { @@ -4034,17 +4076,17 @@ * _.some([null, 0, 'yes', false], Boolean); * // => true * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } * ]; * * // using "_.pluck" callback shorthand - * _.some(food, 'organic'); + * _.some(characters, 'blocked'); * // => true * * // using "_.where" callback shorthand - * _.some(food, { 'type': 'meat' }); + * _.some(characters, { 'age': 1 }); * // => false */ function some(collection, callback, thisArg) { @@ -4162,16 +4204,16 @@ * @returns {Array} Returns a new array of elements that have the given properties. * @example * - * var stooges = [ - * { 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }, - * { 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] } + * var characters = [ + * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] }, + * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } * ]; * - * _.where(stooges, { 'age': 40 }); - * // => [{ 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] }] + * _.where(characters, { 'age': 30 }); + * // => [{ 'name': 'barney', 'age': 30, 'pets': ['hoppy'] }] * - * _.where(stooges, { 'quotes': ['Poifect!'] }); - * // => [{ 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }] + * _.where(characters, { 'pets': ['dino'] }); + * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }] */ var where = filter; @@ -4254,6 +4296,13 @@ * This method is like `_.find` except that it returns the index of the first * element that passes the callback check, instead of the element itself. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Arrays @@ -4265,9 +4314,23 @@ * @returns {number} Returns the index of the found element, else `-1`. * @example * - * _.findIndex(['apple', 'banana', 'beet'], function(food) { - * return /^b/.test(food); + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true }, + * { 'name': 'pebbles', 'age': 1, 'blocked': false } + * ]; + * + * _.findIndex(characters, function(chr) { + * return chr.age < 20; * }); + * // => 2 + * + * // using "_.where" callback shorthand + * _.findIndex(characters, { 'age': 36 }); + * // => 0 + * + * // using "_.pluck" callback shorthand + * _.findIndex(characters, 'blocked'); * // => 1 */ function findIndex(array, callback, thisArg) { @@ -4287,6 +4350,13 @@ * This method is like `_.findIndex` except that it iterates over elements * of a `collection` from right to left. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Arrays @@ -4298,9 +4368,23 @@ * @returns {number} Returns the index of the found element, else `-1`. * @example * - * _.findLastIndex(['apple', 'banana', 'beet'], function(food) { - * return /^b/.test(food); + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': true }, + * { 'name': 'fred', 'age': 40, 'blocked': false }, + * { 'name': 'pebbles', 'age': 1, 'blocked': true } + * ]; + * + * _.findLastIndex(characters, function(chr) { + * return chr.age > 30; * }); + * // => 1 + * + * // using "_.where" callback shorthand + * _.findLastIndex(characters, { 'age': 36 }); + * // => 0 + * + * // using "_.pluck" callback shorthand + * _.findLastIndex(characters, 'blocked'); * // => 2 */ function findLastIndex(array, callback, thisArg) { @@ -4351,24 +4435,19 @@ * }); * // => [1, 2] * - * var food = [ - * { 'name': 'banana', 'organic': true }, - * { 'name': 'beet', 'organic': false }, + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': true, 'employer': 'slate' }, + * { 'name': 'fred', 'age': 40, 'blocked': false, 'employer': 'slate' }, + * { 'name': 'pebbles', 'age': 1, 'blocked': true, 'employer': 'na' } * ]; * * // using "_.pluck" callback shorthand - * _.first(food, 'organic'); - * // => [{ 'name': 'banana', 'organic': true }] - * - * var food = [ - * { 'name': 'apple', 'type': 'fruit' }, - * { 'name': 'banana', 'type': 'fruit' }, - * { 'name': 'beet', 'type': 'vegetable' } - * ]; + * _.first(characters, 'blocked'); + * // => [{ 'name': 'barney', 'age': 36, 'blocked': true, 'employer': 'slate' }] * * // using "_.where" callback shorthand - * _.first(food, { 'type': 'fruit' }); - * // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }] + * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name'); + * // => ['barney', 'fred'] */ function first(array, callback, thisArg) { var n = 0, @@ -4421,14 +4500,14 @@ * _.flatten([1, [2], [3, [[4]]]], true); * // => [1, 2, 3, [[4]]]; * - * var stooges = [ - * { 'name': 'curly', 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }, - * { 'name': 'moe', 'quotes': ['Spread out!', 'You knucklehead!'] } + * var characters = [ + * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] }, + * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } * ]; * * // using "_.pluck" callback shorthand - * _.flatten(stooges, 'quotes'); - * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] + * _.flatten(characters, 'pets'); + * // => ['hoppy', 'baby puss', 'dino'] */ function flatten(array, isShallow, callback, thisArg) { // juggle arguments @@ -4644,24 +4723,19 @@ * }); * // => [2, 3] * - * var food = [ - * { 'name': 'beet', 'organic': false }, - * { 'name': 'carrot', 'organic': true } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false, 'employer': 'slate' }, + * { 'name': 'fred', 'age': 40, 'blocked': true, 'employer': 'slate' }, + * { 'name': 'pebbles', 'age': 1, 'blocked': true, 'employer': 'na' } * ]; * * // using "_.pluck" callback shorthand - * _.last(food, 'organic'); - * // => [{ 'name': 'carrot', 'organic': true }] - * - * var food = [ - * { 'name': 'banana', 'type': 'fruit' }, - * { 'name': 'beet', 'type': 'vegetable' }, - * { 'name': 'carrot', 'type': 'vegetable' } - * ]; + * _.pluck(_.last(characters, 'blocked'), 'name'); + * // => ['fred', 'pebbles'] * * // using "_.where" callback shorthand - * _.last(food, { 'type': 'vegetable' }); - * // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }] + * _.last(characters, { 'employer': 'na' }); + * // => [{ 'name': 'pebbles', 'age': 1, 'blocked': true, 'employer': 'na' }] */ function last(array, callback, thisArg) { var n = 0, @@ -4687,6 +4761,13 @@ * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Arrays @@ -5098,8 +5179,8 @@ * @returns {Array} Returns a new array of grouped elements. * @example * - * _.zip(['moe', 'larry'], [30, 40], [true, false]); - * // => [['moe', 30, true], ['larry', 40, false]] + * _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] */ function zip() { var array = arguments.length > 1 ? arguments : arguments[0], @@ -5128,8 +5209,8 @@ * corresponding values. * @example * - * _.zipObject(['moe', 'larry'], [30, 40]); - * // => { 'moe': 30, 'larry': 40 } + * _.zipObject(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } */ function zipObject(keys, values) { var index = -1, @@ -5202,9 +5283,9 @@ * return greeting + ' ' + this.name; * }; * - * func = _.bind(func, { 'name': 'moe' }, 'hi'); + * func = _.bind(func, { 'name': 'fred' }, 'hi'); * func(); - * // => 'hi moe' + * // => 'hi fred' */ function bind(func, thisArg) { return arguments.length > 2 @@ -5265,7 +5346,7 @@ * @example * * var object = { - * 'name': 'moe', + * 'name': 'fred', * 'greet': function(greeting) { * return greeting + ' ' + this.name; * } @@ -5273,14 +5354,14 @@ * * var func = _.bindKey(object, 'greet', 'hi'); * func(); - * // => 'hi moe' + * // => 'hi fred' * * object.greet = function(greeting) { * return greeting + ', ' + this.name + '!'; * }; * * func(); - * // => 'hi, moe!' + * // => 'hi, fred!' */ function bindKey(object, key) { return arguments.length > 2 @@ -5302,7 +5383,7 @@ * @example * * var realNameMap = { - * 'curly': 'jerome' + * 'pebbles': 'jerome' * }; * * var format = function(name) { @@ -5315,7 +5396,7 @@ * }; * * var welcome = _.compose(greet, format); - * welcome('curly'); + * welcome('pebbles'); * // => 'Hiya Jerome!' */ function compose() { @@ -5353,9 +5434,9 @@ * @returns {Function} Returns a callback function. * @example * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * * // wrap to create custom callback shorthands @@ -5366,8 +5447,8 @@ * }; * }); * - * _.filter(stooges, 'age__gt45'); - * // => [{ 'name': 'larry', 'age': 50 }] + * _.filter(characters, 'age__gt38'); + * // => [{ 'name': 'fred', 'age': 40 }] */ function createCallback(func, thisArg, argCount) { var type = typeof func; @@ -5642,17 +5723,17 @@ * }); * * var data = { - * 'moe': { 'name': 'moe', 'age': 40 }, - * 'curly': { 'name': 'curly', 'age': 60 } + * 'fred': { 'name': 'fred', 'age': 40 }, + * 'pebbles': { 'name': 'pebbles', 'age': 60 } * }; * * // modifying the result cache * var stooge = _.memoize(function(name) { return data[name]; }, _.identity); - * stooge('curly'); - * // => { 'name': 'curly', 'age': 60 } + * stooge('pebbles'); + * // => { 'name': 'pebbles', 'age': 60 } * - * stooge.cache.curly.name = 'jerome'; - * stooge('curly'); + * stooge.cache.pebbles.name = 'jerome'; + * stooge('pebbles'); * // => { 'name': 'jerome', 'age': 60 } */ function memoize(func, resolver) { @@ -5723,8 +5804,8 @@ * * var greet = function(greeting, name) { return greeting + ' ' + name; }; * var hi = _.partial(greet, 'hi'); - * hi('moe'); - * // => 'hi moe' + * hi('fred'); + * // => 'hi fred' */ function partial(func) { return createBound(func, 16, nativeSlice.call(arguments, 1)); @@ -5828,10 +5909,10 @@ * * var hello = function(name) { return 'hello ' + name; }; * hello = _.wrap(hello, function(func) { - * return 'before, ' + func('moe') + ', after'; + * return 'before, ' + func('fred') + ', after'; * }); * hello(); - * // => 'before, hello moe, after' + * // => 'before, hello fred, after' */ function wrap(value, wrapper) { if (!isFunction(wrapper)) { @@ -5857,8 +5938,8 @@ * @returns {string} Returns the escaped string. * @example * - * _.escape('Moe, Larry & Curly'); - * // => 'Moe, Larry & Curly' + * _.escape('Fred, Wilma, & Pebbles'); + * // => 'Fred, Wilma, & Pebbles' */ function escape(string) { return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar); @@ -5874,8 +5955,8 @@ * @returns {*} Returns `value`. * @example * - * var moe = { 'name': 'moe' }; - * moe === _.identity(moe); + * var fred = { 'name': 'fred' }; + * fred === _.identity(fred); * // => true */ function identity(value) { @@ -5899,11 +5980,11 @@ * } * }); * - * _.capitalize('moe'); - * // => 'Moe' + * _.capitalize('fred'); + * // => 'Fred' * - * _('moe').capitalize(); - * // => 'Moe' + * _('fred').capitalize(); + * // => 'Fred' */ function mixin(object, source) { var ctor = object, @@ -6097,8 +6178,8 @@ * * // using the "interpolate" delimiter to create a compiled template * var compiled = _.template('hello <%= name %>'); - * compiled({ 'name': 'moe' }); - * // => 'hello moe' + * compiled({ 'name': 'fred' }); + * // => 'hello fred' * * // using the "escape" delimiter to escape HTML in data property values * _.template('<%- value %>', { 'value': '
+
- diff --git a/test/underscore.html b/test/underscore.html index 4d31aec1ed..67eb7d70ff 100644 --- a/test/underscore.html +++ b/test/underscore.html @@ -24,50 +24,103 @@