diff --git a/underscore.js b/underscore.js new file mode 100644 index 000000000..74d1d9385 --- /dev/null +++ b/underscore.js @@ -0,0 +1,368 @@ +// Javascript can be so much more pleasant when it's functional -- re-implement +// a bunch of utility methods from Prototype and Steele's Functional... +window._ = { + + // The cornerstone, an each implementation. + // Handles objects implementing forEach, _each, arrays, and raw objects. + each : function(obj, iterator, context) { + var index = 0; + try { + if (obj.forEach) { + obj.forEach(iterator, context); + } else if (obj.length) { + for (var i=0; i= result) result = value; + }); + return result; + }, + + // Return the minimum element (or element-based computation). + min : function(obj, iterator, context) { + var result; + _.each(obj, function(value, index) { + value = iterator ? iterator.call(context, value, index) : value; + if (result == null || value < result) result = value; + }); + return result; + }, + + // Optimized version of a common use case of map: fetching a property. + pluck : function(obj, key) { + var results = []; + _.each(obj, function(value){ results.push(value[key]); }); + return results; + }, + + // Return all the elements for which a truth test fails. + reject : function(obj, iterator, context) { + var results = []; + _.each(obj, function(value, index) { + if (!iterator.call(context, value, index)) results.push(value); + }); + return results; + }, + + // Sort the object's values by a criteria produced by an iterator. + sortBy : function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index) { + return { + value : value, + criteria : iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }, + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + sortedIndex : function(array, comparator, obj) { + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + comparator(array[mid], obj) < 0 ? low = mid + 1 : high = mid; + } + return low; + }, + + // Convert anything iterable into a real, live array. + toArray : function(iterable) { + if (!iterable) return []; + if (_.isArray(iterable)) return iterable; + return _.map(iterable, function(val){ return val; }); + }, + + // Return the number of elements in an object. + size : function(obj) { + _.toArray(obj).length; + }, + + //------------- The following methods only apply to arrays. ----------------- + + // Get the first element of an array. + first : function(array) { + return array[0]; + }, + + // Get the last element of an array. + last : function(array) { + return array[array.length - 1]; + }, + + // Trim out all falsy values from an array. + compact : function(array) { + return _.select(array, function(value){ return !!value; }); + }, + + // Return a completely flattened version of an array. + flatten : function(array) { + return _.inject(array, [], function(memo, value) { + if (_.isArray(value)) return memo.concat(_.flatten(value)); + memo.push(value); + return memo; + }); + }, + + // Return a version of the array that does not contain the specified value. + without : function(array) { + var values = array.slice.call(arguments, 0); + return _.select(function(value){ return !_.include(values, value); }); + }, + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + uniq : function(array, sorted) { + return _.inject(array, [], function(memo, el, i) { + if (0 == i || (sorted ? _.last(memo) != el : !_.include(memo, el))) memo.push(el); + return memo; + }); + }, + + // Produce an array that contains every item shared between two given arrays. + intersect : function(array1, array2) { + return _.select(_.uniq(array1), function(item1) { + return _.detect(array2, function(item2) { return item1 === item2; }); + }); + }, + + // If the browser doesn't supply us with indexOf, we might need this function. + // Return the position of the first occurence of an item in an array, + // or -1 if the item is not included in the array. + // indexOf : function(array, item) { + // var length = array.length; + // for (i=0; i)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + + "');}return p.join('');"); + return data ? fn(data) : fn; + } + +};