diff --git a/Rakefile b/Rakefile index b9fd1ca46..45edbd923 100644 --- a/Rakefile +++ b/Rakefile @@ -1,11 +1,6 @@ -require 'rubygems' -require 'uglifier' - -desc "Use the Closure Compiler to compress Underscore.js" +desc "Use Uglify JS to compress Underscore.js" task :build do - source = File.read('underscore.js') - min = Uglifier.compile(source) - File.open('underscore-min.js', 'w') {|f| f.write min } + sh "uglifyjs underscore.js -c -m -o underscore-min.js" end desc "Build the docco documentation" diff --git a/docs/underscore.html b/docs/underscore.html index 1f4b86a94..384ab1000 100644 --- a/docs/underscore.html +++ b/docs/underscore.html @@ -1,11 +1,10 @@ - underscore.js

underscore.js

Underscore.js 1.4.2
+      underscore.js           

underscore.js

Underscore.js 1.4.3
 http://underscorejs.org
 (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
 Underscore may be freely distributed under the MIT license.
 
(function() {

Baseline setup

Establish the root object, window in the browser, or global on the server.

  var root = this;

Save the previous value of the _ variable.

  var previousUnderscore = root._;

Establish the object that gets returned to break out of a loop iteration.

  var breaker = {};

Save bytes in the minified (but not gzipped) version:

  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

Create quick reference variables for speed access to core prototypes.

  var push             = ArrayProto.push,
       slice            = ArrayProto.slice,
       concat           = ArrayProto.concat,
-      unshift          = ArrayProto.unshift,
       toString         = ObjProto.toString,
       hasOwnProperty   = ObjProto.hasOwnProperty;

All ECMAScript 5 native function implementations that we hope to use are declared here.

  var
@@ -33,8 +32,8 @@
     }
     exports._ = _;
   } else {
-    root['_'] = _;
-  }

Current version.

  _.VERSION = '1.4.2';

Collection Functions

The cornerstone, an each implementation, aka forEach. + root._ = _; + }

Current version.

  _.VERSION = '1.4.3';

Collection Functions

The cornerstone, an each implementation, aka forEach. Handles objects with the built-in forEach, arrays, and raw objects. Delegates to ECMAScript 5's native forEach if available.

  var each = _.each = _.forEach = function(obj, iterator, context) {
     if (obj == null) return;
@@ -60,7 +59,9 @@
       results[results.length] = iterator.call(context, value, index, list);
     });
     return results;
-  };

Reduce builds up a single result from a list of values, aka inject, + }; + + var reduceError = 'Reduce of empty array with no initial value';

Reduce builds up a single result from a list of values, aka inject, or foldl. Delegates to ECMAScript 5's native reduce if available.

  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
     var initial = arguments.length > 2;
     if (obj == null) obj = [];
@@ -76,7 +77,7 @@
         memo = iterator.call(context, memo, value, index, list);
       }
     });
-    if (!initial) throw new TypeError('Reduce of empty array with no initial value');
+    if (!initial) throw new TypeError(reduceError);
     return memo;
   };

The right-associative version of reduce, also known as foldr. Delegates to ECMAScript 5's native reduceRight if available.

  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
@@ -84,7 +85,7 @@
     if (obj == null) obj = [];
     if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
       if (context) iterator = _.bind(iterator, context);
-      return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
     }
     var length = obj.length;
     if (length !== +length) {
@@ -100,7 +101,7 @@
         memo = iterator.call(context, memo, obj[index], index, list);
       }
     });
-    if (!initial) throw new TypeError('Reduce of empty array with no initial value');
+    if (!initial) throw new TypeError(reduceError);
     return memo;
   };

Return the first value which passes a truth test. Aliased as detect.

  _.find = _.detect = function(obj, iterator, context) {
     var result;
@@ -122,12 +123,9 @@
     });
     return results;
   };

Return all the elements for which a truth test fails.

  _.reject = function(obj, iterator, context) {
-    var results = [];
-    if (obj == null) return results;
-    each(obj, function(value, index, list) {
-      if (!iterator.call(context, value, index, list)) results[results.length] = value;
-    });
-    return results;
+    return _.filter(obj, function(value, index, list) {
+      return !iterator.call(context, value, index, list);
+    }, context);
   };

Determine whether all of the elements match a truth test. Delegates to ECMAScript 5's native every if available. Aliased as all.

  _.every = _.all = function(obj, iterator, context) {
@@ -152,13 +150,11 @@
     return !!result;
   };

Determine if the array or object contains a given value (using ===). Aliased as include.

  _.contains = _.include = function(obj, target) {
-    var found = false;
-    if (obj == null) return found;
+    if (obj == null) return false;
     if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
-    found = any(obj, function(value) {
+    return any(obj, function(value) {
       return value === target;
     });
-    return found;
   };

Invoke a method (with arguments) on every item in a collection.

  _.invoke = function(obj, method) {
     var args = slice.call(arguments, 2);
     return _.map(obj, function(value) {
@@ -182,7 +178,7 @@
       return Math.max.apply(Math, obj);
     }
     if (!iterator && _.isEmpty(obj)) return -Infinity;
-    var result = {computed : -Infinity};
+    var result = {computed : -Infinity, value: -Infinity};
     each(obj, function(value, index, list) {
       var computed = iterator ? iterator.call(context, value, index, list) : value;
       computed >= result.computed && (result = {value : value, computed : computed});
@@ -193,7 +189,7 @@
       return Math.min.apply(Math, obj);
     }
     if (!iterator && _.isEmpty(obj)) return Infinity;
-    var result = {computed : Infinity};
+    var result = {computed : Infinity, value: Infinity};
     each(obj, function(value, index, list) {
       var computed = iterator ? iterator.call(context, value, index, list) : value;
       computed < result.computed && (result = {value : value, computed : computed});
@@ -230,7 +226,7 @@
     }), 'value');
   };

An internal function used for aggregate "group by" operations.

  var group = function(obj, value, context, behavior) {
     var result = {};
-    var iterator = lookupIterator(value);
+    var iterator = lookupIterator(value || _.identity);
     each(obj, function(value, index) {
       var key = iterator.call(context, value, index, obj);
       behavior(result, key, value);
@@ -244,7 +240,7 @@
   };

Counts instances of an object that group by a certain criterion. Pass either a string attribute to count by, or a function that returns the criterion.

  _.countBy = function(obj, value, context) {
-    return group(obj, value, context, function(result, key, value) {
+    return group(obj, value, context, function(result, key) {
       if (!_.has(result, key)) result[key] = 0;
       result[key]++;
     });
@@ -260,13 +256,16 @@
     return low;
   };

Safely convert anything iterable into a real, live array.

  _.toArray = function(obj) {
     if (!obj) return [];
-    if (obj.length === +obj.length) return slice.call(obj);
+    if (_.isArray(obj)) return slice.call(obj);
+    if (obj.length === +obj.length) return _.map(obj, _.identity);
     return _.values(obj);
   };

Return the number of elements in an object.

  _.size = function(obj) {
+    if (obj == null) return 0;
     return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
   };

Array Functions

Get the first element of an array. Passing n will return the first N values in the array. Aliased as head and take. The guard check allows it to work with _.map.

  _.first = _.head = _.take = function(array, n, guard) {
+    if (array == null) return void 0;
     return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
   };

Returns everything but the last entry of the array. Especially useful on the arguments object. Passing n will return all the values in @@ -275,6 +274,7 @@ 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) {
+    if (array == null) return void 0;
     if ((n != null) && !guard) {
       return slice.call(array, Math.max(array.length - n, 0));
     } else {
@@ -286,7 +286,7 @@
 check allows it to work with _.map.

  _.rest = _.tail = _.drop = function(array, n, guard) {
     return slice.call(array, (n == null) || guard ? 1 : n);
   };

Trim out all falsy values from an array.

  _.compact = function(array) {
-    return _.filter(array, function(value){ return !!value; });
+    return _.filter(array, _.identity);
   };

Internal implementation of a recursive flatten function.

  var flatten = function(input, shallow, output) {
     each(input, function(value) {
       if (_.isArray(value)) {
@@ -303,6 +303,11 @@
   };

Produce a duplicate-free version of the array. If the array has already been sorted, you have the option of using a faster algorithm. Aliased as unique.

  _.uniq = _.unique = function(array, isSorted, iterator, context) {
+    if (_.isFunction(isSorted)) {
+      context = iterator;
+      iterator = isSorted;
+      isSorted = false;
+    }
     var initial = iterator ? _.map(array, iterator, context) : array;
     var results = [];
     var seen = [];
@@ -340,6 +345,7 @@
   };

Converts lists into objects. Pass either a single array of [key, value] pairs, or two parallel arrays of the same length -- one of keys, and one of the corresponding values.

  _.object = function(list, values) {
+    if (list == null) return {};
     var result = {};
     for (var i = 0, l = list.length; i < l; i++) {
       if (values) {
@@ -399,8 +405,8 @@
   };

Function (ahem) Functions

Reusable constructor function for prototype setting.

  var ctor = function(){};

Create a function bound to a given object (assigning this, and arguments, optionally). Binding with arguments is also known as curry. Delegates to ECMAScript 5's native Function.bind if available. -We check for func.bind first, to fail fast when func is undefined.

  _.bind = function bind(func, context) {
-    var bound, args;
+We check for func.bind first, to fail fast when func is undefined.

  _.bind = function(func, context) {
+    var args, bound;
     if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
     if (!_.isFunction(func)) throw new TypeError;
     args = slice.call(arguments, 2);
@@ -408,6 +414,7 @@
       if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
       ctor.prototype = func.prototype;
       var self = new ctor;
+      ctor.prototype = null;
       var result = func.apply(self, args.concat(slice.call(arguments)));
       if (Object(result) === result) return result;
       return self;
@@ -434,25 +441,26 @@
     return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
   };

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, result;
-    var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
+    var context, args, timeout, result;
+    var previous = 0;
+    var later = function() {
+      previous = new Date;
+      timeout = null;
+      result = func.apply(context, args);
+    };
     return function() {
-      context = this; args = arguments;
-      var later = function() {
+      var now = new Date;
+      var remaining = wait - (now - previous);
+      context = this;
+      args = arguments;
+      if (remaining <= 0) {
+        clearTimeout(timeout);
         timeout = null;
-        if (more) {
-          result = func.apply(context, args);
-        }
-        whenDone();
-      };
-      if (!timeout) timeout = setTimeout(later, wait);
-      if (throttling) {
-        more = true;
-      } else {
-        throttling = true;
+        previous = now;
         result = func.apply(context, args);
+      } else if (!timeout) {
+        timeout = setTimeout(later, remaining);
       }
-      whenDone();
       return result;
     };
   };

Returns a function, that, as long as it continues to be invoked, will not @@ -534,8 +542,10 @@ return names.sort(); };

Extend a given object with all the properties in passed-in object(s).

  _.extend = function(obj) {
     each(slice.call(arguments, 1), function(source) {
-      for (var prop in source) {
-        obj[prop] = source[prop];
+      if (source) {
+        for (var prop in source) {
+          obj[prop] = source[prop];
+        }
       }
     });
     return obj;
@@ -555,8 +565,10 @@
     return copy;
   };

Fill in a given object with default properties.

  _.defaults = function(obj) {
     each(slice.call(arguments, 1), function(source) {
-      for (var prop in source) {
-        if (obj[prop] == null) obj[prop] = source[prop];
+      if (source) {
+        for (var prop in source) {
+          if (obj[prop] == null) obj[prop] = source[prop];
+        }
       }
     });
     return obj;
@@ -643,7 +655,7 @@
       return typeof obj === 'function';
     };
   }

Is a given object a finite number?

  _.isFinite = function(obj) {
-    return _.isNumber(obj) && isFinite(obj);
+    return isFinite( obj ) && !isNaN( parseFloat(obj) );
   };

Is the given value NaN? (NaN is the only number which does not equal itself).

  _.isNaN = function(obj) {
     return _.isNumber(obj) && obj != +obj;
   };

Is a given value a boolean?

  _.isBoolean = function(obj) {
@@ -662,7 +674,9 @@
   };

Keep the identity function around for default iterators.

  _.identity = function(value) {
     return value;
   };

Run a function n times.

  _.times = function(n, iterator, context) {
-    for (var i = 0; i < n; i++) iterator.call(context, i);
+    var accum = Array(n);
+    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
+    return accum;
   };

Return a random integer between min and max (inclusive).

  _.random = function(min, max) {
     if (max == null) {
       max = min;
@@ -706,7 +720,7 @@
   };

Generate a unique integer id (unique within the entire client session). Useful for temporary DOM ids.

  var idCounter = 0;
   _.uniqueId = function(prefix) {
-    var id = idCounter++;
+    var id = '' + ++idCounter;
     return prefix ? prefix + id : id;
   };

By default, Underscore uses ERB-style template delimiters, change the following template settings to use alternative delimiters.

  _.templateSettings = {
@@ -738,11 +752,18 @@
     text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
       source += text.slice(index, offset)
         .replace(escaper, function(match) { return '\\' + escapes[match]; });
-      source +=
-        escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" :
-        interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" :
-        evaluate ? "';\n" + evaluate + "\n__p+='" : '';
+
+      if (escape) {
+        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+      }
+      if (interpolate) {
+        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+      }
+      if (evaluate) {
+        source += "';\n" + evaluate + "\n__p+='";
+      }
       index = offset + match.length;
+      return match;
     });
     source += "';\n";

If a variable is not specified, place data values in local scope.

    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
 
diff --git a/index.html b/index.html
index 71b1f5a36..e62aa9246 100644
--- a/index.html
+++ b/index.html
@@ -179,7 +179,7 @@