Socket
Socket
Sign inDemoInstall

underscore.string

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

underscore.string - npm Package Compare versions

Comparing version 1.1.6 to 2.0.0

test/test_underscore/vendor/jquery.js

27

dist/underscore.string.min.js

@@ -1,13 +0,14 @@

(function(k){if(typeof _()!="undefined")var o=_().reverse,p=_.include;var q=String.prototype.trim,l=function(a,b){for(var c=[];b>0;c[--b]=a);return c.join("")},d=function(a){return function(){for(var b=Array.prototype.slice.call(arguments),c=0;c<b.length;c++)b[c]=b[c]==null?"":""+b[c];return a.apply(null,b)}},m=function(){function a(a){return Object.prototype.toString.call(a).slice(8,-1).toLowerCase()}var b=function(){b.cache.hasOwnProperty(arguments[0])||(b.cache[arguments[0]]=b.parse(arguments[0]));
return b.format.call(null,b.cache[arguments[0]],arguments)};b.format=function(b,n){var d=1,e=b.length,f="",j=[],h,i,g,k;for(h=0;h<e;h++)if(f=a(b[h]),f==="string")j.push(b[h]);else if(f==="array"){g=b[h];if(g[2]){f=n[d];for(i=0;i<g[2].length;i++){if(!f.hasOwnProperty(g[2][i]))throw m('[_.sprintf] property "%s" does not exist',g[2][i]);f=f[g[2][i]]}}else f=g[1]?n[g[1]]:n[d++];if(/[^s]/.test(g[8])&&a(f)!="number")throw m("[_.sprintf] expecting number but found %s",a(f));switch(g[8]){case "b":f=f.toString(2);
break;case "c":f=String.fromCharCode(f);break;case "d":f=parseInt(f,10);break;case "e":f=g[7]?f.toExponential(g[7]):f.toExponential();break;case "f":f=g[7]?parseFloat(f).toFixed(g[7]):parseFloat(f);break;case "o":f=f.toString(8);break;case "s":f=(f=String(f))&&g[7]?f.substring(0,g[7]):f;break;case "u":f=Math.abs(f);break;case "x":f=f.toString(16);break;case "X":f=f.toString(16).toUpperCase()}f=/[def]/.test(g[8])&&g[3]&&f>=0?"+"+f:f;i=g[4]?g[4]=="0"?"0":g[4].charAt(1):" ";k=g[6]-String(f).length;i=
g[6]?l(i,k):"";j.push(g[5]?f+i:i+f)}return j.join("")};b.cache={};b.parse=function(a){for(var b=[],d=[],e=0;a;){if((b=/^[^\x25]+/.exec(a))!==null)d.push(b[0]);else if((b=/^\x25{2}/.exec(a))!==null)d.push("%");else if((b=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(a))!==null){if(b[2]){e|=1;var f=[],j=b[2],h=[];if((h=/^([a-z_][a-z_\d]*)/i.exec(j))!==null)for(f.push(h[1]);(j=j.substring(h[0].length))!=="";)if((h=/^\.([a-z_][a-z_\d]*)/i.exec(j))!==null)f.push(h[1]);
else if((h=/^\[(\d+)\]/.exec(j))!==null)f.push(h[1]);else throw"[_.sprintf] huh?";else throw"[_.sprintf] huh?";b[2]=f}else e|=2;if(e===3)throw"[_.sprintf] mixing positional and named placeholders is not (yet) supported";d.push(b)}else throw"[_.sprintf] huh?";a=a.substring(b[0].length)}return d};return b}(),e={isBlank:d(function(a){return/^\s*$/.test(a)}),stripTags:d(function(a){return a.replace(/<\/?[^>]+>/ig,"")}),capitalize:d(function(a){return a.charAt(0).toUpperCase()+a.substring(1).toLowerCase()}),
chop:d(function(a,b){for(var b=b*1||0||a.length,c=[],d=0;d<a.length;)c.push(a.slice(d,d+b)),d+=b;return c}),clean:d(function(a){return e.strip(a.replace(/\s+/g," "))}),count:d(function(a,b){for(var c=0,d,e=0;e<a.length;)d=a.indexOf(b,e),d>=0&&c++,e=e+(d>=0?d:0)+b.length;return c}),chars:d(function(a){return a.split("")}),escapeHTML:d(function(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}),unescapeHTML:d(function(a){return a.replace(/&lt;/g,
"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&amp;/g,"&")}),escapeRegExp:d(function(a){return a.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1")}),insert:d(function(a,b,c){a=a.split("");a.splice(b*1||0,0,c);return a.join("")}),includes:d(function(a,b){return a.indexOf(b)!==-1}),include:function(a,b){return!p||/string|number/.test(typeof a)?this.includes(a,b):p(a,b)},join:d(function(a){var b=Array.prototype.slice.call(arguments);return b.join(b.shift())}),lines:d(function(a){return a.split("\n")}),
reverse:function(a){return!o||/string|number/.test(typeof a)?Array.prototype.reverse.apply(String(a).split("")).join(""):o.call(_(a))},splice:d(function(a,b,c,d){a=a.split("");a.splice(b*1||0,c*1||0,d);return a.join("")}),startsWith:d(function(a,b){return a.length>=b.length&&a.substring(0,b.length)===b}),endsWith:d(function(a,b){return a.length>=b.length&&a.substring(a.length-b.length)===b}),succ:d(function(a){var b=a.split("");b.splice(a.length-1,1,String.fromCharCode(a.charCodeAt(a.length-1)+1));
return b.join("")}),titleize:d(function(a){for(var a=a.split(" "),b,c=0;c<a.length;c++)b=a[c].split(""),typeof b[0]!=="undefined"&&(b[0]=b[0].toUpperCase()),c+1===a.length?a[c]=b.join(""):a[c]=b.join("")+" ";return a.join("")}),camelize:d(function(a){return e.trim(a).replace(/(\-|_|\s)+(.)?/g,function(a,c,d){return d?d.toUpperCase():""})}),underscored:function(a){return e.trim(a).replace(/([a-z\d])([A-Z]+)/g,"$1_$2").replace(/\-|\s+/g,"_").toLowerCase()},dasherize:function(a){return e.trim(a).replace(/([a-z\d])([A-Z]+)/g,
"$1-$2").replace(/^([A-Z]+)/,"-$1").replace(/\_|\s+/g,"-").toLowerCase()},trim:d(function(a,b){if(!b&&q)return q.call(a);b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("^["+b+"]+|["+b+"]+$","g"),"")}),ltrim:d(function(a,b){b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("^["+b+"]+","g"),"")}),rtrim:d(function(a,b){b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("["+b+"]+$","g"),"")}),truncate:d(function(a,b,c){b=b*1||0;return a.length>b?a.slice(0,b)+(c||"..."):a}),words:function(a,b){return String(a).split(b||
" ")},pad:d(function(a,b,c,d){var e="",e=0,b=b*1||0;c?c.length>1&&(c=c.charAt(0)):c=" ";switch(d){case "right":e=b-a.length;e=l(c,e);a+=e;break;case "both":e=b-a.length;e={left:l(c,Math.ceil(e/2)),right:l(c,Math.floor(e/2))};a=e.left+a+e.right;break;default:e=b-a.length,e=l(c,e),a=e+a}return a}),lpad:function(a,b,c){return e.pad(a,b,c)},rpad:function(a,b,c){return e.pad(a,b,c,"right")},lrpad:function(a,b,c){return e.pad(a,b,c,"both")},sprintf:m,vsprintf:function(a,b){b.unshift(a);return m.apply(null,
b)},toNumber:function(a,b){var c;c=(a*1||0).toFixed(b*1||0)*1||0;return!(c===0&&a!=="0"&&a!==0)?c:Number.NaN},strRight:d(function(a,b){var c=!b?-1:a.indexOf(b);return c!=-1?a.slice(c+b.length,a.length):a}),strRightBack:d(function(a,b){var c=!b?-1:a.lastIndexOf(b);return c!=-1?a.slice(c+b.length,a.length):a}),strLeft:d(function(a,b){var c=!b?-1:a.indexOf(b);return c!=-1?a.slice(0,c):a}),strLeftBack:d(function(a,b){var c=a.lastIndexOf(b);return c!=-1?a.slice(0,c):a})};e.strip=e.trim;e.lstrip=e.ltrim;
e.rstrip=e.rtrim;e.center=e.lrpad;e.ljust=e.lpad;e.rjust=e.rpad;typeof module!=="undefined"&&module.exports?module.exports=e:typeof k._!=="undefined"?k._.mixin(e):k._=e})(this||window);
(function(k){var o=String.prototype.trim,l=function(a,b){for(var c=[];b>0;c[--b]=a);return c.join("")},d=function(a){return function(){for(var b=Array.prototype.slice.call(arguments),c=0;c<b.length;c++)b[c]=b[c]==null?"":""+b[c];return a.apply(null,b)}},m=function(){function a(a){return Object.prototype.toString.call(a).slice(8,-1).toLowerCase()}var b=function(){b.cache.hasOwnProperty(arguments[0])||(b.cache[arguments[0]]=b.parse(arguments[0]));return b.format.call(null,b.cache[arguments[0]],arguments)};
b.format=function(b,n){var e=1,d=b.length,f="",j=[],h,i,g,k;for(h=0;h<d;h++)if(f=a(b[h]),f==="string")j.push(b[h]);else if(f==="array"){g=b[h];if(g[2]){f=n[e];for(i=0;i<g[2].length;i++){if(!f.hasOwnProperty(g[2][i]))throw m('[_.sprintf] property "%s" does not exist',g[2][i]);f=f[g[2][i]]}}else f=g[1]?n[g[1]]:n[e++];if(/[^s]/.test(g[8])&&a(f)!="number")throw m("[_.sprintf] expecting number but found %s",a(f));switch(g[8]){case "b":f=f.toString(2);break;case "c":f=String.fromCharCode(f);break;case "d":f=
parseInt(f,10);break;case "e":f=g[7]?f.toExponential(g[7]):f.toExponential();break;case "f":f=g[7]?parseFloat(f).toFixed(g[7]):parseFloat(f);break;case "o":f=f.toString(8);break;case "s":f=(f=String(f))&&g[7]?f.substring(0,g[7]):f;break;case "u":f=Math.abs(f);break;case "x":f=f.toString(16);break;case "X":f=f.toString(16).toUpperCase()}f=/[def]/.test(g[8])&&g[3]&&f>=0?"+"+f:f;i=g[4]?g[4]=="0"?"0":g[4].charAt(1):" ";k=g[6]-String(f).length;i=g[6]?l(i,k):"";j.push(g[5]?f+i:i+f)}return j.join("")};b.cache=
{};b.parse=function(a){for(var b=[],e=[],d=0;a;){if((b=/^[^\x25]+/.exec(a))!==null)e.push(b[0]);else if((b=/^\x25{2}/.exec(a))!==null)e.push("%");else if((b=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(a))!==null){if(b[2]){d|=1;var f=[],j=b[2],h=[];if((h=/^([a-z_][a-z_\d]*)/i.exec(j))!==null)for(f.push(h[1]);(j=j.substring(h[0].length))!=="";)if((h=/^\.([a-z_][a-z_\d]*)/i.exec(j))!==null)f.push(h[1]);else if((h=/^\[(\d+)\]/.exec(j))!==null)f.push(h[1]);
else throw"[_.sprintf] huh?";else throw"[_.sprintf] huh?";b[2]=f}else d|=2;if(d===3)throw"[_.sprintf] mixing positional and named placeholders is not (yet) supported";e.push(b)}else throw"[_.sprintf] huh?";a=a.substring(b[0].length)}return e};return b}(),e={VERSION:"1.2.0",isBlank:d(function(a){return/^\s*$/.test(a)}),stripTags:d(function(a){return a.replace(/<\/?[^>]+>/ig,"")}),capitalize:d(function(a){return a.charAt(0).toUpperCase()+a.substring(1).toLowerCase()}),chop:d(function(a,b){for(var b=
b*1||0||a.length,c=[],e=0;e<a.length;)c.push(a.slice(e,e+b)),e+=b;return c}),clean:d(function(a){return e.strip(a.replace(/\s+/g," "))}),count:d(function(a,b){for(var c=0,e,d=0;d<a.length;)e=a.indexOf(b,d),e>=0&&c++,d=d+(e>=0?e:0)+b.length;return c}),chars:d(function(a){return a.split("")}),escapeHTML:d(function(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}),unescapeHTML:d(function(a){return a.replace(/&lt;/g,"<").replace(/&gt;/g,
">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&amp;/g,"&")}),escapeRegExp:d(function(a){return a.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1")}),insert:d(function(a,b,c){a=a.split("");a.splice(b*1||0,0,c);return a.join("")}),include:d(function(a,b){return a.indexOf(b)!==-1}),join:d(function(a){var b=Array.prototype.slice.call(arguments);return b.join(b.shift())}),lines:d(function(a){return a.split("\n")}),reverse:d(function(a){return Array.prototype.reverse.apply(String(a).split("")).join("")}),
splice:d(function(a,b,c,e){a=a.split("");a.splice(b*1||0,c*1||0,e);return a.join("")}),startsWith:d(function(a,b){return a.length>=b.length&&a.substring(0,b.length)===b}),endsWith:d(function(a,b){return a.length>=b.length&&a.substring(a.length-b.length)===b}),succ:d(function(a){var b=a.split("");b.splice(a.length-1,1,String.fromCharCode(a.charCodeAt(a.length-1)+1));return b.join("")}),titleize:d(function(a){for(var a=a.split(" "),b,c=0;c<a.length;c++)b=a[c].split(""),typeof b[0]!=="undefined"&&(b[0]=
b[0].toUpperCase()),c+1===a.length?a[c]=b.join(""):a[c]=b.join("")+" ";return a.join("")}),camelize:d(function(a){return e.trim(a).replace(/(\-|_|\s)+(.)?/g,function(a,c,e){return e?e.toUpperCase():""})}),underscored:function(a){return e.trim(a).replace(/([a-z\d])([A-Z]+)/g,"$1_$2").replace(/\-|\s+/g,"_").toLowerCase()},dasherize:function(a){return e.trim(a).replace(/([a-z\d])([A-Z]+)/g,"$1-$2").replace(/^([A-Z]+)/,"-$1").replace(/\_|\s+/g,"-").toLowerCase()},humanize:function(a){return e.capitalize(this.underscored(a).replace(/_id$/,
"").replace(/_/g," "))},trim:d(function(a,b){if(!b&&o)return o.call(a);b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("^["+b+"]+|["+b+"]+$","g"),"")}),ltrim:d(function(a,b){b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("^["+b+"]+","g"),"")}),rtrim:d(function(a,b){b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("["+b+"]+$","g"),"")}),truncate:d(function(a,b,c){b=b*1||0;return a.length>b?a.slice(0,b)+(c||"..."):a}),prune:d(function(a,b,c){var c=c||"...",b=b*1||0,d="",d=a.substring(b-
1,b+1).search(/^\w\w$/)===0?e.rtrim(a.slice(0,b).replace(/([\W][\w]*)$/,"")):e.rtrim(a.slice(0,b)),d=d.replace(/\W+$/,"");return d.length+c.length>a.length?a:d+c}),words:function(a,b){return String(a).split(b||" ")},pad:d(function(a,b,c,e){var d="",d=0,b=b*1||0;c?c.length>1&&(c=c.charAt(0)):c=" ";switch(e){case "right":d=b-a.length;d=l(c,d);a+=d;break;case "both":d=b-a.length;d={left:l(c,Math.ceil(d/2)),right:l(c,Math.floor(d/2))};a=d.left+a+d.right;break;default:d=b-a.length,d=l(c,d),a=d+a}return a}),
lpad:function(a,b,c){return e.pad(a,b,c)},rpad:function(a,b,c){return e.pad(a,b,c,"right")},lrpad:function(a,b,c){return e.pad(a,b,c,"both")},sprintf:m,vsprintf:function(a,b){b.unshift(a);return m.apply(null,b)},toNumber:function(a,b){var c;c=(a*1||0).toFixed(b*1||0)*1||0;return!(c===0&&a!=="0"&&a!==0)?c:Number.NaN},strRight:d(function(a,b){var c=!b?-1:a.indexOf(b);return c!=-1?a.slice(c+b.length,a.length):a}),strRightBack:d(function(a,b){var c=!b?-1:a.lastIndexOf(b);return c!=-1?a.slice(c+b.length,
a.length):a}),strLeft:d(function(a,b){var c=!b?-1:a.indexOf(b);return c!=-1?a.slice(0,c):a}),strLeftBack:d(function(a,b){var c=a.lastIndexOf(b);return c!=-1?a.slice(0,c):a}),exports:function(){var a={},b;for(b in this)if(this.hasOwnProperty(b)&&!(b=="include"||b=="contains"||b=="reverse"))a[b]=this[b];return a}};e.strip=e.trim;e.lstrip=e.ltrim;e.rstrip=e.rtrim;e.center=e.lrpad;e.ljust=e.lpad;e.rjust=e.rpad;e.contains=e.include;if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)module.exports=
e;exports._s=e}else typeof k._!=="undefined"?(k._.string=e,k._.str=k._.string):k._={string:e,str:e}})(this||window);
// Underscore.string
// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
// Underscore.strings is freely distributable under the terms of the MIT license.
// Documentation: https://github.com/edtsech/underscore.string
// Documentation: https://github.com/epeli/underscore.string
// Some code is borrowed from MooTools and Alexandru Marasteanu.
// Version 1.1.6
// Version 2.0.0
(function(root){
'use strict';
if (typeof _ != 'undefined') {
var _reverse = _().reverse,
_include = _.include;
}
// Defining helper functions.

@@ -25,3 +19,3 @@

var strRepeat = function(i, m) {
for (var o = []; m > 0; o[--m] = i);
for (var o = []; m > 0; o[--m] = i) {}
return o.join('');

@@ -177,2 +171,4 @@ };

var _s = {
VERSION: '2.0.0',

@@ -240,14 +236,6 @@ isBlank: sArgs(function(str){

includes: sArgs(function(str, needle){
include: sArgs(function(str, needle){
return str.indexOf(needle) !== -1;
}),
include: function(obj, needle) {
if (!_include || (/string|number/).test(typeof obj)) {
return this.includes(obj, needle);
} else {
return _include(obj, needle);
}
},
join: sArgs(function(sep) {

@@ -262,9 +250,5 @@ var args = slice(arguments);

reverse: function(obj){
if (!_reverse || (/string|number/).test(typeof obj)) {
return Array.prototype.reverse.apply(String(obj).split('')).join('');
} else {
return _reverse.call(_(obj));
}
},
reverse: sArgs(function(str){
return Array.prototype.reverse.apply(String(str).split('')).join('');
}),

@@ -316,2 +300,6 @@ splice: sArgs(function(str, i, howmany, substr){

humanize: function(str){
return _s.capitalize(this.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
},
trim: sArgs(function(str, characters){

@@ -341,2 +329,35 @@ if (!characters && nativeTrim) {

/**
* _s.prune: a more elegant version of truncate
* prune extra chars, never leaving a half-chopped word.
* @author github.com/sergiokas
*/
prune: sArgs(function(str, length, pruneStr){
// Function to check word/digit chars including non-ASCII encodings.
var isWordChar = function(c) { return ((c.toUpperCase() != c.toLowerCase()) || /[-_\d]/.test(c)); }
var template = '';
var pruned = '';
var i = 0;
// Set default values
pruneStr = pruneStr || '...';
length = parseNumber(length);
// Convert to an ASCII string to avoid problems with unicode chars.
for (i in str) {
template += (isWordChar(str[i]))?'A':' ';
}
// Check if we're in the middle of a word
if( template.substring(length-1, length+1).search(/^\w\w$/) === 0 )
pruned = _s.rtrim(template.slice(0,length).replace(/([\W][\w]*)$/,''));
else
pruned = _s.rtrim(template.slice(0,length));
pruned = pruned.replace(/\W+$/,'');
return (pruned.length+pruneStr.length>str.length) ? str : str.substring(0, pruned.length)+pruneStr;
}),
words: function(str, delimiter) {

@@ -418,4 +439,15 @@ return String(str).split(delimiter || " ");

return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr;
})
}),
exports: function() {
var result = {};
for (var prop in this) {
if (!this.hasOwnProperty(prop) || prop == 'include' || prop == 'contains' || prop == 'reverse') continue;
result[prop] = this[prop];
}
return result;
}
};

@@ -425,23 +457,32 @@

_s.strip = _s.trim;
_s.lstrip = _s.ltrim;
_s.rstrip = _s.rtrim;
_s.center = _s.lrpad;
_s.ljust = _s.lpad;
_s.rjust = _s.rpad;
_s.strip = _s.trim;
_s.lstrip = _s.ltrim;
_s.rstrip = _s.rtrim;
_s.center = _s.lrpad;
_s.ljust = _s.lpad;
_s.rjust = _s.rpad;
_s.contains = _s.include;
// CommonJS module is defined
if (typeof module !== 'undefined' && module.exports) {
// Export module
module.exports = _s;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
// Export module
module.exports = _s;
}
exports._s = _s;
// Integrate with Underscore.js
} else if (typeof root._ !== 'undefined') {
root._.mixin(_s);
// root._.mixin(_s);
root._.string = _s;
root._.str = root._.string;
// Or define it
} else {
root._ = _s;
root._ = {
string: _s,
str: _s
};
}
}(this || window));
{
"name": "underscore.string",
"version": "1.1.6",
"version": "2.0.0",
"description": "String manipulation extensions for Underscore.js javascript library.",
"homepage": "https://github.com/edtsech/underscore.string",
"homepage": "http://epeli.github.com/underscore.string/",
"contributors": [

@@ -27,11 +27,9 @@ "Esa-Matti Suuronen <esa-matti@suuronen.org> (http://esa-matti.suuronen.org/)",

},
"dependencies": {
"underscore": "1.1.7"
},
"dependencies": [],
"repository": {
"type": "git",
"url": "https://github.com/edtsech/underscore.string.git"
"url": "https://github.com/epeli/underscore.string.git"
},
"bugs": {
"url": "https://github.com/edtsech/underscore.string/issues"
"url": "https://github.com/epeli/underscore.string/issues"
},

@@ -38,0 +36,0 @@ "licenses" : [

@@ -70,2 +70,6 @@ (function() {

JSLitmus.test('prune', function(){
return _('Hello world').prune(5);
});
JSLitmus.test('isBlank', function(){

@@ -72,0 +76,0 @@ return _('').isBlank();

@@ -10,4 +10,4 @@ $(document).ready(function() {

test("provides standalone functions", function() {
equals(typeof _.trim, "function");
equals(typeof _.str.trim, "function");
});
});
$(document).ready(function() {
// Include Underscore.string methods to Underscore namespace
_.mixin(_.str.exports());
module("String extensions");

@@ -69,8 +72,8 @@

test("Strings: reverse", function() {
equals(_.reverse("foo"), "oof" );
equals(_.reverse("foobar"), "raboof" );
equals(_.reverse("foo bar"), "rab oof" );
equals(_.reverse("saippuakauppias"), "saippuakauppias" );
equals(_.reverse(123), "321", "Non string");
equals(_.reverse(123.45), "54.321", "Non string");
equals(_.str.reverse("foo"), "oof" );
equals(_.str.reverse("foobar"), "raboof" );
equals(_.str.reverse("foo bar"), "rab oof" );
equals(_.str.reverse("saippuakauppias"), "saippuakauppias" );
equals(_.str.reverse(123), "321", "Non string");
equals(_.str.reverse(123.45), "54.321", "Non string");
});

@@ -123,7 +126,6 @@

test("Strings: include", function() {
ok(_.include("foobar", "bar"), 'foobar includes bar');
ok(!_("foobar").include("buzz"), 'foobar does not includes buzz');
ok(_(12345).include(34), '12345 includes 34');
ok(!_(12345).include(6), '12345 does not includes 6');
ok(!_(12345).chain().include(6).value(), '12345 does not includes 6');
ok(_.str.include("foobar", "bar"), 'foobar includes bar');
ok(!_.str.include("foobar", "buzz"), 'foobar does not includes buzz');
ok(_.str.include(12345, 34), '12345 includes 34');
ok(!_.str.contains(12345, 6), '12345 does not includes 6');
});

@@ -196,2 +198,12 @@

test('String: humanize', function(){
equals(_('the_humanize_string_method').humanize(), 'The humanize string method');
equals(_('ThehumanizeStringMethod').humanize(), 'Thehumanize string method');
equals(_('the humanize string method').humanize(), 'The humanize string method');
equals(_('the humanize_id string method_id').humanize(), 'The humanize id string method');
equals(_('the humanize string method ').humanize(), 'The humanize string method');
equals(_(' capitalize dash-CamelCase_underscore trim ').humanize(), 'Capitalize dash camel case underscore trim');
equals(_(123).humanize(), '123');
});
test('String: truncate', function(){

@@ -204,2 +216,11 @@ equals(_('Hello world').truncate(6, 'read more'), 'Hello read more');

test('String: prune', function(){
equals(_('Hello, cruel world').prune(6, ' read more'), 'Hello read more');
equals(_('Hello, world').prune(5, 'read a lot more'), 'Hello, world');
equals(_('Hello, world').prune(5), 'Hello...');
equals(_('Hello, world').prune(8), 'Hello...');
equals(_('Hello, cruel world').prune(15), 'Hello, cruel...');
equals(_('Hello world').prune(22), 'Hello world');
});
test('String: isBlank', function(){

@@ -206,0 +227,0 @@ ok(_('').isBlank());

$(document).ready(function() {
module("Array-only functions (last, compact, uniq, and so on...)");
module("Arrays");

@@ -27,6 +27,19 @@ test("arrays: first", function() {

test("arrays: initial", function() {
equals(_.initial([1,2,3,4,5]).join(", "), "1, 2, 3, 4", 'working initial()');
equals(_.initial([1,2,3,4],2).join(", "), "1, 2", 'initial can take an index');
var result = (function(){ return _(arguments).initial(); })(1, 2, 3, 4);
equals(result.join(", "), "1, 2, 3", 'initial works on arguments object');
result = _.map([[1,2,3],[1,2,3]], _.initial);
equals(_.flatten(result).join(','), '1,2,1,2', 'initial works with _.map');
});
test("arrays: last", function() {
equals(_.last([1,2,3]), 3, 'can pull out the last element of an array');
equals(_.last([1,2,3], 0).join(', '), "", 'can pass an index to last');
equals(_.last([1,2,3], 2).join(', '), '2, 3', 'can pass an index to last');
var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4);
equals(result, 4, 'works on an arguments object');
result = _.map([[1,2,3],[1,2,3]], _.last);
equals(result.join(','), '3,3', 'works well with _.map');
});

@@ -41,6 +54,9 @@

test("arrays: flatten", function() {
var list = [1, [2], [3, [[[4]]]]];
equals(_.flatten(list).join(', '), '1, 2, 3, 4', 'can flatten nested arrays');
var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
equals(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
if (window.JSON) {
var list = [1, [2], [3, [[[4]]]]];
equals(JSON.stringify(_.flatten(list)), '[1,2,3,4]', 'can flatten nested arrays');
equals(JSON.stringify(_.flatten(list, true)), '[1,2,3,[[[4]]]]', 'can shallowly flatten nested arrays');
var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
equals(JSON.stringify(result), '[1,2,3,4]', 'works on an arguments object');
}
});

@@ -66,2 +82,10 @@

var list = [{name:'moe'}, {name:'curly'}, {name:'larry'}, {name:'curly'}];
var iterator = function(value) { return value.name; };
equals(_.map(_.uniq(list, false, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator');
var iterator = function(value) { return value +1; };
var list = [1, 2, 2, 3, 4, 4];
equals(_.uniq(list, true, iterator).join(', '), '1, 2, 3, 4', 'iterator works with sorted array');
var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);

@@ -71,10 +95,23 @@ equals(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');

test("arrays: intersect", function() {
test("arrays: intersection", function() {
var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
equals(_.intersect(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
equals(_(stooges).intersect(leaders).join(''), 'moe', 'can perform an OO-style intersection');
var result = (function(){ return _.intersect(arguments, leaders); })('moe', 'curly', 'larry');
equals(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
equals(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection');
var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry');
equals(result.join(''), 'moe', 'works on an arguments object');
});
test("arrays: union", function() {
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
equals(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]);
equals(result.join(' '), '1 2 3 30 40 1', 'takes the union of a list of nested arrays');
});
test("arrays: difference", function() {
var result = _.difference([1, 2, 3], [2, 30, 40]);
equals(result.join(' '), '1 3', 'takes the difference of two arrays');
});
test('arrays: zip', function() {

@@ -81,0 +118,0 @@ var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];

$(document).ready(function() {
module("Underscore chaining.");
module("Chaining");

@@ -5,0 +5,0 @@ test("chaining: map/flatten/reduce", function() {

$(document).ready(function() {
module("Collection functions (each, any, select, and so on...)");
module("Collections");

@@ -80,2 +80,9 @@ test("collections: each", function() {

ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
// Sparse arrays:
var sparseArray = [];
sparseArray[100] = 10;
sparseArray[200] = 20;
equals(_.reduce(sparseArray, function(a, b){ return a + b }), 30, 'initially-sparse arrays with no memo');
});

@@ -132,2 +139,4 @@

test('collections: any', function() {
var nativeSome = Array.prototype.some;
Array.prototype.some = null;
ok(!_.any([]), 'the empty set');

@@ -139,2 +148,3 @@ ok(!_.any([false, false, false]), 'all false values');

ok(_.some([false, false, true]), 'aliased as "some"');
Array.prototype.some = nativeSome;
});

@@ -173,2 +183,5 @@

equals(neg, 1, 'can perform a computation-based max');
equals(-Infinity, _.max({}), 'Maximum value of an empty object');
equals(-Infinity, _.max([]), 'Maximum value of an empty array');
});

@@ -181,2 +194,5 @@

equals(neg, 3, 'can perform a computation-based min');
equals(Infinity, _.min({}), 'Minimum value of an empty object');
equals(Infinity, _.min([]), 'Minimum value of an empty array');
});

@@ -194,2 +210,8 @@

equals(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
var grouped = _.groupBy(list, 'length');
equals(grouped['3'].join(' '), 'one two six ten');
equals(grouped['4'].join(' '), 'four five nine');
equals(grouped['5'].join(' '), 'three seven eight');
});

@@ -203,2 +225,9 @@

test('collections: shuffle', function() {
var numbers = _.range(10);
var shuffled = _.shuffle(numbers).sort();
notStrictEqual(numbers, shuffled, 'original object is unmodified');
equals(shuffled.join(','), numbers.join(','), 'contains the same members before and after shuffle');
});
test('collections: toArray', function() {

@@ -205,0 +234,0 @@ ok(!_.isArray(arguments), 'arguments object is not an array');

$(document).ready(function() {
module("Function functions (bind, bindAll, and so on...)");
module("Functions");

@@ -32,2 +32,9 @@ test("functions: bind", function() {

_.bind(func, false, false, 'can bind a function to `false`')();
// These tests are only meaningful when using a browser without a native bind function
// To test this with a modern browser, set underscore's nativeBind to undefined
var F = function () { return this; };
var Boundf = _.bind(F, {hello: "moe curly"});
equal(new Boundf().hello, undefined, "function should not be bound to the context, to comply with ECMAScript 5");
equal(Boundf().hello, "moe curly", "When called without the new operator, it's OK to be bound to the context");
});

@@ -87,3 +94,3 @@

asyncTest("functions: throttle", 1, function() {
asyncTest("functions: throttle", 2, function() {
var counter = 0;

@@ -93,9 +100,41 @@ var incr = function(){ counter++; };

throttledIncr(); throttledIncr(); throttledIncr();
setTimeout(throttledIncr, 70);
setTimeout(throttledIncr, 120);
setTimeout(throttledIncr, 140);
setTimeout(throttledIncr, 190);
setTimeout(throttledIncr, 220);
setTimeout(throttledIncr, 240);
_.delay(function(){ ok(counter == 3, "incr was throttled"); start(); }, 400);
_.delay(function(){ ok(counter == 1, "incr was called immediately"); }, 30);
_.delay(function(){ ok(counter == 4, "incr was throttled"); start(); }, 400);
});
asyncTest("functions: throttle arguments", 2, function() {
var value = 0;
var update = function(val){ value = val; };
var throttledUpdate = _.throttle(update, 100);
throttledUpdate(1); throttledUpdate(2); throttledUpdate(3);
setTimeout(function(){ throttledUpdate(4); }, 120);
setTimeout(function(){ throttledUpdate(5); }, 140);
setTimeout(function(){ throttledUpdate(6); }, 260);
setTimeout(function(){ throttledUpdate(7); }, 270);
_.delay(function(){ ok(value == 1, "updated to latest value"); }, 40);
_.delay(function(){ ok(value == 7, "updated to latest value"); start(); }, 400);
});
asyncTest("functions: throttle once", 1, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100);
throttledIncr();
_.delay(function(){ ok(counter == 1, "incr was called once"); start(); }, 220);
});
asyncTest("functions: throttle twice", 1, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100);
throttledIncr(); throttledIncr();
_.delay(function(){ ok(counter == 2, "incr was called twice"); start(); }, 220);
});
asyncTest("functions: debounce", 1, function() {

@@ -102,0 +141,0 @@ var counter = 0;

$(document).ready(function() {
module("Object functions (values, extend, isEqual, and so on...)");
module("Objects");

@@ -25,2 +25,6 @@ test("objects: keys", function() {

ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
var Animal = function(){};
Animal.prototype.run = function(){};
equals(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype');
});

@@ -66,22 +70,287 @@

equals(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original');
equals(_.clone(undefined), void 0, 'non objects should not be changed by clone');
equals(_.clone(1), 1, 'non objects should not be changed by clone');
equals(_.clone(null), null, 'non objects should not be changed by clone');
});
test("objects: isEqual", function() {
var moe = {name : 'moe', lucky : [13, 27, 34]};
var clone = {name : 'moe', lucky : [13, 27, 34]};
ok(moe != clone, 'basic equality between objects is false');
ok(_.isEqual(moe, clone), 'deep equality is true');
ok(_(moe).isEqual(clone), 'OO-style deep equality works');
ok(!_.isEqual(5, NaN), '5 is not equal to NaN');
ok(NaN != NaN, 'NaN is not equal to NaN (native equality)');
ok(NaN !== NaN, 'NaN is not equal to NaN (native identity)');
ok(!_.isEqual(NaN, NaN), 'NaN is not equal to NaN');
ok(_.isEqual(new Date(100), new Date(100)), 'identical dates are equal');
ok(_.isEqual((/hello/ig), (/hello/ig)), 'identical regexes are equal');
ok(!_.isEqual(null, [1]), 'a falsy is never equal to a truthy');
ok(_.isEqual({isEqual: function () { return true; }}, {}), 'first object implements `isEqual`');
ok(_.isEqual({}, {isEqual: function () { return true; }}), 'second object implements `isEqual`');
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), 'objects with the same number of undefined keys are not equal');
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'wrapped objects are not equal');
equals(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, 'wrapped objects are equal');
function First() {
this.value = 1;
}
First.prototype.value = 1;
function Second() {
this.value = 1;
}
Second.prototype.value = 2;
// Basic equality and identity comparisons.
ok(_.isEqual(null, null), "`null` is equal to `null`");
ok(_.isEqual(), "`undefined` is equal to `undefined`");
ok(!_.isEqual(0, -0), "`0` is not equal to `-0`");
ok(!_.isEqual(-0, 0), "Commutative equality is implemented for `0` and `-0`");
ok(!_.isEqual(null, undefined), "`null` is not equal to `undefined`");
ok(!_.isEqual(undefined, null), "Commutative equality is implemented for `null` and `undefined`");
// String object and primitive comparisons.
ok(_.isEqual("Curly", "Curly"), "Identical string primitives are equal");
ok(_.isEqual(new String("Curly"), new String("Curly")), "String objects with identical primitive values are equal");
ok(!_.isEqual("Curly", "Larry"), "String primitives with different values are not equal");
ok(!_.isEqual(new String("Curly"), "Curly"), "String primitives and their corresponding object wrappers are not equal");
ok(!_.isEqual("Curly", new String("Curly")), "Commutative equality is implemented for string objects and primitives");
ok(!_.isEqual(new String("Curly"), new String("Larry")), "String objects with different primitive values are not equal");
ok(!_.isEqual(new String("Curly"), {toString: function(){ return "Curly"; }}), "String objects and objects with a custom `toString` method are not equal");
// Number object and primitive comparisons.
ok(_.isEqual(75, 75), "Identical number primitives are equal");
ok(_.isEqual(new Number(75), new Number(75)), "Number objects with identical primitive values are equal");
ok(!_.isEqual(75, new Number(75)), "Number primitives and their corresponding object wrappers are not equal");
ok(!_.isEqual(new Number(75), 75), "Commutative equality is implemented for number objects and primitives");
ok(!_.isEqual(new Number(75), new Number(63)), "Number objects with different primitive values are not equal");
ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), "Number objects and objects with a `valueOf` method are not equal");
// Comparisons involving `NaN`.
ok(_.isEqual(NaN, NaN), "`NaN` is equal to `NaN`");
ok(!_.isEqual(61, NaN), "A number primitive is not equal to `NaN`");
ok(!_.isEqual(new Number(79), NaN), "A number object is not equal to `NaN`");
ok(!_.isEqual(Infinity, NaN), "`Infinity` is not equal to `NaN`");
// Boolean object and primitive comparisons.
ok(_.isEqual(true, true), "Identical boolean primitives are equal");
ok(_.isEqual(new Boolean, new Boolean), "Boolean objects with identical primitive values are equal");
ok(!_.isEqual(true, new Boolean(true)), "Boolean primitives and their corresponding object wrappers are not equal");
ok(!_.isEqual(new Boolean(true), true), "Commutative equality is implemented for booleans");
ok(!_.isEqual(new Boolean(true), new Boolean), "Boolean objects with different primitive values are not equal");
// Common type coercions.
ok(!_.isEqual(true, new Boolean(false)), "Boolean objects are not equal to the boolean primitive `true`");
ok(!_.isEqual("75", 75), "String and number primitives with like values are not equal");
ok(!_.isEqual(new Number(63), new String(63)), "String and number objects with like values are not equal");
ok(!_.isEqual(75, "75"), "Commutative equality is implemented for like string and number values");
ok(!_.isEqual(0, ""), "Number and string primitives with like values are not equal");
ok(!_.isEqual(1, true), "Number and boolean primitives with like values are not equal");
ok(!_.isEqual(new Boolean(false), new Number(0)), "Boolean and number objects with like values are not equal");
ok(!_.isEqual(false, new String("")), "Boolean primitives and string objects with like values are not equal");
ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), "Dates and their corresponding numeric primitive values are not equal");
// Dates.
ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), "Date objects referencing identical times are equal");
ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), "Date objects referencing different times are not equal");
ok(!_.isEqual(new Date(2009, 11, 13), {
getTime: function(){
return 12606876e5;
}
}), "Date objects and objects with a `getTime` method are not equal");
ok(!_.isEqual(new Date("Curly"), new Date("Curly")), "Invalid dates are not equal");
// Functions.
ok(!_.isEqual(First, Second), "Different functions with identical bodies and source code representations are not equal");
// RegExps.
ok(_.isEqual(/(?:)/gim, /(?:)/gim), "RegExps with equivalent patterns and flags are equal");
ok(!_.isEqual(/(?:)/g, /(?:)/gi), "RegExps with equivalent patterns and different flags are not equal");
ok(!_.isEqual(/Moe/gim, /Curly/gim), "RegExps with different patterns and equivalent flags are not equal");
ok(!_.isEqual(/(?:)/gi, /(?:)/g), "Commutative equality is implemented for RegExps");
ok(!_.isEqual(/Curly/g, {source: "Larry", global: true, ignoreCase: false, multiline: false}), "RegExps and RegExp-like objects are not equal");
// Empty arrays, array-like objects, and object literals.
ok(_.isEqual({}, {}), "Empty object literals are equal");
ok(_.isEqual([], []), "Empty array literals are equal");
ok(_.isEqual([{}], [{}]), "Empty nested arrays and objects are equal");
ok(!_.isEqual({length: 0}, []), "Array-like objects and arrays are not equal.");
ok(!_.isEqual([], {length: 0}), "Commutative equality is implemented for array-like objects");
ok(!_.isEqual({}, []), "Object literals and array literals are not equal");
ok(!_.isEqual([], {}), "Commutative equality is implemented for objects and arrays");
// Arrays with primitive and object values.
ok(_.isEqual([1, "Larry", true], [1, "Larry", true]), "Arrays containing identical primitives are equal");
ok(_.isEqual([/Moe/g, new Date(2009, 9, 25)], [/Moe/g, new Date(2009, 9, 25)]), "Arrays containing equivalent elements are equal");
// Multi-dimensional arrays.
var a = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
var b = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
ok(_.isEqual(a, b), "Arrays containing nested arrays and objects are recursively compared");
// Overwrite the methods defined in ES 5.1 section 15.4.4.
a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null;
b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null;
// Array elements and properties.
ok(!_.isEqual(a, b), "Arrays containing equivalent elements and different non-numeric properties are not equal");
a.push("White Rocks");
ok(!_.isEqual(a, b), "Arrays of different lengths are not equal");
a.push("East Boulder");
b.push("Gunbarrel Ranch", "Teller Farm");
ok(!_.isEqual(a, b), "Arrays of identical lengths containing different elements are not equal");
// Sparse arrays.
ok(_.isEqual(Array(3), Array(3)), "Sparse arrays of identical lengths are equal");
ok(!_.isEqual(Array(3), Array(6)), "Sparse arrays of different lengths are not equal when both are empty");
// According to the Microsoft deviations spec, section 2.1.26, JScript 5.x treats `undefined`
// elements in arrays as elisions. Thus, sparse arrays and dense arrays containing `undefined`
// values are equivalent.
if (0 in [undefined]) {
ok(!_.isEqual(Array(3), [undefined, undefined, undefined]), "Sparse and dense arrays are not equal");
ok(!_.isEqual([undefined, undefined, undefined], Array(3)), "Commutative equality is implemented for sparse and dense arrays");
}
// Simple objects.
ok(_.isEqual({a: "Curly", b: 1, c: true}, {a: "Curly", b: 1, c: true}), "Objects containing identical primitives are equal");
ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), "Objects containing equivalent members are equal");
ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), "Objects of identical sizes with different values are not equal");
ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), "Objects of identical sizes with different property names are not equal");
ok(!_.isEqual({a: 1, b: 2}, {a: 1}), "Objects of different sizes are not equal");
ok(!_.isEqual({a: 1}, {a: 1, b: 2}), "Commutative equality is implemented for objects");
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), "Objects with identical keys and different values are not equivalent");
// `A` contains nested objects and arrays.
a = {
name: new String("Moe Howard"),
age: new Number(77),
stooge: true,
hobbies: ["acting"],
film: {
name: "Sing a Song of Six Pants",
release: new Date(1947, 9, 30),
stars: [new String("Larry Fine"), "Shemp Howard"],
minutes: new Number(16),
seconds: 54
}
};
// `B` contains equivalent nested objects and arrays.
b = {
name: new String("Moe Howard"),
age: new Number(77),
stooge: true,
hobbies: ["acting"],
film: {
name: "Sing a Song of Six Pants",
release: new Date(1947, 9, 30),
stars: [new String("Larry Fine"), "Shemp Howard"],
minutes: new Number(16),
seconds: 54
}
};
ok(_.isEqual(a, b), "Objects with nested equivalent members are recursively compared");
// Instances.
ok(_.isEqual(new First, new First), "Object instances are equal");
ok(!_.isEqual(new First, new Second), "Objects with different constructors and identical own properties are not equal");
ok(!_.isEqual({value: 1}, new First), "Object instances and objects sharing equivalent properties are not identical");
ok(!_.isEqual({value: 2}, new Second), "The prototype chain of objects should not be examined");
// Circular Arrays.
(a = []).push(a);
(b = []).push(b);
ok(_.isEqual(a, b), "Arrays containing circular references are equal");
a.push(new String("Larry"));
b.push(new String("Larry"));
ok(_.isEqual(a, b), "Arrays containing circular references and equivalent properties are equal");
a.push("Shemp");
b.push("Curly");
ok(!_.isEqual(a, b), "Arrays containing circular references and different properties are not equal");
// Circular Objects.
a = {abc: null};
b = {abc: null};
a.abc = a;
b.abc = b;
ok(_.isEqual(a, b), "Objects containing circular references are equal");
a.def = 75;
b.def = 75;
ok(_.isEqual(a, b), "Objects containing circular references and equivalent properties are equal");
a.def = new Number(75);
b.def = new Number(63);
ok(!_.isEqual(a, b), "Objects containing circular references and different properties are not equal");
// Cyclic Structures.
a = [{abc: null}];
b = [{abc: null}];
(a[0].abc = a).push(a);
(b[0].abc = b).push(b);
ok(_.isEqual(a, b), "Cyclic structures are equal");
a[0].def = "Larry";
b[0].def = "Larry";
ok(_.isEqual(a, b), "Cyclic structures containing equivalent properties are equal");
a[0].def = new String("Larry");
b[0].def = new String("Curly");
ok(!_.isEqual(a, b), "Cyclic structures containing different properties are not equal");
// Complex Circular References.
a = {foo: {b: {foo: {c: {foo: null}}}}};
b = {foo: {b: {foo: {c: {foo: null}}}}};
a.foo.b.foo.c.foo = a;
b.foo.b.foo.c.foo = b;
ok(_.isEqual(a, b), "Cyclic structures with nested and identically-named properties are equal");
// Chaining.
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal');
equals(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, '`isEqual` can be chained');
// Custom `isEqual` methods.
var isEqualObj = {isEqual: function (o) { return o.isEqual == this.isEqual; }, unique: {}};
var isEqualObjClone = {isEqual: isEqualObj.isEqual, unique: {}};
ok(_.isEqual(isEqualObj, isEqualObjClone), 'Both objects implement identical `isEqual` methods');
ok(_.isEqual(isEqualObjClone, isEqualObj), 'Commutative equality is implemented for objects with custom `isEqual` methods');
ok(!_.isEqual(isEqualObj, {}), 'Objects that do not implement equivalent `isEqual` methods are not equal');
ok(!_.isEqual({}, isEqualObj), 'Commutative equality is implemented for objects with different `isEqual` methods');
// Custom `isEqual` methods - comparing different types
LocalizedString = (function() {
function LocalizedString(id) { this.id = id; this.string = (this.id===10)? 'Bonjour': ''; }
LocalizedString.prototype.isEqual = function(that) {
if (_.isString(that)) return this.string == that;
else if (that instanceof LocalizedString) return this.id == that.id;
return false;
};
return LocalizedString;
})();
var localized_string1 = new LocalizedString(10), localized_string2 = new LocalizedString(10), localized_string3 = new LocalizedString(11);
ok(_.isEqual(localized_string1, localized_string2), 'comparing same typed instances with same ids');
ok(!_.isEqual(localized_string1, localized_string3), 'comparing same typed instances with different ids');
ok(_.isEqual(localized_string1, 'Bonjour'), 'comparing different typed instances with same values');
ok(_.isEqual('Bonjour', localized_string1), 'comparing different typed instances with same values');
ok(!_.isEqual('Bonjour', localized_string3), 'comparing two localized strings with different ids');
ok(!_.isEqual(localized_string1, 'Au revoir'), 'comparing different typed instances with different values');
ok(!_.isEqual('Au revoir', localized_string1), 'comparing different typed instances with different values');
// Custom `isEqual` methods - comparing with serialized data
Date.prototype.toJSON = function() {
return {
_type:'Date',
year:this.getUTCFullYear(),
month:this.getUTCMonth(),
day:this.getUTCDate(),
hours:this.getUTCHours(),
minutes:this.getUTCMinutes(),
seconds:this.getUTCSeconds()
};
};
Date.prototype.isEqual = function(that) {
var this_date_components = this.toJSON();
var that_date_components = (that instanceof Date) ? that.toJSON() : that;
delete this_date_components['_type']; delete that_date_components['_type']
return _.isEqual(this_date_components, that_date_components);
};
var date = new Date();
var date_json = {
_type:'Date',
year:date.getUTCFullYear(),
month:date.getUTCMonth(),
day:date.getUTCDate(),
hours:date.getUTCHours(),
minutes:date.getUTCMinutes(),
seconds:date.getUTCSeconds()
};
ok(_.isEqual(date_json, date), 'serialized date matches date');
ok(_.isEqual(date, date_json), 'date matches serialized date');
});

@@ -114,4 +383,4 @@

parent.iArray = [1, 2, 3];\
parent.iString = 'hello';\
parent.iNumber = 100;\
parent.iString = new String('hello');\
parent.iNumber = new Number(100);\
parent.iFunction = (function(){});\

@@ -122,3 +391,3 @@ parent.iDate = new Date();\

parent.iNull = null;\
parent.iBoolean = false;\
parent.iBoolean = new Boolean(false);\
parent.iUndefined = undefined;\

@@ -177,5 +446,6 @@ </script>"

ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are');
ok(!_.isNumber(NaN), 'NaN is not a number');
ok(_.isNumber(NaN), 'NaN *is* a number');
ok(_.isNumber(Infinity), 'Infinity is a number');
ok(_.isNumber(iNumber), 'even from another frame');
ok(!_.isNumber('1'), 'numeric strings are not numbers');
});

@@ -185,3 +455,3 @@

ok(!_.isBoolean(2), 'a number is not a boolean');
ok(!_.isBoolean("string"), 'a string is not a boolean');
ok(!_.isBoolean("string"), 'a string is not a boolean');
ok(!_.isBoolean("false"), 'the string "false" is not a boolean');

@@ -188,0 +458,0 @@ ok(!_.isBoolean("true"), 'the string "true" is not a boolean');

$(document).ready(function() {
module("Utility functions (uniqueId, template)");
module("Utility");

@@ -44,2 +44,7 @@ test("utility: noConflict", function() {

test("utility: _.escape", function() {
equals(_.escape("Curly & Moe"), "Curly &amp; Moe");
equals(_.escape("Curly &amp; Moe"), "Curly &amp;amp; Moe");
});
test("utility: template", function() {

@@ -85,2 +90,6 @@ var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");

var template = _.template("<i><%- value %></i>");
var result = template({value: "<script>"});
equals(result, '<i>&lt;script&gt;</i>');
if (!$.browser.msie) {

@@ -87,0 +96,0 @@ var fromHTML = _.template($('#template').html());

@@ -1,2 +0,2 @@

// Underscore.js 1.1.7
// Underscore.js 1.2.1
// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.

@@ -51,8 +51,15 @@ // Underscore is freely distributable under the MIT license.

// Export the Underscore object for **CommonJS**, with backwards-compatibility
// for the old `require()` API. If we're not in CommonJS, add `_` to the
// global object.
if (typeof module !== 'undefined' && module.exports) {
module.exports = _;
_._ = _;
// Export the Underscore object for **Node.js** and **"CommonJS"**, with
// backwards-compatibility for the old `require()` API. If we're not in
// CommonJS, add `_` to the global object.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else if (typeof define === 'function' && define.amd) {
// Register as a named module with AMD.
define('underscore', function() {
return _;
});
} else {

@@ -64,3 +71,3 @@ // Exported as a string, for Closure Compiler "advanced" mode.

// Current version.
_.VERSION = '1.1.7';
_.VERSION = '1.2.1';

@@ -203,4 +210,4 @@ // Collection Functions

if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
any(obj, function(value) {
if (found = value === target) return true;
found = any(obj, function(value) {
return value === target;
});

@@ -226,2 +233,3 @@ return found;

if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
if (!iterator && _.isEmpty(obj)) return -Infinity;
var result = {computed : -Infinity};

@@ -238,2 +246,3 @@ each(obj, function(value, index, list) {

if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
if (!iterator && _.isEmpty(obj)) return Infinity;
var result = {computed : Infinity};

@@ -247,2 +256,17 @@ each(obj, function(value, index, list) {

// Shuffle an array.
_.shuffle = function(obj) {
var shuffled = [], rand;
each(obj, function(value, index, list) {
if (index == 0) {
shuffled[0] = value;
} else {
rand = Math.floor(Math.random() * (index + 1));
shuffled[index] = shuffled[rand];
shuffled[rand] = value;
}
});
return shuffled;
};
// Sort the object's values by a criterion produced by an iterator.

@@ -261,5 +285,7 @@ _.sortBy = function(obj, iterator, context) {

// Groups the object's values by a criterion produced by an iterator
_.groupBy = function(obj, iterator) {
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = function(obj, val) {
var result = {};
var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
each(obj, function(value, index) {

@@ -308,2 +334,16 @@ var key = iterator(value, index);

// Returns everything but the last entry of the array. Especcialy useful on
// the arguments object. Passing **n** will return all the values in
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
_.initial = function(array, n, guard) {
return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) {
return (n != null) && !guard ? slice.call(array, array.length - n) : array[array.length - 1];
};
// Returns everything but the first entry of the array. Aliased as `tail`.

@@ -317,7 +357,2 @@ // Especially useful on the arguments object. Passing an **index** will return

// Get the last element of an array.
_.last = function(array) {
return array[array.length - 1];
};
// Trim out all falsy values from an array.

@@ -329,5 +364,5 @@ _.compact = function(array) {

// Return a completely flattened version of an array.
_.flatten = function(array) {
_.flatten = function(array, shallow) {
return _.reduce(array, function(memo, value) {
if (_.isArray(value)) return memo.concat(_.flatten(value));
if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
memo[memo.length] = value;

@@ -346,7 +381,13 @@ return memo;

// Aliased as `unique`.
_.uniq = _.unique = function(array, isSorted) {
return _.reduce(array, function(memo, el, i) {
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
_.uniq = _.unique = function(array, isSorted, iterator) {
var initial = iterator ? _.map(array, iterator) : array;
var result = [];
_.reduce(initial, function(memo, el, i) {
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
memo[memo.length] = el;
result[result.length] = array[i];
}
return memo;
}, []);
return result;
};

@@ -357,3 +398,3 @@

_.union = function() {
return _.uniq(_.flatten(arguments));
return _.uniq(_.flatten(arguments, true));
};

@@ -406,3 +447,2 @@

// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.

@@ -442,2 +482,5 @@ _.lastIndexOf = function(array, item) {

// Reusable constructor function for prototype setting.
var ctor = function(){};
// Create a function bound to a given object (assigning `this`, and arguments,

@@ -447,7 +490,14 @@ // optionally). Binding with arguments is also known as `curry`.

// We check for `func.bind` first, to fail fast when `func` is undefined.
_.bind = function(func, obj) {
_.bind = function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};

@@ -488,22 +538,25 @@ };

// Internal function used to implement `_.throttle` and `_.debounce`.
var limit = function(func, wait, debounce) {
var timeout;
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time.
_.throttle = function(func, wait) {
var context, args, timeout, throttling, more;
var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
return function() {
var context = this, args = arguments;
var throttler = function() {
context = this; args = arguments;
var later = function() {
timeout = null;
if (more) func.apply(context, args);
whenDone();
};
if (!timeout) timeout = setTimeout(later, wait);
if (throttling) {
more = true;
} else {
func.apply(context, args);
};
if (debounce) clearTimeout(timeout);
if (debounce || !timeout) timeout = setTimeout(throttler, wait);
}
whenDone();
throttling = true;
};
};
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time.
_.throttle = function(func, wait) {
return limit(func, wait, false);
};
// Returns a function, that, as long as it continues to be invoked, will not

@@ -513,3 +566,12 @@ // be triggered. The function will be called after it stops being called for

_.debounce = function(func, wait) {
return limit(func, wait, true);
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};

@@ -558,3 +620,2 @@

// Object Functions

@@ -609,2 +670,3 @@ // ----------------

_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);

@@ -621,43 +683,89 @@ };

// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
// Check object identity.
if (a === b) return true;
// Different types?
var atype = typeof(a), btype = typeof(b);
if (atype != btype) return false;
// Basic equality test (watch out for coercions).
if (a == b) return true;
// One is falsy and the other truthy.
if ((!a && b) || (a && !b)) return false;
// Internal recursive comparison function.
function eq(a, b, stack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
if (a === b) return a !== 0 || 1 / a == 1 / b;
// A strict comparison is necessary because `null == undefined`.
if ((a == null) || (b == null)) return a === b;
// Unwrap any wrapped objects.
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
// One of them implements an isEqual()?
if (a.isEqual) return a.isEqual(b);
if (b.isEqual) return b.isEqual(a);
// Check dates' integer values.
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
// Both are NaN?
if (_.isNaN(a) && _.isNaN(b)) return false;
// Compare regular expressions.
if (_.isRegExp(a) && _.isRegExp(b))
return a.source === b.source &&
a.global === b.global &&
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline;
// If a is not an object by this point, we can't handle it.
if (atype !== 'object') return false;
// Check for different array lengths before comparing contents.
if (a.length && (a.length !== b.length)) return false;
// Nothing else worked, deep compare the contents.
var aKeys = _.keys(a), bKeys = _.keys(b);
// Different object sizes?
if (aKeys.length != bKeys.length) return false;
// Recursive comparison of contents.
for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
return true;
// Invoke a custom `isEqual` method if one is provided.
if (_.isFunction(a.isEqual)) return a.isEqual(b);
if (_.isFunction(b.isEqual)) return b.isEqual(a);
// Compare object types.
var typeA = typeof a;
if (typeA != typeof b) return false;
// Optimization; ensure that both values are truthy or falsy.
if (!a != !b) return false;
// `NaN` values are equal.
if (_.isNaN(a)) return _.isNaN(b);
// Compare string objects by value.
var isStringA = _.isString(a), isStringB = _.isString(b);
if (isStringA || isStringB) return isStringA && isStringB && String(a) == String(b);
// Compare number objects by value.
var isNumberA = _.isNumber(a), isNumberB = _.isNumber(b);
if (isNumberA || isNumberB) return isNumberA && isNumberB && +a == +b;
// Compare boolean objects by value. The value of `true` is 1; the value of `false` is 0.
var isBooleanA = _.isBoolean(a), isBooleanB = _.isBoolean(b);
if (isBooleanA || isBooleanB) return isBooleanA && isBooleanB && +a == +b;
// Compare dates by their millisecond values.
var isDateA = _.isDate(a), isDateB = _.isDate(b);
if (isDateA || isDateB) return isDateA && isDateB && a.getTime() == b.getTime();
// Compare RegExps by their source patterns and flags.
var isRegExpA = _.isRegExp(a), isRegExpB = _.isRegExp(b);
if (isRegExpA || isRegExpB) {
// Ensure commutative equality for RegExps.
return isRegExpA && isRegExpB &&
a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
}
// Ensure that both values are objects.
if (typeA != 'object') return false;
// Arrays or Arraylikes with different lengths are not equal.
if (a.length !== b.length) return false;
// Objects with different constructors are not equal.
if (a.constructor !== b.constructor) return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = stack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (stack[length] == a) return true;
}
// Add the first object to the stack of traversed objects.
stack.push(a);
var size = 0, result = true;
// Deep compare objects.
for (var key in a) {
if (hasOwnProperty.call(a, key)) {
// Count the expected number of properties.
size++;
// Deep compare each member.
if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break;
}
}
// Ensure that both objects contain the same number of properties.
if (result) {
for (key in b) {
if (hasOwnProperty.call(b, key) && !(size--)) break;
}
result = !size;
}
// Remove the first object from the stack of traversed objects.
stack.pop();
return result;
}
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
return eq(a, b, []);
};
// Is a given array or object empty?
// Is a given array, string, or object empty?
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {

@@ -677,3 +785,3 @@ if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;

_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]';
return toString.call(obj) == '[object Array]';
};

@@ -687,9 +795,15 @@

// Is a given variable an arguments object?
_.isArguments = function(obj) {
return !!(obj && hasOwnProperty.call(obj, 'callee'));
};
if (toString.call(arguments) == '[object Arguments]') {
_.isArguments = function(obj) {
return toString.call(obj) == '[object Arguments]';
};
} else {
_.isArguments = function(obj) {
return !!(obj && hasOwnProperty.call(obj, 'callee'));
};
}
// Is a given value a function?
_.isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
return toString.call(obj) == '[object Function]';
};

@@ -699,3 +813,3 @@

_.isString = function(obj) {
return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
return toString.call(obj) == '[object String]';
};

@@ -705,8 +819,8 @@

_.isNumber = function(obj) {
return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
return toString.call(obj) == '[object Number]';
};
// Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
// that does not equal itself.
// Is the given value `NaN`?
_.isNaN = function(obj) {
// `NaN` is the only value for which `===` is not reflexive.
return obj !== obj;

@@ -717,3 +831,3 @@ };

_.isBoolean = function(obj) {
return obj === true || obj === false;
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};

@@ -723,3 +837,3 @@

_.isDate = function(obj) {
return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
return toString.call(obj) == '[object Date]';
};

@@ -729,3 +843,3 @@

_.isRegExp = function(obj) {
return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
return toString.call(obj) == '[object RegExp]';
};

@@ -763,2 +877,7 @@

// Escape a string for HTML interpolation.
_.escape = function(string) {
return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
};
// Add your own custom functions to the Underscore object, ensuring that

@@ -784,3 +903,4 @@ // they're correctly added to the OOP wrapper as well.

evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};

@@ -797,2 +917,5 @@

.replace(/'/g, "\\'")
.replace(c.escape, function(match, code) {
return "',_.escape(" + code.replace(/\\'/g, "'") + "),'";
})
.replace(c.interpolate, function(match, code) {

@@ -809,4 +932,4 @@ return "'," + code.replace(/\\'/g, "'") + ",'";

+ "');}return __p.join('');";
var func = new Function('obj', tmpl);
return data ? func(data) : func;
var func = new Function('obj', '_', tmpl);
return data ? func(data, _) : function(data) { return func(data, _) };
};

@@ -870,2 +993,2 @@

})();
}).call(this);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc