diff --git a/.gitignore b/.gitignore
index 87adb6951b..cf9a5f5959 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
*.custom.*
.DS_Store
-dist/
node_modules/
diff --git a/.jamignore b/.jamignore
index faf22fdc0a..a1eae95dcc 100644
--- a/.jamignore
+++ b/.jamignore
@@ -1,7 +1,14 @@
*.custom.*
.*
-dist/
+build.js
+index.js
+build/
doc/*.php
node_modules/
perf/*.sh
test/*.sh
+test/test-build.js
+test/template/
+vendor/closure-compiler
+vendor/docdown
+vendor/uglifyjs
diff --git a/.npmignore b/.npmignore
index a21c8bba85..c65b57a14f 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,6 +1,5 @@
*.custom.*
.*
-dist/
doc/*.php
node_modules/
perf/*.html
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000..811124587a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.6
+ - 0.8
\ No newline at end of file
diff --git a/README.md b/README.md
index cd0b26894d..563275e0a0 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,17 @@
-# Lo-Dash v0.7.0
+# Lo-Dash v0.8.0
+[](http://travis-ci.org/bestiejs/lodash)
-A drop-in replacement[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer) for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues-20), and [additional features](https://github.com/bestiejs/lodash#features).
+A drop-in replacement[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer) for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues), and [additional features](http://lodash.com/#features).
Lo-Dash’s performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls.
## Download
- * [Development source](https://raw.github.com/bestiejs/lodash/v0.7.0/lodash.js)
- * [Production source](https://raw.github.com/bestiejs/lodash/v0.7.0/lodash.min.js)
- * CDN copies of ≤ [v0.7.0](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.7.0/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/)
- * For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
+ * [Development build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.js)
+ * [Production build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.min.js)
+ * [Underscore build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.underscore.min.js) tailored for projects already using Underscore
+ * CDN copies of ≤ [v0.8.0](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.8.0/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/)
+ * For optimal file size, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
## Dive in
@@ -32,32 +34,21 @@ For more information check out these screencasts over Lo-Dash:
## Features
* AMD loader support ([RequireJS](http://requirejs.org/), [curl.js](https://github.com/cujojs/curl), etc.)
- * [_.bind](http://lodash.com/docs#bind) supports *“lazy”* binding
* [_.clone](http://lodash.com/docs#clone) supports *“deep”* cloning
- * [_.countBy](http://lodash.com/docs#countBy) as a companion function for [_.groupBy](http://lodash.com/docs#groupBy) and [_.sortBy](http://lodash.com/docs#sortBy)
- * [_.debounce](http://lodash.com/docs#debounce)’ed functions match [_.throttle](http://lodash.com/docs#throttle)’ed functions’ return value behavior
* [_.forEach](http://lodash.com/docs#forEach) is chainable and supports exiting iteration early
* [_.forIn](http://lodash.com/docs#forIn) for iterating over an object’s own and inherited properties
* [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an object’s own properties
- * [_.indexOf](http://lodash.com/docs#indexOf) and [_.lastIndexOf](http://lodash.com/docs#lastIndexOf) accept a `fromIndex` argument
- * [_.invert](http://lodash.com/docs#invert) to create inverted objects
+ * [_.lateBind](http://lodash.com/docs#lateBind) for late binding
* [_.merge](http://lodash.com/docs#merge) for a *“deep”* [_.extend](http://lodash.com/docs#extend)
- * [_.object](http://lodash.com/docs#object) and [_.pairs](http://lodash.com/docs#pairs) for composing objects
- * [_.omit](http://lodash.com/docs#omit) for the inverse functionality of [_.pick](http://lodash.com/docs#pick)
* [_.partial](http://lodash.com/docs#partial) for partial application without `this` binding
* [_.pick](http://lodash.com/docs#pick) and [_.omit](http://lodash.com/docs#omit) accept `callback` and `thisArg` arguments
- * [_.random](http://lodash.com/docs#random) for generating random numbers within a given range
- * [_.sortBy](http://lodash.com/docs#sortBy) performs a [stable](http://en.wikipedia.org/wiki/Sorting_algorithm#Stability) sort
* [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging
- * [_.unescape](http://lodash.com/docs#unescape) to unescape strings escaped by [_.escape](http://lodash.com/docs#escape)
- * [_.where](http://lodash.com/docs#where) for filtering collections by contained properties
- * [_.countBy](http://lodash.com/docs#countBy), [_.groupBy](http://lodash.com/docs#groupBy), [_.sortedIndex](http://lodash.com/docs#sortedIndex), and [_.uniq](http://lodash.com/docs#uniq) accept a `thisArg` argument
* [_.contains](http://lodash.com/docs#contains), [_.size](http://lodash.com/docs#size), [_.toArray](http://lodash.com/docs#toArray),
[and more…](http://lodash.com/docs "_.countBy, _.every, _.filter, _.find, _.forEach, _.groupBy, _.invoke, _.map, _.pluck, _.reduce, _.reduceRight, _.reject, _.some, _.sortBy, _.where") accept strings
## Support
-Lo-Dash has been tested in at least Chrome 5-21, Firefox 1-15, IE 6-9, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.8, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
+Lo-Dash has been tested in at least Chrome 5-22, Firefox 1-15, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.11, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
## Custom builds
@@ -89,7 +80,7 @@ lodash mobile
lodash strict
```
- * Underscore builds, with iteration fixes removed and only Underscore’s API, may be created using the `underscore` modifier argument.
+ * Underscore builds, tailored for projects already using Underscore, may be created using the `underscore` modifier argument.
```bash
lodash underscore
```
@@ -97,23 +88,17 @@ lodash underscore
Custom builds may be created using the following commands:
* Use the `category` argument to pass comma separated categories of methods to include in the build.
- Valid categories are *“arrays”*, *“chaining”*, *“collections”*, *“functions”*, *“objects”*, and *“utilities”*.
+ Valid categories (case-insensitive) are *“arrays”*, *“chaining”*, *“collections”*, *“functions”*, *“objects”*, and *“utilities”*.
```bash
lodash category=collections,functions
lodash category="collections, functions"
-```
-
- * Use the `exclude` argument to pass comma separated names of methods to exclude from the build.
-```bash
-lodash exclude=union,uniq,zip
-lodash exclude="union, uniq, zip"
```
* Use the `exports` argument to pass comma separated names of ways to export the `LoDash` function.
- Valid exports are *“amd”*, *“commonjs”*, *“global”*, *“node”*, and *“none”*.
+ Valid exports are *“amd”*, *“commonjs”*, *“global”*, *“node”*, and *“none”*.
```bash
lodash exports=amd,commonjs,node
-lodash include="amd, commonjs, node"
+lodash exports="amd, commonjs, node"
```
* Use the `iife` argument to specify code to replace the immediately-invoked function expression that wraps Lo-Dash.
@@ -121,31 +106,49 @@ lodash include="amd, commonjs, node"
lodash iife="!function(window,undefined){%output%}(this)"
```
- * Use the `include` argument to pass comma separated names of methods to include in the build.
+ * Use the `include` argument to pass comma separated method/category names to include in the build.
```bash
lodash include=each,filter,map
lodash include="each, filter, map"
```
-All arguments, except `exclude` with `include` and `legacy` with `csp`/`mobile`, may be combined.
+ * Use the `minus` argument to pass comma separated method/category names to remove from those included in the build.
+```bash
+lodash underscore minus=result,shuffle
+lodash underscore minus="result, shuffle"
+```
+ * Use the `plus` argument to pass comma separated method/category names to add to those included in the build.
```bash
-lodash backbone legacy exports=global category=utilities exclude=first,last
-lodash -s underscore mobile strict exports=amd category=functions include=pick,uniq
+lodash backbone plus=random,template
+lodash backbone plus="random, template"
```
+ * Use the `template` argument to pass the file path pattern used to match template files to precompile
+```bash
+lodash template="./*.jst"
+```
+
+ * Use the `settings` argument to pass the template settings used when precompiling templates
+```bash
+lodash settings="{interpolate:/\\{\\{([\\s\\S]+?)\\}\\}/g}"
+```
+
+All arguments, except `legacy` with `csp` or `mobile`, may be combined.
+Unless specified by `-o` or `--output`, all files created are saved to the current working directory.
+
The following options are also supported:
- * `-c`, `--stdout` Write output to standard output
- * `-h`, `--help` Display help information
- * `-o`, `--output` Write output to a given path/filename
- * `-s`, `--silent` Skip status updates normally logged to the console
- * `-V`, `--version` Output current version of Lo-Dash
+ * `-c`, `--stdout` Write output to standard output
+ * `-d`, `--debug` Write only the debug output
+ * `-h`, `--help` Display help information
+ * `-m`, `--minify` Write only the minified output
+ * `-o`, `--output` Write output to a given path/filename
+ * `-s`, `--silent` Skip status updates normally logged to the console
+ * `-V`, `--version` Output current version of Lo-Dash
The `lodash` command-line utility is available when Lo-Dash is installed as a global package (i.e. `npm install -g lodash`).
-Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`.
-
## Installation and usage
In browsers:
@@ -192,43 +195,31 @@ require({
});
```
-## Resolved Underscore.js issues (20+)
-
- * Allow iteration of objects with a `length` property [[#148](https://github.com/documentcloud/underscore/issues/148), [#154](https://github.com/documentcloud/underscore/issues/154), [#252](https://github.com/documentcloud/underscore/issues/252), [#448](https://github.com/documentcloud/underscore/issues/448), [#659](https://github.com/documentcloud/underscore/issues/659), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L543-549)]
- * Ensure array-like objects with invalid `length` properties are treated like regular objects [[#741](https://github.com/documentcloud/underscore/issues/741), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L491-501)]
- * Ensure *“Arrays”*, *“Collections”*, and *“Objects”* methods don’t error when passed falsey arguments [[#650](https://github.com/documentcloud/underscore/pull/650), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1719-1754)]
- * Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L503-520)]
- * Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L554-579)]
- * Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L134-140)]
- * Register as an AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L118-132)]
- * `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L223-234)]
- * `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L289-298)]
- * `_.countBy` and `_.groupBy` should only add values to own, not inherited, properties [[#736](https://github.com/documentcloud/underscore/issues/736), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L306-313)]
- * `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L946-968)]
- * `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L486-489)]
- * `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L581-600)]
- * `_.isElement` should use strict equality for its duck type check [[#734](https://github.com/documentcloud/underscore/issues/734), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L696-705)]
- * `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L732-737)]
- * `_.isEqual` should return `true` for like-objects from different documents [[#733](https://github.com/documentcloud/underscore/issues/733), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L784-795)]
- * `_.isEqual` should use custom `isEqual` methods before checking strict equality [[#748](https://github.com/documentcloud/underscore/issues/748), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L758-761)]
- * `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L803-815)]
- * `_.isNaN(new Number(NaN))` should return `true` [[#749](https://github.com/documentcloud/underscore/issues/749), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L823-825)]
- * `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L879-881)]
- * `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1222-1225)]
- * `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1257-1271)]
- * `_.sortedIndex` should support arrays with high `length` values [[#735](https://github.com/documentcloud/underscore/issues/735), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1404-1413)]
- * `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1534-1544)]
- * `_.toArray` uses custom `toArray` methods of arrays and strings [[#747](https://github.com/documentcloud/underscore/issues/747), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1571-1579)]
+## Resolved Underscore.js issues
+
+ * Add AMD loader support [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L118-140)]
+ * Allow iteration of objects with a `length` property [[#799](https://github.com/documentcloud/underscore/pull/799), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L510-516)]
+ * Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L470-487)]
+ * Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L526-546)]
+ * Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L142-148)]
+ * `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L215-224)]
+ * `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L267-276)]
+ * `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L946-968)]
+ * `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L465-468)]
+ * `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L556-570)]
+ * `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L703-708)]
+ * `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L763-775)]
+ * `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L856-858)]
+ * `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L1222-1225)]
+ * `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L1525-1535)]
## Optimized methods (50+)
* `_.bind`
* `_.bindAll`
- * `_.clone`
* `_.compact`
* `_.contains`, `_.include`
* `_.defaults`
- * `_.defer`
* `_.difference`
* `_.each`
* `_.every`, `_.all`
@@ -245,7 +236,6 @@ require({
* `_.invoke`
* `_.isArguments`
* `_.isDate`
- * `_.isEmpty`
* `_.isFinite`
* `_.isFunction`
* `_.isObject`
@@ -272,11 +262,11 @@ require({
* `_.sortedIndex`
* `_.template`
* `_.throttle`
- * `_.times`
* `_.toArray`
* `_.union`
* `_.uniq`, `_.unique`
* `_.values`
+ * `_.where`
* `_.without`
* `_.wrap`
* `_.zip`
@@ -284,30 +274,25 @@ require({
## Release Notes
-### v0.7.0
+### v0.8.0
#### Compatibility Warnings ####
- * Renamed `_.zipObject` to `_.object`
- * Replaced `_.drop` with `_.omit`
- * Made `_.drop` alias `_.rest`
+ * Made `_.random` return `0` or `1` when no arguments are passed
+ * Moved late bind functionality from `_.bind` to [_.lateBind](http://lodash.com/docs#lateBind)
+ * Removed first argument falsey checks from methods
+ * Removed support for custom `clone`, `isEqual`, `toArray` methods from
+ `_.clone`, `_.isEqual`, and `_.toArray`
#### Changes ####
- * Added [_.invert](http://lodash.com/docs#invert), [_.pairs](http://lodash.com/docs#pairs), and [_.random](http://lodash.com/docs#random)
- * Added `_.result` to the `backbone` build
- * Added `exports`, `iife`, `-c`/`--stdout`, `-o`/`--output`, and `-s`/`--silent` build options
- * Ensured `isPlainObject` works with objects from other documements
- * Ensured `_.isEqual` compares values with circular references correctly
- * Ensured `_.merge` work with four or more arguments
- * Ensured `_.sortBy` performs a stable sort for `undefined` values
- * Ensured `_.template` works with "interpolate" delimiters containing ternary operators
- * Ensured the production build works in Node.js
- * Ensured template delimiters are tokenized correctly
- * Made pseudo private properties `_chain` and `_wrapped` double-underscored to avoid conflicts
- * Made `minify.js` support `underscore.js`
- * Reduced the size of `mobile` and `underscore` builds
- * Simplified `_.isEqual` and `_.size`
+ * Added `-d`/`--debug`, `-m/--minify`, `minus`, `plus`, `settings`, and `template` build options
+ * Added `_.isPlainObject` and `_.lateBind`
+ * Allowed `_.sortedIndex` to accept a property name as the `callback` argument
+ * Ensured methods accept a `thisArg` of `null`
+ * Fixed the `iife` build option to accept more values
+ * Made `_.times` return an array of `callback` results
+ * Simplified `_.max`, `_.min`, and `_.reduceRight`
The full changelog is available [here](https://github.com/bestiejs/lodash/wiki/Changelog).
diff --git a/build.js b/build.js
index d412e73e8e..776328a765 100755
--- a/build.js
+++ b/build.js
@@ -12,8 +12,14 @@
/** The current working directory */
var cwd = process.cwd();
+ /** Shortcut to native `Array.prototype` */
+ var ArrayProto = Array.prototype;
+
+ /** Shortcut used to push arrays of values to an array */
+ var push = ArrayProto.push;
+
/** Shortcut used to convert array-like objects to arrays */
- var slice = [].slice;
+ var slice = ArrayProto.slice;
/** Shortcut to the `stdout` object */
var stdout = process.stdout;
@@ -61,11 +67,11 @@
'bind': ['isFunction'],
'bindAll': ['bind', 'isFunction'],
'chain': ['mixin'],
- 'clone': ['extend', 'forIn', 'forOwn', 'isArguments', 'isFunction'],
+ 'clone': ['extend', 'forOwn', 'isArguments', 'isPlainObject'],
'compact': [],
'compose': [],
'contains': [],
- 'countBy': [],
+ 'countBy': ['identity'],
'debounce': [],
'defaults': ['isArguments'],
'defer': [],
@@ -75,14 +81,14 @@
'every': ['identity'],
'extend': ['isArguments'],
'filter': ['identity'],
- 'find': [],
+ 'find': ['identity'],
'first': [],
'flatten': ['isArray'],
- 'forEach': [],
- 'forIn': ['isArguments'],
- 'forOwn': ['isArguments'],
+ 'forEach': ['identity'],
+ 'forIn': ['identity', 'isArguments'],
+ 'forOwn': ['identity', 'isArguments'],
'functions': ['isArguments', 'isFunction'],
- 'groupBy': [],
+ 'groupBy': ['identity'],
'has': [],
'identity': [],
'indexOf': ['sortedIndex'],
@@ -103,38 +109,40 @@
'isNull': [],
'isNumber': [],
'isObject': [],
+ 'isPlainObject': ['forIn', 'isArguments', 'isFunction'],
'isRegExp': [],
'isString': [],
'isUndefined': [],
'keys': ['isArguments'],
'last': [],
'lastIndexOf': [],
+ 'lateBind': ['isFunction'],
'map': ['identity'],
- 'max': [],
+ 'max': ['identity'],
'memoize': [],
- 'merge': ['isArguments', 'isArray', 'forIn'],
- 'min': [],
+ 'merge': ['isArray', 'isPlainObject'],
+ 'min': ['identity'],
'mixin': ['forEach', 'functions'],
'noConflict': [],
'object': [],
'omit': ['indexOf', 'isArguments'],
'once': [],
'pairs': [],
- 'partial': [],
+ 'partial': ['isFunction'],
'pick': [],
'pluck': [],
'random': [],
'range': [],
- 'reduce': [],
- 'reduceRight': ['keys'],
+ 'reduce': ['identity'],
+ 'reduceRight': ['forEach', 'keys'],
'reject': ['identity'],
'rest': [],
'result': ['isFunction'],
'shuffle': [],
'size': ['keys'],
'some': ['identity'],
- 'sortBy': [],
- 'sortedIndex': ['bind'],
+ 'sortBy': ['identity'],
+ 'sortedIndex': ['identity'],
'tap': ['mixin'],
'template': ['escape'],
'throttle': [],
@@ -159,7 +167,6 @@
'arrayBranch',
'beforeLoop',
'bottom',
- 'exit',
'firstArg',
'hasDontEnumBug',
'inLoop',
@@ -205,6 +212,7 @@
'keys',
'last',
'lastIndexOf',
+ 'lateBind',
'map',
'max',
'min',
@@ -226,21 +234,15 @@
/** List of methods used by Underscore */
var underscoreMethods = _.without.apply(_, [allMethods].concat([
- 'countBy',
'forIn',
'forOwn',
- 'invert',
+ 'isPlainObject',
+ 'lateBind',
'merge',
- 'object',
- 'omit',
- 'pairs',
- 'partial',
- 'random',
- 'unescape',
- 'where'
+ 'partial'
]));
- /** List of ways to export the `LoDash` function */
+ /** List of ways to export the `lodash` function */
var exportsAll = [
'amd',
'commonjs',
@@ -250,6 +252,75 @@
/*--------------------------------------------------------------------------*/
+ /**
+ * Compiles template files matched by the given file path `pattern` into a
+ * single source, extending `_.templates` with precompiled templates named after
+ * each template file's basename.
+ *
+ * @private
+ * @param {String} [pattern='/*.jst'] The file path pattern.
+ * @param {Object} [options=_.templateSettings] The options object.
+ * @returns {String} Returns the compiled source.
+ */
+ function buildTemplate(pattern, options) {
+ pattern || (pattern = path.join(cwd, '*.jst'));
+ options || (options = _.templateSettings);
+
+ var directory = path.dirname(pattern);
+
+ var moduleName = 'lodash';
+
+ var source = [
+ ';(function(window) {',
+ " var freeExports = typeof exports == 'object' && exports &&",
+ " (typeof global == 'object' && global && global == global.global && (window = global), exports);",
+ '',
+ ' var templates = {};',
+ '',
+ ' var _ = window._;',
+ ''
+ ];
+
+ // convert to a regexp
+ pattern = RegExp(
+ path.basename(pattern)
+ .replace(/[.+?^=!:${}()|[\]\/\\]/g, '\\$&')
+ .replace(/\*/g, '.*?') + '$'
+ );
+
+ fs.readdirSync(directory).forEach(function(filename) {
+ var filePath = path.join(directory, filename);
+ if (pattern.test(filename)) {
+ var text = fs.readFileSync(filePath, 'utf8'),
+ precompiled = getFunctionSource(_.template(text, null, options)),
+ prop = filename.replace(/\..*$/, '');
+
+ source.push(" templates['" + prop + "'] = " + precompiled + ';');
+ }
+ });
+
+ source.push(
+ '',
+ " if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {",
+ " define(['" + moduleName + "'], function(lodash) {",
+ ' _ = lodash;',
+ ' _.templates = _.extend(_.templates || {}, templates);',
+ ' });',
+ " } else if (freeExports) {",
+ " if (typeof module == 'object' && module && module.exports == freeExports) {",
+ ' (module.exports = templates).templates = templates;',
+ ' } else {',
+ ' freeExports.templates = templates;',
+ ' }',
+ ' } else if (_) {',
+ ' _.templates = _.extend(_.templates || {}, templates);',
+ ' }',
+ '}(this));'
+ );
+
+ return source.join('\n');
+ }
+
/**
* Removes unnecessary comments, whitespace, and pseudo private properties.
*
@@ -284,23 +355,31 @@
' lodash legacy Build tailored for older browsers without ES5 support',
' lodash mobile Build with IE < 9 bug fixes & method compilation removed',
' lodash strict Build with `_.bindAll`, `_.defaults`, & `_.extend` in strict mode',
- ' lodash underscore Build with iteration fixes removed and only Underscore’s API',
- ' lodash exclude=... Comma separated names of methods to exclude from the build',
- ' lodash include=... Comma separated names of methods to include in the build',
- ' lodash category=... Comma separated categories of methods to include in the build',
+ ' lodash underscore Build tailored for projects already using Underscore',
+ ' lodash include=... Comma separated method/category names to include in the build',
+ ' lodash minus=... Comma separated method/category names to remove from those included in the build',
+ ' lodash plus=... Comma separated method/category names to add to those included in the build',
+ ' lodash category=... Comma separated categories of methods to include in the build (case-insensitive)',
' (i.e. “arrays”, “chaining”, “collections”, “functions”, “objects”, and “utilities”)',
- ' lodash exports=... Comma separated names of ways to export the `LoDash` function',
+ ' lodash exports=... Comma separated names of ways to export the `lodash` function',
' (i.e. “amd”, “commonjs”, “global”, “node”, and “none”)',
' lodash iife=... Code to replace the immediately-invoked function expression that wraps Lo-Dash',
- ' (e.g. “!function(window,undefined){%output%}(this)”)',
+ ' (e.g. `lodash iife="!function(window,undefined){%output%}(this)"`)',
'',
- ' All arguments, except `exclude` with `include` & `legacy` with `csp`/`mobile`,',
- ' may be combined.',
+ ' lodash template=... File path pattern used to match template files to precompile',
+ ' (e.g. `lodash template=./*.jst`)',
+ ' lodash settings=... Template settings used when precompiling templates',
+ ' (e.g. `lodash settings="{interpolate:/\\\\{\\\\{([\\\\s\\\\S]+?)\\\\}\\\\}/g}"`)',
+ '',
+ ' All arguments, except `legacy` with `csp` or `mobile`, may be combined.',
+ ' Unless specified by `-o` or `--output`, all files created are saved to the current working directory.',
'',
' Options:',
'',
' -c, --stdout Write output to standard output',
+ ' -d, --debug Write only the debug output',
' -h, --help Display help information',
+ ' -m, --minify Write only the minified output',
' -o, --output Write output to a given path/filename',
' -s, --silent Skip status updates normally logged to the console',
' -V, --version Output current version of Lo-Dash',
@@ -391,14 +470,39 @@
}
/**
- * Gets the `_.isArguments` fallback snippet from `source`.
+ * Gets the `_.isArguments` fallback from `source`.
*
* @private
* @param {String} source The source to inspect.
- * @returns {String} Returns the `isArguments` fallback snippet.
+ * @returns {String} Returns the `isArguments` fallback.
*/
function getIsArgumentsFallback(source) {
- return (source.match(/(?:\s*\/\/.*)*\n( +)if *\(noArgsClass[\s\S]+?};\n\1}/) || [''])[0];
+ return (source.match(/(?:\s*\/\/.*)*\n( +)if *\(noArgsClass\)[\s\S]+?};\n\1}/) || [''])[0];
+ }
+
+ /**
+ * Gets the `_.isFunction` fallback from `source`.
+ *
+ * @private
+ * @param {String} source The source to inspect.
+ * @returns {String} Returns the `isFunction` fallback.
+ */
+ function getIsFunctionFallback(source) {
+ return (source.match(/(?:\s*\/\/.*)*\n( +)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/) || [''])[0];
+ }
+
+ /**
+ * Gets the names of methods in `source` belonging to the given `category`.
+ *
+ * @private
+ * @param {String} source The source to inspect.
+ * @param {String} category The category to filter by.
+ * @returns {Array} Returns a new array of method names belonging to the given category.
+ */
+ function getMethodsByCategory(source, category) {
+ return allMethods.filter(function(methodName) {
+ return category && RegExp('@category ' + category + '\\b').test(matchFunction(source, methodName));
+ });
}
/**
@@ -454,6 +558,41 @@
return result ? result[0] : '';
}
+ /**
+ * Converts a comma separated options string into an array.
+ *
+ * @private
+ * @param {String} value The option to convert.
+ * @returns {Array} Returns the new converted array.
+ */
+ function optionToArray(value) {
+ return value.match(/\w+=(.*)$/)[1].split(/, */);
+ }
+
+ /**
+ * Converts a comma separated options string into an array containing
+ * only real method names.
+ *
+ * @private
+ * @param {String} source The source to inspect.
+ * @param {String} value The option to convert.
+ * @returns {Array} Returns the new converted array.
+ */
+ function optionToMethodsArray(source, value) {
+ var methodNames = optionToArray(value);
+
+ // convert categories to method names
+ methodNames.forEach(function(category) {
+ push.apply(methodNames, getMethodsByCategory(source, category));
+ });
+
+ // convert aliases to real method names
+ methodNames = methodNames.map(getRealName);
+
+ // remove nonexistent and duplicate method names
+ return _.uniq(_.intersection(allMethods, methodNames));
+ }
+
/**
* Removes the all references to `refName` from `createIterator` in `source`.
*
@@ -491,7 +630,7 @@
return source;
}
// remove function
- source = source.replace(matchFunction(source, funcName), '');
+ source = source.replace(snippet, '');
// grab the method assignments snippet
snippet = getMethodAssignments(source);
@@ -526,7 +665,7 @@
* @returns {String} Returns the source with the `isFunction` fallback removed.
*/
function removeIsFunctionFallback(source) {
- return source.replace(/(?:\s*\/\/.*)*\n( +)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/, '');
+ return source.replace(getIsFunctionFallback(source), '');
}
/**
@@ -539,7 +678,7 @@
function removeKeysOptimization(source) {
return removeVar(source, 'isKeysFast')
// remove optimized branch in `iteratorTemplate`
- .replace(/(?: *\/\/.*\n)* *'( *)<% *if *\(isKeysFast[\s\S]+?'\1<% *} *else *\{ *%>.+\n([\s\S]+?) *'\1<% *} *%>.+/, '$2')
+ .replace(/(?: *\/\/.*\n)* *'( *)<% *if *\(isKeysFast[\s\S]+?'\1<% *} *else *\{ *%>.+\n([\s\S]+?) *'\1<% *} *%>.+/, "'\\n' +\n$2")
// remove `isKeysFast` from `beforeLoop.object` of `mapIteratorOptions`
.replace(/=\s*'\s*\+\s*\(isKeysFast.+/, "= []'")
// remove `isKeysFast` from `inLoop.object` of `mapIteratorOptions`, `invoke`, `pairs`, `pluck`, and `sortBy`
@@ -560,7 +699,7 @@
// remove `noArgsClass` from `_.clone` and `_.isEqual`
.replace(/ *\|\| *\(noArgsClass *&&[^)]+?\)\)/g, '')
// remove `noArgsClass` from `_.isEqual`
- .replace(/if *\(noArgsClass[^}]+?}\n/, '');
+ .replace(/if *\(noArgsClass[^}]+?}\n/, '\n');
}
/**
@@ -589,13 +728,17 @@
* @returns {String} Returns the source with the variable removed.
*/
function removeVar(source, varName) {
+ // simplify `arrayLikeClasses` and `cloneableClasses`
+ if (/^(?:arrayLike|cloneable)Classes$/.test(varName)) {
+ source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?(true;\\n)'), '$1$2');
+ }
source = source.replace(RegExp(
// begin non-capturing group
'(?:' +
// match multi-line comment block
'(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' +
// match a variable declaration that's not part of a declaration list
- '( +)var ' + varName + ' *= *(?:.+?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\1.+?;)\\n|' +
+ '( +)var ' + varName + ' *= *(?:.+?(?:;|&&\\n[^;]+;)|(?:\\w+\\(|{)[\\s\\S]+?\\n\\1.+?;)\\n|' +
// match a variable in a declaration list
'\\n +' + varName + ' *=.+?,' +
// end non-capturing group
@@ -625,18 +768,20 @@
*/
function replaceVar(source, varName, varValue) {
// replace a variable that's not part of a declaration list
- source = source.replace(RegExp(
+ var result = source.replace(RegExp(
'(( +)var ' + varName + ' *= *)' +
'(?:.+?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\2.+?;)\\n'
), '$1' + varValue + ';\n');
- // replace a varaible at the start or middle of a declaration list
- source = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), '$1 ' + varValue + ',');
-
- // replace a variable at the end of a variable declaration list
- source = source.replace(RegExp('(,\\s*' + varName + ' *=).+?;'), '$1 ' + varValue + ';');
-
- return source;
+ if (source == result) {
+ // replace a varaible at the start or middle of a declaration list
+ result = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), '$1 ' + varValue + ',');
+ }
+ if (source == result) {
+ // replace a variable at the end of a variable declaration list
+ result = source.replace(RegExp('(,\\s*' + varName + ' *=).+?;'), '$1 ' + varValue + ';');
+ }
+ return result;
}
/**
@@ -664,9 +809,9 @@
/**
* Creates a debug and minified build, executing the `callback` for each.
- * The `callback` is invoked with 2 arguments; (filepath, source)
+ * The `callback` is invoked with 2 arguments; (filePath, source)
*
- * @param {Array} options The options array.
+ * @param {Array} [options=[]] An array of commands.
* @param {Function} callback The function called per build.
*/
function build(options, callback) {
@@ -678,7 +823,7 @@
// used to report invalid command-line arguments
var invalidArgs = _.reject(options.slice(options[0] == 'node' ? 2 : 0), function(value, index, options) {
if (/^(?:-o|--output)$/.test(options[index - 1]) ||
- /^(?:category|exclude|exports|iife|include)=.*$/.test(value)) {
+ /^(?:category|exclude|exports|iife|include|minus|plus|settings|template)=.*$/.test(value)) {
return true;
}
return [
@@ -689,7 +834,9 @@
'strict',
'underscore',
'-c', '--stdout',
+ '-d', '--debug',
'-h', '--help',
+ '-m', '--minify',
'-o', '--output',
'-s', '--silent',
'-V', '--version'
@@ -725,9 +872,14 @@
/*------------------------------------------------------------------------*/
- // collections of method names to exclude or include
- var excludeMethods = [],
- includeMethods = [];
+ // backup `dependencyMap` to restore later
+ var dependencyBackup = _.clone(dependencyMap, true);
+
+ // used to specify a custom IIFE to wrap Lo-Dash
+ var iife = options.reduce(function(result, value) {
+ var match = value.match(/iife=(.*)/);
+ return match ? match[1] : result;
+ }, null);
// flag used to specify a Backbone build
var isBackbone = options.indexOf('backbone') > -1;
@@ -735,12 +887,18 @@
// flag used to specify a Content Security Policy build
var isCSP = options.indexOf('csp') > -1 || options.indexOf('CSP') > -1;
+ // flag used to specify only creating the debug build
+ var isDebug = options.indexOf('-d') > -1 || options.indexOf('--debug') > -1;
+
// flag used to specify a legacy build
var isLegacy = options.indexOf('legacy') > -1;
// flag used to specify an Underscore build
var isUnderscore = options.indexOf('underscore') > -1;
+ // flag used to specify only creating the minified build
+ var isMinify = !isDebug && options.indexOf('-m') > -1 || options.indexOf('--minify')> -1;
+
// flag used to specify a mobile build
var isMobile = !isLegacy && (isCSP || isUnderscore || options.indexOf('mobile') > -1);
@@ -754,49 +912,112 @@
// constructed using the "use strict" directive
var isStrict = options.indexOf('strict') > -1;
- // flag used to specify if the build should include the "use strict" directive
- var useStrict = isStrict || !(isLegacy || isMobile);
+ // used to specify the ways to export the `lodash` function
+ var exportsOptions = options.reduce(function(result, value) {
+ return /exports/.test(value) ? optionToArray(value).sort() : result;
+ }, isUnderscore
+ ? ['commonjs', 'global', 'node']
+ : exportsAll.slice()
+ );
+
+ // used to specify the output path for builds
+ var outputPath = options.reduce(function(result, value, index) {
+ if (/-o|--output/.test(value)) {
+ result = options[index + 1];
+ result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result));
+ }
+ return result;
+ }, '');
+
+ // used to match external template files to precompile
+ var templatePattern = options.reduce(function(result, value) {
+ var match = value.match(/template=(.+)$/);
+ return match
+ ? path.join(fs.realpathSync(path.dirname(match[1])), path.basename(match[1]))
+ : result;
+ }, '');
+
+ // used when precompiling template files
+ var templateSettings = options.reduce(function(result, value) {
+ var match = value.match(/settings=(.+)$/);
+ return match
+ ? Function('return {' + match[1].replace(/^{|}$/g, '') + '}')()
+ : result;
+ }, _.clone(_.templateSettings));
+
+ // flag used to specify a template build
+ var isTemplate = !!templatePattern;
// the lodash.js source
var source = fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8');
- // used to specify the ways to export the `LoDash` function
- var exportsOptions = options.reduce(function(result, value) {
- var match = value.match(/^exports=(.*)$/);
- if (!match) {
- return result;
- }
- return match[1].split(/, */).sort();
- }, exportsAll.slice());
+ // flag used to specify if the build should include the "use strict" directive
+ var useStrict = isStrict || !(isLegacy || isMobile);
- // used to specify whether filtering is for exclusion or inclusion
- var filterType = options.reduce(function(result, value) {
- if (result) {
- return result;
+ /*------------------------------------------------------------------------*/
+
+ // names of methods to include in the build
+ var buildMethods = !isTemplate && (function() {
+ var result;
+
+ var minusMethods = options.reduce(function(accumulator, value) {
+ return /exclude|minus/.test(value)
+ ? _.union(accumulator, optionToMethodsArray(source, value))
+ : accumulator;
+ }, []);
+
+ var plusMethods = options.reduce(function(accumulator, value) {
+ return /plus/.test(value)
+ ? _.union(accumulator, optionToMethodsArray(source, value))
+ : accumulator;
+ }, []);
+
+ // add method names explicitly
+ options.some(function(value) {
+ return /include/.test(value) &&
+ (result = getDependencies(optionToMethodsArray(source, value)));
+ });
+
+ // add method names required by Backbone and Underscore builds
+ if (isBackbone && !result) {
+ result = getDependencies(backboneDependencies);
}
- var pair = value.match(/^(exclude|include)=(.*)$/);
- if (!pair) {
- return result;
+ if (isUnderscore && !result) {
+ result = getDependencies(underscoreMethods);
}
- // remove nonexistent method names
- var methodNames = _.intersection(allMethods, pair[2].split(/, */).map(getRealName));
- if (pair[1] == 'exclude') {
- excludeMethods = methodNames;
- } else {
- includeMethods = methodNames;
+ // add method names by category
+ options.some(function(value) {
+ if (!/category/.test(value)) {
+ return false;
+ }
+ // resolve method names belonging to each category (case-insensitive)
+ var methodNames = optionToArray(value).reduce(function(accumulator, category) {
+ var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1);
+ return accumulator.concat(getMethodsByCategory(source, capitalized));
+ }, []);
+
+ return (result = _.union(result || [], getDependencies(methodNames)));
+ });
+
+ // init `result` if it hasn't been inited
+ if (!result) {
+ result = allMethods.slice();
}
- // return `filterType`
- return pair[1];
- }, '');
- // used to specify a custom IIFE to wrap Lo-Dash
- var iife = options.reduce(function(result, value) {
- return result || (result = value.match(/^iife=(.*)$/)) && result[1];
- }, '');
+ if (plusMethods.length) {
+ result = _.union(result, getDependencies(plusMethods));
+ }
+ if (minusMethods.length) {
+ result = _.without.apply(_, [result].concat(minusMethods, getDependants(result)));
+ }
+ return result;
+ }());
+
+ /*------------------------------------------------------------------------*/
// load customized Lo-Dash module
- var lodash = (function() {
+ var lodash = !isTemplate && (function() {
var context = vm.createContext({
'clearTimeout': clearTimeout,
'setTimeout': setTimeout
@@ -812,7 +1033,7 @@
}
}
if (isLegacy) {
- ['isBindFast', 'isKeysFast', 'isStrictFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'].forEach(function(varName) {
+ _.each(['isBindFast', 'isKeysFast', 'isStrictFast', 'nativeBind', 'nativeGetPrototypeOf', 'nativeIsArray', 'nativeKeys'], function(varName) {
source = replaceVar(source, varName, 'false');
});
@@ -820,42 +1041,66 @@
source = removeKeysOptimization(source);
}
else if (isUnderscore) {
+ // update dependencies
+ dependencyMap.clone = ['extend', 'isArray'];
+ dependencyMap.isEqual = ['isArray', 'isFunction'];
+ dependencyMap.isEmpty = ['isArray'];
+
+ // remove unneeded variables
+ source = removeVar(source, 'arrayLikeClasses');
+ source = removeVar(source, 'cloneableClasses');
+
+ // remove large array optimizations from `cachedContains`
+ source = source.replace(/( +)function cachedContains[\s\S]+?\n\1}/, [
+ ' function cachedContains(array, fromIndex) {',
+ ' return function(value) {',
+ ' return indexOf(array, value, fromIndex || 0) > -1;',
+ ' };',
+ ' }'
+ ].join('\n'));
+
+ // reduce the number of arguments passed to `cachedContains` from 3 to 2
+ source = source.replace(/(cachedContains\(\w+, *\w+), *\w+/g, '$1');
+
+ // replace `arrayLikeClasses` in `_.isEmpty`
+ source = source.replace(/'if *\(arrayLikeClasses[\s\S]+?' \|\|\\n/, "'if (isArray(value) || className == stringClass ||");
+
+ // replace `arrayLikeClasses` in `_.isEqual`
+ source = source.replace(/(?: *\/\/.*\n)*( +)var isArr *= *arrayLikeClasses[^}]+}/, '$1var isArr = isArray(a);');
+
+ // remove "exit early" feature from `_.each`
+ source = source.replace(/( )+var baseIteratorOptions *=[\s\S]+?\n\1.+?;/, function(match) {
+ return match.replace(/if *\(callback[^']+/, 'callback(value, index, collection)');
+ });
+
// remove `deep` clone functionality
source = source.replace(/( +)function clone[\s\S]+?\n\1}/, [
' function clone(value) {',
- ' if (value == null) {',
- ' return value;',
- ' }',
- ' var isObj = objectTypes[typeof value];',
- ' if (isObj && value.clone && isFunction(value.clone)) {',
- ' return value.clone(deep);',
- ' }',
- ' if (isObj) {',
- ' var className = toString.call(value);',
- ' if (!cloneableClasses[className] || (noArgsClass && isArguments(value))) {',
- ' return value;',
- ' }',
- ' var isArr = className == arrayClass;',
- ' }',
- ' return isObj',
- ' ? (isArr ? slice.call(value) : extend({}, value))',
- ' : value;',
+ ' return value && objectTypes[typeof value]',
+ ' ? (isArray(value) ? slice.call(value) : extend({}, value))',
+ ' : value',
' }'
].join('\n'));
+
+ // remove unused features from `createBound`
+ if (buildMethods.indexOf('partial') == -1) {
+ source = source.replace(matchFunction(source, 'createBound'), function(match) {
+ return match
+ .replace(/(function createBound\([^{]+{)[\s\S]+?(\n *function bound)/, '$1$2')
+ .replace(/thisBinding *=[^}]+}/, 'thisBinding = thisArg;\n');
+ });
+ }
}
if (isMobile) {
source = replaceVar(source, 'isKeysFast', 'false');
source = removeKeysOptimization(source);
- // remove Opera 10.53-10.60 JIT fixes
- source = source.replace(/length *> *-1 *&& *length/g, 'length');
-
// remove `prototype` [[Enumerable]] fix from `_.keys`
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(.+?propertyIsEnumerable[\s\S]+?\n\1}/, '');
// remove `prototype` [[Enumerable]] fix from `iteratorTemplate`
source = source
- .replace(/(?: *\/\/.*\n)*\s*' *(?:<% *)?if *\(!hasDontEnumBug *(?:&&|\))[\s\S]+?<% *} *(?:%>|').+/g, '')
+ .replace(/(?: *\/\/.*\n)* *' *(?:<% *)?if *\(!hasDontEnumBug *(?:&&|\))[\s\S]+?<% *} *(?:%>|').+/g, '')
.replace(/!hasDontEnumBug *\|\|/g, '');
}
vm.runInContext(source, context);
@@ -864,469 +1109,361 @@
/*------------------------------------------------------------------------*/
- // customize for Backbone and Underscore builds
- if (isUnderscore) {
- // don't expose `_.forIn` or `_.forOwn` if `isUnderscore` is `true` unless
- // requested by `include`
- if (includeMethods.indexOf('forIn') == -1) {
- source = source.replace(/ *lodash\.forIn *=.+\n/, '');
- }
- if (includeMethods.indexOf('forOwn') == -1) {
- source = source.replace(/ *lodash\.forOwn *=.+\n/, '');
- }
+ if (isTemplate) {
+ source = buildTemplate(templatePattern, templateSettings);
}
+ else {
+ // simplify template snippets by removing unnecessary brackets
+ source = source.replace(
+ RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *([,\\n])", 'g'), "$1'$2"
+ );
- // include methods required by Backbone and Underscore builds
- [
- { 'flag': isBackbone, 'methodNames': backboneDependencies },
- { 'flag': isUnderscore, 'methodNames': underscoreMethods }
- ]
- .some(function(data) {
- var flag = data.flag,
- methodNames = data.methodNames;
-
- if (!flag) {
- return false;
- }
- // add any additional sub-dependencies
- methodNames = getDependencies(methodNames);
-
- if (filterType == 'exclude') {
- // remove excluded methods from `methodNames`
- includeMethods = _.without.apply(_, [methodNames].concat(excludeMethods));
- }
- else if (filterType) {
- // merge `methodNames` into `includeMethods`
- includeMethods = _.union(includeMethods, methodNames);
- }
- else {
- // include only the `methodNames`
- includeMethods = methodNames;
- }
- filterType = 'include';
- return true;
- });
-
- /*------------------------------------------------------------------------*/
+ source = source.replace(
+ RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *\\+", 'g'), "$1;\\n'+"
+ );
- // include methods by category
- options.some(function(value) {
- var categories = value.match(/^category=(.*)$/);
- if (!categories) {
- return false;
- }
- // resolve method names belonging to each category
- var categoryMethods = categories[1].split(/, */).reduce(function(result, category) {
- return result.concat(allMethods.filter(function(methodName) {
- return RegExp('@category ' + category + '\\b', 'i').test(matchFunction(source, methodName));
- }));
- }, []);
+ // remove methods from the build
+ allMethods.forEach(function(otherName) {
+ if (!_.contains(buildMethods, otherName)) {
+ source = removeFunction(source, otherName);
+ }
+ });
- if (filterType == 'exclude') {
- // remove excluded methods from `categoryMethods`
- includeMethods = _.without.apply(_, [categoryMethods].concat(excludeMethods));
- }
- else if (filterType) {
- // merge `categoryMethods` into `includeMethods`
- includeMethods = _.union(includeMethods, categoryMethods);
- }
- else {
- // include only the `categoryMethods`
- includeMethods = categoryMethods;
+ // remove `isArguments` fallback before `isArguments` is transformed by
+ // other parts of the build process
+ if (isRemoved(source, 'isArguments')) {
+ source = removeIsArgumentsFallback(source);
}
- filterType = 'include';
- return true;
- });
- /*------------------------------------------------------------------------*/
+ /*----------------------------------------------------------------------*/
- // remove methods from the build
- (function() {
- // exit early if "exclude" or "include" options aren't specified
- if (!filterType) {
- return;
- }
- if (filterType == 'exclude') {
- // remove methods that are named in `excludeMethods` and their dependants
- excludeMethods.forEach(function(methodName) {
- getDependants(methodName).concat(methodName).forEach(function(otherName) {
- source = removeFunction(source, otherName);
- });
+ if (isLegacy) {
+ _.each(['isBindFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'], function(varName) {
+ source = removeVar(source, varName);
});
- }
- else {
- // add dependencies to `includeMethods`
- includeMethods = getDependencies(includeMethods);
- // remove methods that aren't named in `includeMethods`
- allMethods.forEach(function(otherName) {
- if (!_.contains(includeMethods, otherName)) {
- source = removeFunction(source, otherName);
+ _.each(['bind', 'isArray'], function(methodName) {
+ var snippet = matchFunction(source, methodName),
+ modified = snippet;
+
+ // remove native `Function#bind` branch in `_.bind`
+ if (methodName == 'bind') {
+ modified = modified.replace(/(?:\s*\/\/.*)*\s*return isBindFast[^:]+:\s*/, 'return ');
}
+ // remove native `Array.isArray` branch in `_.isArray`
+ else {
+ modified = modified.replace(/nativeIsArray * \|\|/, '');
+ }
+ source = source.replace(snippet, modified);
});
- }
- }());
-
- /*------------------------------------------------------------------------*/
- // simplify template snippets by removing unnecessary brackets
- source = source.replace(
- RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *([,\\n])", 'g'), "$1'$2"
- );
+ // replace `_.keys` with `shimKeys`
+ if (!isRemoved(source, 'keys')) {
+ source = source.replace(
+ matchFunction(source, 'keys').replace(/[\s\S]+?var keys *=/, ''),
+ matchFunction(source, 'shimKeys').replace(/[\s\S]+?var shimKeys *=/, '')
+ );
- source = source.replace(
- RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *\\+", 'g'), "$1;\\n'+"
- );
-
- // remove `isArguments` fallback before `isArguments` is transformed by
- // other parts of the build process
- if (isRemoved(source, 'isArguments')) {
- source = removeIsArgumentsFallback(source);
- }
- // DRY out isType functions
- (function() {
- var iteratorName = _.find(['forEach', 'forOwn'], function(methodName) {
- return !isRemoved(source, methodName);
- });
-
- // skip this optimization if there are no iteration methods to use
- if (!iteratorName) {
- return;
- }
- var funcNames = [],
- objectSnippets = [];
-
- // build replacement code
- _.forOwn({
- 'Arguments': 'argsClass',
- 'Date': 'dateClass',
- 'Number': 'numberClass',
- 'RegExp': 'regexpClass',
- 'String': 'stringClass'
- },
- function(value, key) {
- if (!isUnderscore && key == 'Arguments') {
- return;
+ source = removeFunction(source, 'shimKeys');
}
- var funcName = 'is' + key,
- funcCode = matchFunction(source, funcName);
-
- if (funcCode) {
- funcNames.push(funcName);
- objectSnippets.push("'" + key + "': " + value);
+ // replace `_.isArguments` with fallback
+ if (!isRemoved(source, 'isArguments')) {
+ source = source.replace(
+ matchFunction(source, 'isArguments').replace(/[\s\S]+?function isArguments/, ''),
+ getIsArgumentsFallback(source).match(/isArguments *= *function([\s\S]+?) *};/)[1] + ' }\n'
+ );
+
+ source = removeIsArgumentsFallback(source);
}
- });
- // skip this optimization if there are less than 2 isType functions
- if (funcNames.length < 2) {
- return;
+ source = removeVar(source, 'reNative');
+ source = removeFromCreateIterator(source, 'nativeKeys');
}
- // remove existing isType functions
- funcNames.forEach(function(funcName) {
- source = removeFunction(source, funcName);
- });
-
- // insert new DRY code after the method assignments
- var snippet = getMethodAssignments(source);
- source = source.replace(snippet, snippet + '\n' +
- ' // add `_.' + funcNames.join('`, `_.') + '`\n' +
- ' ' + iteratorName + '({\n ' + objectSnippets.join(',\n ') + '\n }, function(className, key) {\n' +
- " lodash['is' + key] = function(value) {\n" +
- ' return toString.call(value) == className;\n' +
- ' };\n' +
- ' });\n'
- );
- }());
+ if (isMobile) {
+ // inline all functions defined with `createIterator`
+ _.functions(lodash).forEach(function(methodName) {
+ // match `methodName` with pseudo private `_` prefixes removed to allow matching `shimKeys`
+ var reFunc = RegExp('(\\bvar ' + methodName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n');
+
+ // skip if not defined with `createIterator`
+ if (!reFunc.test(source)) {
+ return;
+ }
+ // extract, format, and inject the compiled function's source code
+ source = source.replace(reFunc, '$1' + getFunctionSource(lodash[methodName]) + ';\n');
+ });
- /*------------------------------------------------------------------------*/
+ // replace `callee` in `_.merge` with `merge`
+ source = source.replace(matchFunction(source, 'merge'), function(match) {
+ return match.replace(/\bcallee\b/g, 'merge');
+ });
- if (isLegacy) {
- ['isBindFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'].forEach(function(varName) {
- source = removeVar(source, varName);
- });
+ if (isUnderscore) {
+ (function() {
+ // replace `isArguments` and its fallback
+ var snippet = matchFunction(source, 'isArguments')
+ .replace(/function isArguments/, 'lodash.isArguments = function');
- ['bind', 'isArray'].forEach(function(methodName) {
- var snippet = matchFunction(source, methodName),
- modified = snippet;
+ source = removeFunction(source, 'isArguments');
- // remove native `Function#bind` branch in `_.bind`
- if (methodName == 'bind') {
- modified = modified.replace(/(?:\s*\/\/.*)*\s*else if *\(isBindFast[^}]+}/, '');
+ source = source.replace(getIsArgumentsFallback(source), function(match) {
+ return snippet + '\n' + match
+ .replace(/\bisArguments\b/g, 'lodash.$&')
+ .replace(/\bnoArgsClass\b/g, '!lodash.isArguments(arguments)');
+ });
+ }());
}
- // remove native `Array.isArray` branch in `_.isArray`
else {
- modified = modified.replace(/nativeIsArray * \|\|/, '');
+ source = removeIsArgumentsFallback(source);
}
- source = source.replace(snippet, modified);
- });
- // replace `_.keys` with `shimKeys`
- if (!isRemoved(source, 'keys')) {
- source = source.replace(
- matchFunction(source, 'keys').replace(/[\s\S]+?var keys *=/, ''),
- matchFunction(source, 'shimKeys').replace(/[\s\S]+?var shimKeys *=/, '')
- );
+ // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment
+ source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, '');
- source = removeFunction(source, 'shimKeys');
- }
- // replace `_.isArguments` with fallback
- if (!isRemoved(source, 'isArguments')) {
- source = source.replace(
- matchFunction(source, 'isArguments').replace(/[\s\S]+?function isArguments/, ''),
- getIsArgumentsFallback(source).match(/isArguments *= *function([\s\S]+?) *};/)[1] + ' }\n'
- );
-
- source = removeIsArgumentsFallback(source);
- }
+ // remove `iteratesOwnLast` from `isPlainObject`
+ source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, '');
- source = removeVar(source, 'reNative');
- source = removeFromCreateIterator(source, 'nativeKeys');
- }
+ // remove JScript [[DontEnum]] fix from `_.isEqual`
+ source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, '');
- if (isMobile) {
- // inline all functions defined with `createIterator`
- _.functions(lodash).forEach(function(methodName) {
- // match `methodName` with pseudo private `_` prefixes removed to allow matching `shimKeys`
- var reFunc = RegExp('(\\bvar ' + methodName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n');
+ // remove `hasObjectSpliceBug` fix from the mutator Array functions mixin
+ source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, '');
- // skip if not defined with `createIterator`
- if (!reFunc.test(source)) {
- return;
- }
- // extract, format, and inject the compiled function's source code
- source = source.replace(reFunc, '$1' + getFunctionSource(lodash[methodName]) + ';\n');
- });
+ // remove `noArraySliceOnStrings` from `_.toArray`
+ source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1');
- // replace `callee` in `_.merge` with `merge`
- source = source.replace(matchFunction(source, 'merge'), function(match) {
- return match.replace(/\bcallee\b/g, 'merge');
- });
+ // remove `noCharByIndex` from `_.reduceRight`
+ source = source.replace(/}\s*else if *\(noCharByIndex[^}]+/, '');
- if (!isUnderscore) {
- source = removeIsArgumentsFallback(source);
+ source = removeVar(source, 'extendIteratorOptions');
+ source = removeVar(source, 'iteratorTemplate');
+ source = removeVar(source, 'noArraySliceOnStrings');
+ source = removeVar(source, 'noCharByIndex');
source = removeNoArgsClass(source);
+ source = removeNoNodeClass(source);
}
+ else {
+ // inline `iteratorTemplate` template
+ source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() {
+ var snippet = getFunctionSource(lodash._iteratorTemplate);
+
+ // prepend data object references to property names to avoid having to
+ // use a with-statement
+ iteratorOptions.forEach(function(property) {
+ snippet = snippet.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property);
+ });
- // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, '');
-
- // remove `iteratesOwnLast` from `isPlainObject`
- source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, '');
-
- // remove JScript [[DontEnum]] fix from `_.isEqual`
- source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, '');
-
- // remove `hasObjectSpliceBug` fix from the mutator Array functions mixin
- source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, '');
-
- // remove `noArraySliceOnStrings` from `_.toArray`
- source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1');
-
- // remove `noCharByIndex` from `_.reduceRight`
- source = source.replace(/noCharByIndex *&&[^:]+: *([^;]+)/g, '$1');
-
- source = removeVar(source, 'extendIteratorOptions');
- source = removeVar(source, 'iteratorTemplate');
- source = removeVar(source, 'noArraySliceOnStrings');
- source = removeVar(source, 'noCharByIndex');
- source = removeNoNodeClass(source);
- }
- else {
- // inline `iteratorTemplate` template
- source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() {
- var snippet = getFunctionSource(lodash._iteratorTemplate);
-
- // prepend data object references to property names to avoid having to
- // use a with-statement
- iteratorOptions.forEach(function(property) {
- snippet = snippet.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property);
- });
-
- // remove unnecessary code
- snippet = snippet
- .replace(/var __t.+/, "var __p = '';")
- .replace(/function print[^}]+}/, '')
- .replace(/'(?:\\n|\s)+'/g, "''")
- .replace(/__p *\+= *' *';/g, '')
- .replace(/(__p *\+= *)' *' *\+/g, '$1')
- .replace(/(\{) *;|; *(\})/g, '$1$2')
- .replace(/\(\(__t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__t\)/g, '$1');
-
- // remove the with-statement
- snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1');
-
- // minor cleanup
- snippet = snippet
- .replace(/obj *\|\| *\(obj *= *\{}\);/, '')
- .replace(/var __p = '';\s*__p \+=/, 'var __p =');
-
- // remove comments, including sourceURLs
- snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, '');
-
- return '$1' + snippet + ';\n';
- }()));
+ // remove unnecessary code
+ snippet = snippet
+ .replace(/var __t.+/, "var __p = '';")
+ .replace(/function print[^}]+}/, '')
+ .replace(/'(?:\\n|\s)+'/g, "''")
+ .replace(/__p *\+= *' *';/g, '')
+ .replace(/(__p *\+= *)' *' *\+/g, '$1')
+ .replace(/(\{) *;|; *(\})/g, '$1$2')
+ .replace(/\(\(__t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__t\)/g, '$1');
+
+ // remove the with-statement
+ snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1');
+
+ // minor cleanup
+ snippet = snippet
+ .replace(/obj *\|\| *\(obj *= *\{}\);/, '')
+ .replace(/var __p = '';\s*__p \+=/, 'var __p =');
+
+ // remove comments, including sourceURLs
+ snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, '');
+
+ return '$1' + snippet + ';\n';
+ }()));
+ }
}
/*------------------------------------------------------------------------*/
- // customize Lo-Dash's export bootstrap
- if (exportsOptions.indexOf('amd') == -1) {
- source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +define[\s\S]+?else /, '$1');
- }
- if (exportsOptions.indexOf('node') == -1) {
- source = source.replace(/(?: *\/\/.*\n)* *if *\(typeof +module[\s\S]+?else *{\n([\s\S]+?) *}\n/, '$1');
- }
- if (exportsOptions.indexOf('commonjs') == -1) {
- source = source.replace(/(?: *\/\/.*\n)*(?:( +)else *{)?\s*freeExports\._ *=.+(\n\1})?\n/, '');
- }
- if (exportsOptions.indexOf('global') == -1) {
- source = source.replace(/(?:( +)else *{)?(?:\s*\/\/.*)*\s*window\._ *= *lodash.+(\n\1})?\n/g, '');
- }
-
- // remove `if (freeExports) {...}` if it's empty
- source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports\) *{\s*}(?:\s*else *{\n([\s\S]+?) *})?/, '$1');
-
- /*------------------------------------------------------------------------*/
-
// customize Lo-Dash's IIFE
(function() {
- if (iife) {
+ if (typeof iife == 'string') {
var token = '%output%',
index = iife.indexOf(token);
source = source.match(/\/\*![\s\S]+?\*\/\n/) +
iife.slice(0, index) +
- source.replace(/^[^(]+?\(function[^{]+?{|}\(this\)\)[;\s]*$/g, '') +
+ source.replace(/^[\s\S]+?\(function[^{]+?{|}\(this\)\)[;\s]*$/g, '') +
iife.slice(index + token.length);
}
}());
/*------------------------------------------------------------------------*/
- // modify/remove references to removed methods/variables
- if (isRemoved(source, 'isArguments')) {
- source = replaceVar(source, 'noArgsClass', 'false');
- }
- if (isRemoved(source, 'isFunction')) {
- source = removeIsFunctionFallback(source);
- }
- if (isRemoved(source, 'mixin')) {
- // remove `LoDash` constructor
- source = removeFunction(source, 'LoDash');
- // remove `LoDash` calls
- source = source.replace(/(?:new +LoDash(?!\()|(?:new +)?LoDash\([^)]*\));?/g, '');
- // remove `LoDash.prototype` additions
- source = source.replace(/(?:\s*\/\/.*)*\s*LoDash.prototype *=[\s\S]+?\/\*-+\*\//, '');
- // remove `hasObjectSpliceBug` assignment
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasObjectSpliceBug;|.+?hasObjectSpliceBug *=.+/g, '');
- }
+ // customize Lo-Dash's export bootstrap
+ (function() {
+ var isAMD = exportsOptions.indexOf('amd') > -1,
+ isCommonJS = exportsOptions.indexOf('commonjs') > -1,
+ isGlobal = exportsOptions.indexOf('global') > -1,
+ isNode = exportsOptions.indexOf('node') > -1;
- // remove pseudo private properties
- source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n');
+ if (!isAMD) {
+ source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +define[\s\S]+?else /, '$1');
+ }
+ if (!isNode) {
+ source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +module[\s\S]+?else *{([\s\S]+?\n)\1}\n/, '$1$2');
+ }
+ if (!isCommonJS) {
+ source = source.replace(/(?: *\/\/.*\n)*(?:( +)else *{)?\s*freeExports\.\w+ *=[\s\S]+?(?:\n\1})?\n/, '');
+ }
+ if (!isGlobal) {
+ source = source.replace(/(?:( +)(})? *else(?: *if *\(_\))? *{)?(?:\s*\/\/.*)*\s*(?:window\._|_\.templates) *=[\s\S]+?(?:\n\1})?\n/g, '$1$2\n');
+ }
+ // remove `if (freeExports) {...}` if it's empty
+ if (isAMD && isGlobal) {
+ source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports\) *{\s*}\n/, '');
+ } else {
+ source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports\) *{\s*}(?:\s*else *{([\s\S]+?) *})?\n/, '$1');
+ }
- // assign debug source before further modifications that rely on the minifier
- // to remove unused variables and other dead code
- debugSource = source;
+ if ((source.match(/\bfreeExports\b/g) || []).length < 2) {
+ source = removeVar(source, 'freeExports');
+ }
+ }());
- // remove associated functions, variables, and code snippets that the minifier may miss
- if (isRemoved(source, 'clone')) {
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var cloneableClasses *=[\s\S]+?true;\n/g, '');
- }
- if (isRemoved(source, 'isArray')) {
- source = removeVar(source, 'nativeIsArray');
- }
- if (isRemoved(source, 'keys')) {
- source = removeFunction(source, 'shimKeys');
- }
- if (isRemoved(source, 'template')) {
- // remove `templateSettings` assignment
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, '');
- }
- if (isRemoved(source, 'toArray')) {
- source = removeVar(source, 'noArraySliceOnStrings');
- }
- if (isUnderscore
- ? isRemoved(source, 'merge')
- : isRemoved(source, 'clone', 'merge')
- ) {
- source = removeFunction(source, 'isPlainObject');
- }
- if (isRemoved(source, 'clone', 'isArguments', 'isEmpty', 'isEqual')) {
- source = removeNoArgsClass(source);
- }
- if (isRemoved(source, 'isEqual', 'isPlainObject')) {
- source = removeNoNodeClass(source);
- }
- if ((source.match(/\bcreateIterator\b/g) || []).length < 2) {
- source = removeFunction(source, 'createIterator');
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var noArgsEnum;|.+?noArgsEnum *=.+/g, '');
- }
- if (isRemoved(source, 'createIterator', 'bind')) {
- source = removeVar(source, 'isBindFast');
- source = removeVar(source, 'isStrictFast');
- source = removeVar(source, 'nativeBind');
- }
- if (isRemoved(source, 'createIterator', 'bind', 'isArray', 'keys')) {
- source = removeVar(source, 'reNative');
- }
- if (isRemoved(source, 'createIterator', 'isEmpty', 'isEqual')) {
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var arrayLikeClasses *=[\s\S]+?true;\n/g, '');
- }
- if (isRemoved(source, 'createIterator', 'isEqual')) {
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug;|.+?hasDontEnumBug *=.+/g, '');
- }
- if (isRemoved(source, 'createIterator', 'isPlainObject')) {
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast;|.+?iteratesOwnLast *=.+/g, '');
- }
- if (isRemoved(source, 'createIterator', 'keys')) {
- source = removeVar(source, 'nativeKeys');
- }
- if (!source.match(/var (?:hasDontEnumBug|hasObjectSpliceBug|iteratesOwnLast|noArgsEnum)\b/g)) {
- // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, and `noArgsEnum` assignment
- source = source.replace(/ *\(function\(\) *{[\s\S]+?}\(1\)\);/, '');
+ /*------------------------------------------------------------------------*/
+
+ if (isTemplate) {
+ debugSource = source;
}
+ else {
+ // modify/remove references to removed methods/variables
+ if (isRemoved(source, 'invert')) {
+ source = replaceVar(source, 'htmlUnescapes', "{'&':'&','<':'<','>':'>','"':'\"',''':\"'\"}");
+ }
+ if (isRemoved(source, 'isArguments')) {
+ source = replaceVar(source, 'noArgsClass', 'false');
+ }
+ if (isRemoved(source, 'isFunction')) {
+ source = removeIsFunctionFallback(source);
+ }
+ if (isRemoved(source, 'mixin')) {
+ // remove `lodash.prototype` additions
+ source = source.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\)[\s\S]+?\/\*-+\*\//, '');
+ // remove `hasObjectSpliceBug` assignment
+ source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasObjectSpliceBug;|.+?hasObjectSpliceBug *=.+/g, '');
+ }
+
+ // remove pseudo private properties
+ source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n');
- debugSource = cleanupSource(debugSource);
- source = cleanupSource(source);
+ // assign debug source before further modifications that rely on the minifier
+ // to remove unused variables and other dead code
+ debugSource = source;
+
+ // remove associated functions, variables, and code snippets that the minifier may miss
+ if (isRemoved(source, 'clone')) {
+ source = removeVar(source, 'cloneableClasses');
+ }
+ if (isRemoved(source, 'isArray')) {
+ source = removeVar(source, 'nativeIsArray');
+ }
+ if (isRemoved(source, 'isPlainObject')) {
+ source = removeVar(source, 'nativeGetPrototypeOf');
+ }
+ if (isRemoved(source, 'keys')) {
+ source = removeFunction(source, 'shimKeys');
+ }
+ if (isRemoved(source, 'template')) {
+ // remove `templateSettings` assignment
+ source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, '');
+ }
+ if (isRemoved(source, 'toArray')) {
+ source = removeVar(source, 'noArraySliceOnStrings');
+ }
+ if (isRemoved(source, 'clone', 'isArguments', 'isEmpty', 'isEqual')) {
+ source = removeNoArgsClass(source);
+ }
+ if (isRemoved(source, 'isEqual', 'isPlainObject')) {
+ source = removeNoNodeClass(source);
+ }
+ if ((source.match(/\bcreateIterator\b/g) || []).length < 2) {
+ source = removeFunction(source, 'createIterator');
+ source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var noArgsEnum;|.+?noArgsEnum *=.+/g, '');
+ }
+ if (isRemoved(source, 'createIterator', 'bind')) {
+ source = removeVar(source, 'isBindFast');
+ source = removeVar(source, 'isStrictFast');
+ source = removeVar(source, 'nativeBind');
+ }
+ if (isRemoved(source, 'createIterator', 'bind', 'isArray', 'isPlainObject', 'keys')) {
+ source = removeVar(source, 'reNative');
+ }
+ if (isRemoved(source, 'createIterator', 'isEmpty', 'isEqual')) {
+ source = removeVar(source, 'arrayLikeClasses');
+ }
+ if (isRemoved(source, 'createIterator', 'isEqual')) {
+ source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug;|.+?hasDontEnumBug *=.+/g, '');
+ }
+ if (isRemoved(source, 'createIterator', 'isPlainObject')) {
+ source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast;|.+?iteratesOwnLast *=.+/g, '');
+ }
+ if (isRemoved(source, 'createIterator', 'keys')) {
+ source = removeVar(source, 'nativeKeys');
+ source = removeKeysOptimization(source);
+ }
+ if (!source.match(/var (?:hasDontEnumBug|hasObjectSpliceBug|iteratesOwnLast|noArgsEnum)\b/g)) {
+ // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, and `noArgsEnum` assignment
+ source = source.replace(/ *\(function\(\) *{[\s\S]+?}\(1\)\);/, '');
+ }
+ }
/*------------------------------------------------------------------------*/
// used to specify creating a custom build
- var isCustom = !_.isEqual(exportsOptions, exportsAll) || filterType || iife || isBackbone || isLegacy || isMobile || isStrict || isUnderscore;
+ var isCustom = isBackbone || isLegacy || isMobile || isStrict || isUnderscore ||
+ /(?:category|exclude|exports|iife|include|minus|plus)=/.test(options) ||
+ !_.isEqual(exportsOptions, exportsAll);
- // used to specify the output path for builds
- var outputPath = options.reduce(function(result, value, index) {
- return result || (/^(?:-o|--output)$/.test(value) ? options[index + 1] : result);
- }, '');
+ // used as the basename of the output path
+ var basename = outputPath
+ ? path.basename(outputPath, '.js')
+ : 'lodash' + (isTemplate ? '.template' : isCustom ? '.custom' : '');
- // used to name temporary files created in `dist/`
- var workingName = 'lodash' + (isCustom ? '.custom' : '') + '.min';
+ // restore `dependencyMap`
+ dependencyMap = dependencyBackup;
// output debug build
- if (isCustom && !outputPath && !isStdOut) {
- callback(debugSource, path.join(cwd, 'lodash.custom.js'));
+ if (!isMinify && (isCustom || isDebug || isTemplate)) {
+ if (isDebug && isStdOut) {
+ stdout.write(debugSource);
+ callback(debugSource);
+ } else if (!isStdOut) {
+ callback(debugSource, (isDebug && outputPath) || path.join(cwd, basename + '.js'));
+ }
}
// begin the minification process
- minify(source, {
- 'silent': isSilent,
- 'workingName': workingName,
- 'onComplete': function(source) {
- // correct overly aggressive Closure Compiler minification
- source = source.replace(/prototype\s*=\s*{\s*valueOf\s*:\s*1\s*}/, 'prototype={valueOf:1,y:1}');
-
- // inject "use strict" directive
- if (isStrict) {
- source = source.replace(/^(\/\*![\s\S]+?\*\/\n;\(function[^)]+\){)([^'"])/, '$1"use strict";$2');
- }
- if (isStdOut) {
- stdout.write(source);
- callback(source);
- } else {
- callback(source, outputPath || path.join(cwd, workingName + '.js'));
+ if (!isDebug) {
+ outputPath || (outputPath = path.join(cwd, basename + '.min.js'));
+
+ minify(source, {
+ 'isSilent': isSilent,
+ 'isTemplate': isTemplate,
+ 'outputPath': outputPath,
+ 'onComplete': function(source) {
+ // correct overly aggressive Closure Compiler minification
+ source = source.replace(/prototype\s*=\s*{\s*valueOf\s*:\s*1\s*}/, 'prototype={valueOf:1,y:1}');
+
+ // inject "use strict" directive
+ if (isStrict) {
+ source = source.replace(/^(\/\*![\s\S]+?\*\/\n;\(function[^)]+\){)([^'"])/, '$1"use strict";$2');
+ }
+ if (isStdOut) {
+ stdout.write(source);
+ callback(source);
+ } else {
+ callback(source, outputPath);
+ }
}
- }
- });
+ });
+ }
}
/*--------------------------------------------------------------------------*/
@@ -1337,8 +1474,8 @@
}
else {
// or invoked directly
- build(process.argv, function(source, filepath) {
- filepath && fs.writeFileSync(filepath, source, 'utf8');
+ build(process.argv, function(source, filePath) {
+ filePath && fs.writeFileSync(filePath, source, 'utf8');
});
}
}());
diff --git a/build/minify.js b/build/minify.js
index b04571a965..3fede079b5 100755
--- a/build/minify.js
+++ b/build/minify.js
@@ -9,18 +9,15 @@
spawn = require('child_process').spawn;
/** The directory that is the base of the repository */
- var basePath = path.join(__dirname, '../');
+ var basePath = fs.realpathSync(path.join(__dirname, '..'));
/** The directory where the Closure Compiler is located */
var closurePath = path.join(basePath, 'vendor', 'closure-compiler', 'compiler.jar');
- /** The distribution directory */
- var distPath = path.join(basePath, 'dist');
-
/** Load other modules */
- var preprocess = require(path.join(__dirname, 'pre-compile')),
- postprocess = require(path.join(__dirname, 'post-compile')),
- uglifyJS = require(path.join(basePath, 'vendor', 'uglifyjs', 'uglify-js'));
+ var preprocess = require('./pre-compile'),
+ postprocess = require('./post-compile'),
+ uglifyJS = require('../vendor/uglifyjs/uglify-js');
/** Closure Compiler command-line options */
var closureOptions = [
@@ -37,31 +34,38 @@
* The exposed `minify` function minifies a given Lo-Dash `source` and invokes
* the `onComplete` callback when finished.
*
- * @param {Array|String} source The array of command-line arguments or the
- * source to minify.
- * @param {Object} options The options object containing `onComplete`,
- * `silent`, and `workingName`.
+ * @param {Array|String} [source=''] The source to minify or array of commands.
+ * @param {Object} [options={}] The options object.
*/
function minify(source, options) {
+ source || (source = '');
options || (options = {});
+ // juggle arguments
if (Array.isArray(source)) {
- // convert the command-line arguments to an options object
+ // convert commands to an options object
options = source;
+
var filePath = options[options.length - 1],
- dirPath = path.dirname(filePath),
- workingName = path.basename(filePath, '.js') + '.min',
- outputPath = path.join(dirPath, workingName + '.js'),
- isSilent = options.indexOf('-s') > -1 || options.indexOf('--silent') > -1;
+ isSilent = options.indexOf('-s') > -1 || options.indexOf('--silent') > -1,
+ isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1,
+ outputPath = path.join(path.dirname(filePath), path.basename(filePath, '.js') + '.min.js');
+
+ outputPath = options.reduce(function(result, value, index) {
+ if (/-o|--output/.test(value)) {
+ result = options[index + 1];
+ result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result));
+ }
+ return result;
+ }, outputPath);
- source = fs.readFileSync(filePath, 'utf8');
options = {
- 'silent': isSilent,
- 'workingName': workingName,
- 'onComplete': function(source) {
- fs.writeFileSync(outputPath, source, 'utf8');
- }
+ 'isSilent': isSilent,
+ 'isTemplate': isTemplate,
+ 'outputPath': outputPath
};
+
+ source = fs.readFileSync(filePath, 'utf8');
}
new Minify(source, options);
}
@@ -72,35 +76,28 @@
* @private
* @constructor
* @param {String} source The source to minify.
- * @param {Object} options The options object containing `onComplete`,
- * `silent`, and `workingName`.
+ * @param {Object} options The options object.
*/
function Minify(source, options) {
- source || (source = '');
- options || (options = {});
-
- if (typeof source != 'string') {
+ // juggle arguments
+ if (typeof source == 'object' && source) {
options = source || options;
source = options.source || '';
}
- // create the destination directory if it doesn't exist
- if (!fs.existsSync(distPath)) {
- // avoid errors when called as a npm executable
- try {
- fs.mkdirSync(distPath);
- } catch(e) { }
- }
-
this.compiled = {};
this.hybrid = {};
this.uglified = {};
- this.isSilent = !!options.silent;
- this.onComplete = options.onComplete || function() {};
- this.workingName = options.workingName || 'temp';
+ this.isSilent = !!options.isSilent;
+ this.isTemplate = !!options.isTemplate;
+ this.outputPath = options.outputPath;
- source = preprocess(source);
+ source = preprocess(source, options);
this.source = source;
+ this.onComplete = options.onComplete || function(source) {
+ fs.writeFileSync(this.outputPath, source, 'utf8');
+ };
+
// begin the minification process
closureCompile.call(this, source, onClosureCompile.bind(this));
}
@@ -117,10 +114,19 @@
* @param {Function} callback The function to call once the process completes.
*/
function closureCompile(source, message, callback) {
+ var options = closureOptions.slice();
+
+ // use simple optimizations when minifying template files
+ if (this.isTemplate) {
+ options = options.map(function(value) {
+ return value.replace(/^(compilation_level)=.+$/, '$1=SIMPLE_OPTIMIZATIONS');
+ });
+ }
+
// the standard error stream, standard output stream, and Closure Compiler process
var error = '',
output = '',
- compiler = spawn('java', ['-jar', closurePath].concat(closureOptions));
+ compiler = spawn('java', ['-jar', closurePath].concat(options));
// juggle arguments
if (typeof message == 'function') {
@@ -130,7 +136,7 @@
if (!this.isSilent) {
console.log(message == null
- ? 'Compressing ' + this.workingName + ' using the Closure Compiler...'
+ ? 'Compressing ' + path.basename(this.outputPath, '.js') + ' using the Closure Compiler...'
: message
);
}
@@ -183,7 +189,7 @@
if (!this.isSilent) {
console.log(message == null
- ? 'Compressing ' + this.workingName + ' using UglifyJS...'
+ ? 'Compressing ' + path.basename(this.outputPath, '.js') + ' using UglifyJS...'
: message
);
}
@@ -278,7 +284,7 @@
if (!this.isSilent) {
console.log('Done. Size: %d bytes.', result.length);
}
- var message = 'Compressing ' + this.workingName + ' using hybrid minification...';
+ var message = 'Compressing ' + path.basename(this.outputPath, '.js') + ' using hybrid minification...';
// store the gzipped result and report the size
this.uglified.gzip = result;
@@ -332,24 +338,8 @@
function onComplete() {
var compiled = this.compiled,
hybrid = this.hybrid,
- name = this.workingName,
uglified = this.uglified;
- // avoid errors when called as a npm executable
- try {
- // save the Closure Compiled version to disk
- fs.writeFileSync(path.join(distPath, name + '.compiler.js'), compiled.source);
- fs.writeFileSync(path.join(distPath, name + '.compiler.js.gz'), compiled.gzip);
-
- // save the Uglified version to disk
- fs.writeFileSync(path.join(distPath, name + '.uglify.js'), uglified.source);
- fs.writeFileSync(path.join(distPath, name + '.uglify.js.gz'), uglified.gzip);
-
- // save the hybrid minified version to disk
- fs.writeFileSync(path.join(distPath, name + '.hybrid.js'), hybrid.source);
- fs.writeFileSync(path.join(distPath, name + '.hybrid.js.gz'), hybrid.gzip);
- } catch(e) { }
-
// select the smallest gzipped file and use its minified counterpart as the
// official minified release (ties go to Closure Compiler)
var min = Math.min(compiled.gzip.length, hybrid.gzip.length, uglified.gzip.length);
diff --git a/build/post-compile.js b/build/post-compile.js
index 2b83991360..477fa6fd1d 100644
--- a/build/post-compile.js
+++ b/build/post-compile.js
@@ -10,10 +10,10 @@
'lodash':
'/*!\n' +
' Lo-Dash @VERSION lodash.com/license\n' +
- ' Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE\n' +
+ ' Underscore.js 1.4.0 underscorejs.org/LICENSE\n' +
'*/',
'underscore':
- '/*! Underscore.js @VERSION github.com/documentcloud/underscore/blob/master/LICENSE */'
+ '/*! Underscore.js @VERSION underscorejs.org/LICENSE */'
};
/*--------------------------------------------------------------------------*/
@@ -27,7 +27,7 @@
*/
function postprocess(source) {
// move vars exposed by Closure Compiler into the IIFE
- source = source.replace(/^([^(\n]+)\s*(\(function[^)]+\){)/, '$2$1');
+ source = source.replace(/^((?:(['"])use strict\2;)?(?:var (?:[a-z]+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^)]+\){)/, '$3$1');
// unescape properties (i.e. foo["bar"] => foo.bar)
source = source.replace(/(\w)\["([^."]+)"\]/g, function(match, left, right) {
@@ -56,13 +56,20 @@
// expose `postprocess`
if (module != require.main) {
module.exports = postprocess;
- } else {
+ }
+ else {
// read the Lo-Dash source file from the first argument if the script
// was invoked directly (e.g. `node post-compile.js source.js`) and write to
// the same file
(function() {
- var source = fs.readFileSync(process.argv[2], 'utf8');
- fs.writeFileSync(process.argv[2], postprocess(source), 'utf8');
+ var options = process.argv;
+ if (options.length < 3) {
+ return;
+ }
+ var filePath = options[options.length - 1],
+ source = fs.readFileSync(filePath, 'utf8');
+
+ fs.writeFileSync(filePath, postprocess(source), 'utf8');
}());
}
}());
diff --git a/build/pre-compile.js b/build/pre-compile.js
index 08e0bef5d4..924f684f95 100644
--- a/build/pre-compile.js
+++ b/build/pre-compile.js
@@ -12,12 +12,12 @@
'callback',
'collection',
'concat',
+ 'createCallback',
'ctor',
'hasOwnProperty',
'identity',
'index',
'iteratee',
- 'iteratorBind',
'length',
'nativeKeys',
'object',
@@ -33,6 +33,7 @@
'stringClass',
'thisArg',
'toString',
+ 'undefined',
'value',
// lesser used variables
@@ -44,7 +45,6 @@
'callee',
'className',
'compareAscending',
- 'data',
'forIn',
'found',
'funcs',
@@ -58,19 +58,18 @@
'isPlainObject',
'methodName',
'noaccum',
+ 'noop',
'objectClass',
'objectTypes',
'pass',
'properties',
'property',
'propsLength',
- 'recursive',
'source',
- 'sources',
+ 'stackA',
+ 'stackB',
'stackLength',
- 'target',
- 'valueProp',
- 'values'
+ 'target'
];
/** Used to minify `compileIterator` option properties */
@@ -80,7 +79,6 @@
'arrayBranch',
'beforeLoop',
'bottom',
- 'exit',
'firstArg',
'hasDontEnumBug',
'inLoop',
@@ -106,7 +104,6 @@
var propWhitelist = [
'_',
'__chain__',
- '__proto__',
'__wrapped__',
'after',
'all',
@@ -118,7 +115,6 @@
'chain',
'clearTimeout',
'clone',
- 'clones',
'collect',
'compact',
'compose',
@@ -177,12 +173,14 @@
'isNull',
'isNumber',
'isObject',
+ 'isPlainObject',
'isRegExp',
'isString',
'isUndefined',
'keys',
'last',
'lastIndexOf',
+ 'lateBind',
'map',
'max',
'memoize',
@@ -214,13 +212,11 @@
'sortBy',
'sortedIndex',
'source',
- 'sources',
- 'stackA',
- 'stackB',
'tail',
'take',
'tap',
'template',
+ 'templates',
'templateSettings',
'throttle',
'times',
@@ -249,16 +245,24 @@
/**
* Pre-process a given Lo-Dash `source`, preparing it for minification.
*
- * @param {String} source The source to process.
+ * @param {String} [source=''] The source to process.
+ * @param {Object} [options={}] The options object.
* @returns {String} Returns the processed source.
*/
- function preprocess(source) {
- // remove copyright to add later in post-compile.js
- source = source.replace(/\/\*![\s\S]+?\*\//, '');
+ function preprocess(source, options) {
+ source || (source = '');
+ options || (options = {});
// remove unrecognized JSDoc tags so Closure Compiler won't complain
source = source.replace(/@(?:alias|category)\b.*/g, '');
+ if (options.isTemplate) {
+ return source;
+ }
+
+ // remove copyright to add later in post-compile.js
+ source = source.replace(/\/\*![\s\S]+?\*\//, '');
+
// add brackets to whitelisted properties so Closure Compiler won't mung them
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']");
@@ -278,7 +282,7 @@
// remove whitespace from string literals
source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) {
// avoids removing the '\n' of the `stringEscapes` object
- return string.replace(/\[object |delete |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) {
+ return string.replace(/\[object |delete |else |function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) {
return match == false || match == '\\n' ? '' : match;
});
});
@@ -287,7 +291,7 @@
source = source.replace(/\+"__p\+='"/g, '+"\\n__p+=\'"');
// remove whitespace from `_.template` related regexes
- source = source.replace(/(?:reDelimiterCode\w+|reEmptyString\w+|reInsertVariable) *=.+/g, function(match) {
+ source = source.replace(/(?:reEmptyString\w+|reInsertVariable) *=.+/g, function(match) {
return match.replace(/ |\\n/g, '');
});
@@ -303,12 +307,12 @@
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *try *\{(?:\s*\/\/.*)*\n *var useSourceURL[\s\S]+?catch[^}]+}\n/, '');
// remove debug sourceURL use in `_.template`
- source = source.replace(/(?:\s*\/\/.*\n)* *if *\(useSourceURL[^}]+}/, '');
+ source = source.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, '');
- // minify internal properties used by 'compareAscending', `_.clone`, `_.isEqual`, `_.merge`, and `_.sortBy`
+ // minify internal properties used by 'compareAscending', `_.merge`, and `_.sortBy`
(function() {
- var properties = ['clones', 'criteria', 'index', 'sources', 'thorough', 'value', 'values'],
- snippets = source.match(/( +)(?:function (?:clone|compareAscending|isEqual)|var merge|var sortBy)\b[\s\S]+?\n\1}/g);
+ var properties = ['criteria', 'index', 'value'],
+ snippets = source.match(/( +)(?:function compareAscending|var merge|var sortBy)\b[\s\S]+?\n\1}/g);
if (!snippets) {
return;
@@ -443,8 +447,17 @@
// was invoked directly (e.g. `node pre-compile.js source.js`) and write to
// the same file
(function() {
- var source = fs.readFileSync(process.argv[2], 'utf8');
- fs.writeFileSync(process.argv[2], preprocess(source), 'utf8');
+ var options = process.argv;
+ if (options.length < 3) {
+ return;
+ }
+ var filePath = options[options.length - 1],
+ isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1,
+ source = fs.readFileSync(filePath, 'utf8');
+
+ fs.writeFileSync(filePath, preprocess(source, {
+ 'isTemplate': isTemplate
+ }), 'utf8');
}());
}
}());
diff --git a/component.json b/component.json
deleted file mode 100644
index 5fd89537ea..0000000000
--- a/component.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "name": "lodash",
- "version": "0.7.0",
- "description": "A drop-in replacement for Underscore.js delivering performance, bug fixes, and additional features.",
- "homepage": "http://lodash.com",
- "main": [
- "./lodash.js",
- "./lodash.min.js"
- ],
- "keywords": [
- "browser",
- "client",
- "functional",
- "performance",
- "server",
- "speed",
- "util"
- ],
- "licenses": [
- {
- "type": "MIT",
- "url": "http://lodash.com/license"
- }
- ],
- "author": {
- "name": "John-David Dalton",
- "email": "john.david.dalton@gmail.com",
- "web": "http://allyoucanleet.com/"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/bestiejs/lodash.git"
- }
-}
diff --git a/doc/README.md b/doc/README.md
index c48f6f141d..5a997081d6 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -1,4 +1,4 @@
-# Lo-Dash v0.7.0
+# Lo-Dash v0.8.0
@@ -14,7 +14,7 @@
* [`_.bind`](#_bindfunc--thisarg-arg1-arg2-)
* [`_.bindAll`](#_bindallobject--methodname1-methodname2-)
* [`_.chain`](#_chainvalue)
-* [`_.clone`](#_clonevalue-deep--guard-data)
+* [`_.clone`](#_clonevalue-deep)
* [`_.collect`](#_mapcollection--callbackidentity-thisarg)
* [`_.compact`](#_compactarray)
* [`_.compose`](#_composefunc1-func2-)
@@ -26,14 +26,14 @@
* [`_.delay`](#_delayfunc-wait--arg1-arg2-)
* [`_.detect`](#_findcollection-callback--thisarg)
* [`_.difference`](#_differencearray--array1-array2-)
-* [`_.drop`](#_restarray--n-guard)
+* [`_.drop`](#_restarray--n)
* [`_.each`](#_foreachcollection-callback--thisarg)
* [`_.escape`](#_escapestring)
* [`_.every`](#_everycollection--callbackidentity-thisarg)
* [`_.extend`](#_extendobject--source1-source2-)
* [`_.filter`](#_filtercollection--callbackidentity-thisarg)
* [`_.find`](#_findcollection-callback--thisarg)
-* [`_.first`](#_firstarray--n-guard)
+* [`_.first`](#_firstarray--n)
* [`_.flatten`](#_flattenarray-shallow)
* [`_.foldl`](#_reducecollection-callback--accumulator-thisarg)
* [`_.foldr`](#_reducerightcollection-callback--accumulator-thisarg)
@@ -43,11 +43,11 @@
* [`_.functions`](#_functionsobject)
* [`_.groupBy`](#_groupbycollection-callbackproperty--thisarg)
* [`_.has`](#_hasobject-property)
-* [`_.head`](#_firstarray--n-guard)
+* [`_.head`](#_firstarray--n)
* [`_.identity`](#_identityvalue)
* [`_.include`](#_containscollection-target)
* [`_.indexOf`](#_indexofarray-value--fromindex0)
-* [`_.initial`](#_initialarray--n-guard)
+* [`_.initial`](#_initialarray--n)
* [`_.inject`](#_reducecollection-callback--accumulator-thisarg)
* [`_.intersection`](#_intersectionarray1-array2-)
* [`_.invert`](#_invertobject)
@@ -58,23 +58,25 @@
* [`_.isDate`](#_isdatevalue)
* [`_.isElement`](#_iselementvalue)
* [`_.isEmpty`](#_isemptyvalue)
-* [`_.isEqual`](#_isequala-b--data)
+* [`_.isEqual`](#_isequala-b)
* [`_.isFinite`](#_isfinitevalue)
* [`_.isFunction`](#_isfunctionvalue)
* [`_.isNaN`](#_isnanvalue)
* [`_.isNull`](#_isnullvalue)
* [`_.isNumber`](#_isnumbervalue)
* [`_.isObject`](#_isobjectvalue)
+* [`_.isPlainObject`](#_isplainobjectvalue)
* [`_.isRegExp`](#_isregexpvalue)
* [`_.isString`](#_isstringvalue)
* [`_.isUndefined`](#_isundefinedvalue)
* [`_.keys`](#_keysobject)
-* [`_.last`](#_lastarray--n-guard)
+* [`_.last`](#_lastarray--n)
* [`_.lastIndexOf`](#_lastindexofarray-value--fromindexarraylength-1)
+* [`_.lateBind`](#_latebindobject-methodname--arg1-arg2-)
* [`_.map`](#_mapcollection--callbackidentity-thisarg)
* [`_.max`](#_maxarray--callback-thisarg)
* [`_.memoize`](#_memoizefunc--resolver)
-* [`_.merge`](#_mergeobject--source1-source2--indicator-data)
+* [`_.merge`](#_mergeobject--source1-source2-)
* [`_.methods`](#_functionsobject)
* [`_.min`](#_minarray--callback-thisarg)
* [`_.mixin`](#_mixinobject)
@@ -86,21 +88,21 @@
* [`_.partial`](#_partialfunc--arg1-arg2-)
* [`_.pick`](#_pickobject-callback-prop1-prop2--thisarg)
* [`_.pluck`](#_pluckcollection-property)
-* [`_.random`](#_randommin-max)
+* [`_.random`](#_randommin0-max1)
* [`_.range`](#_rangestart0-end--step1)
* [`_.reduce`](#_reducecollection-callback--accumulator-thisarg)
* [`_.reduceRight`](#_reducerightcollection-callback--accumulator-thisarg)
* [`_.reject`](#_rejectcollection--callbackidentity-thisarg)
-* [`_.rest`](#_restarray--n-guard)
+* [`_.rest`](#_restarray--n)
* [`_.result`](#_resultobject-property)
* [`_.select`](#_filtercollection--callbackidentity-thisarg)
* [`_.shuffle`](#_shufflearray)
* [`_.size`](#_sizecollection)
* [`_.some`](#_somecollection--callbackidentity-thisarg)
* [`_.sortBy`](#_sortbycollection-callbackproperty--thisarg)
-* [`_.sortedIndex`](#_sortedindexarray-value--callbackidentity-thisarg)
-* [`_.tail`](#_restarray--n-guard)
-* [`_.take`](#_firstarray--n-guard)
+* [`_.sortedIndex`](#_sortedindexarray-value--callbackidentityproperty-thisarg)
+* [`_.tail`](#_restarray--n)
+* [`_.take`](#_firstarray--n)
* [`_.tap`](#_tapvalue-interceptor)
* [`_.template`](#_templatetext-data-options)
* [`_.throttle`](#_throttlefunc-wait)
@@ -154,15 +156,15 @@
### `_(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L297 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L241 "View in source") [Ⓣ][1]
The `lodash` function.
#### Arguments
-1. `value` *(Mixed)*: The value to wrap in a `LoDash` instance.
+1. `value` *(Mixed)*: The value to wrap in a `lodash` instance.
#### Returns
-*(Object)*: Returns a `LoDash` instance.
+*(Object)*: Returns a `lodash` instance.
* * *
@@ -172,7 +174,7 @@ The `lodash` function.
### `_.VERSION`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4260 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3993 "View in source") [Ⓣ][1]
*(String)*: The semantic version number.
@@ -184,9 +186,9 @@ The `lodash` function.
### `_.after(n, func)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3297 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3100 "View in source") [Ⓣ][1]
-Creates a new function that is restricted to executing only after it is called `n` times.
+Creates a function that is restricted to executing only after it is called `n` times.
#### Arguments
1. `n` *(Number)*: The number of times the function must be called before it is executed.
@@ -212,13 +214,13 @@ _.forEach(notes, function(note) {
### `_.bind(func [, thisArg, arg1, arg2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3351 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3133 "View in source") [Ⓣ][1]
-Creates a new function that, when called, invokes `func` with the `this` binding of `thisArg` and prepends any additional `bind` arguments to those passed to the bound function. Lazy defined methods may be bound by passing the object they are bound to as `func` and the method name as `thisArg`.
+Creates a function that, when called, invokes `func` with the `this` binding of `thisArg` and prepends any additional `bind` arguments to those passed to the bound function.
#### Arguments
-1. `func` *(Function|Object)*: The function to bind or the object the method belongs to.
-2. `[thisArg]` *(Mixed)*: The `this` binding of `func` or the method name.
+1. `func` *(Function)*: The function to bind.
+2. `[thisArg]` *(Mixed)*: The `this` binding of `func`.
3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to be partially applied.
#### Returns
@@ -226,7 +228,6 @@ Creates a new function that, when called, invokes `func` with the `this` binding
#### Example
```js
-// basic bind
var func = function(greeting) {
return greeting + ' ' + this.name;
};
@@ -234,25 +235,6 @@ var func = function(greeting) {
func = _.bind(func, { 'name': 'moe' }, 'hi');
func();
// => 'hi moe'
-
-// lazy bind
-var object = {
- 'name': 'moe',
- 'greet': function(greeting) {
- return greeting + ' ' + this.name;
- }
-};
-
-var func = _.bind(object, 'greet', 'hi');
-func();
-// => 'hi moe'
-
-object.greet = function(greeting) {
- return greeting + ', ' + this.name + '!';
-};
-
-func();
-// => 'hi, moe!'
```
* * *
@@ -263,7 +245,7 @@ func();
### `_.bindAll(object [, methodName1, methodName2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3421 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3163 "View in source") [Ⓣ][1]
Binds methods on `object` to `object`, overwriting the existing method. If no method names are provided, all the function properties of `object` will be bound.
@@ -294,7 +276,7 @@ jQuery('#lodash_button').on('click', buttonView.onClick);
### `_.chain(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4185 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3918 "View in source") [Ⓣ][1]
Wraps the value in a `lodash` wrapper object.
@@ -327,16 +309,14 @@ var youngest = _.chain(stooges)
-### `_.clone(value, deep [, guard, data={}])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1089 "View in source") [Ⓣ][1]
+### `_.clone(value, deep)`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1045 "View in source") [Ⓣ][1]
-Creates a clone of `value`. If `deep` is `true`, all nested objects will also be cloned otherwise they will be assigned by reference. If a value has a `clone` method it will be used to perform the clone. Functions, DOM nodes, `arguments` objects, and objects created by constructors other than `Object` are **not** cloned unless they have a custom `clone` method.
+Creates a clone of `value`. If `deep` is `true`, all nested objects will also be cloned otherwise they will be assigned by reference. Functions, DOM nodes, `arguments` objects, and objects created by constructors other than `Object` are **not** cloned.
#### Arguments
1. `value` *(Mixed)*: The value to clone.
2. `deep` *(Boolean)*: A flag to indicate a deep clone.
-3. `[guard]` *(Object)*: Internally used to allow this method to work with others like `_.map` without using their callback `index` argument for `deep`.
-4. `[data={}]` *(Object)*: Internally used to track traversed objects to avoid circular references and indicate whether to perform a more thorough clone of non-object values.
#### Returns
*(Mixed)*: Returns the cloned `value`.
@@ -369,9 +349,9 @@ shallow[0] === stooges[0];
### `_.compact(array)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2529 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2412 "View in source") [Ⓣ][1]
-Creates a new array with all falsey values of `array` removed. The values `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.
+Creates an array with all falsey values of `array` removed. The values `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.
#### Arguments
1. `array` *(Array)*: The array to compact.
@@ -393,9 +373,9 @@ _.compact([0, 1, false, 2, '', 3]);
### `_.compose([func1, func2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3459 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3200 "View in source") [Ⓣ][1]
-Creates a new function that is the composition of the passed functions, where each function consumes the return value of the function that follows. In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
+Creates a function that is the composition of the passed functions, where each function consumes the return value of the function that follows. In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
#### Arguments
1. `[func1, func2, ...]` *(Function)*: Functions to compose.
@@ -420,7 +400,7 @@ welcome('moe');
### `_.contains(collection, target)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1985 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1894 "View in source") [Ⓣ][1]
Checks if a given `target` element is present in a `collection` using strict equality for comparisons, i.e. `===`.
@@ -454,14 +434,14 @@ _.contains('curly', 'ur');
### `_.countBy(collection, callback|property [, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2021 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1930 "View in source") [Ⓣ][1]
-Creates an object composed of keys returned from running each element of `collection` through a `callback`. The corresponding value of each key is the number of times the key was returned by `callback`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*. The `callback` argument may also be the name of a property to count by *(e.g. 'length')*.
+Creates an object composed of keys returned from running each element of `collection` through a `callback`. The corresponding value of each key is the number of times the key was returned by `callback`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. The `callback` argument may also be the name of a property to count by *(e.g. 'length')*.
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `callback|property` *(Function|String)*: The function called per iteration or property name to count by.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Object)*: Returns the composed aggregate object.
@@ -486,9 +466,9 @@ _.countBy(['one', 'two', 'three'], 'length');
### `_.debounce(func, wait, immediate)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3492 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3233 "View in source") [Ⓣ][1]
-Creates a new function that will delay the execution of `func` until after `wait` milliseconds have elapsed since the last time it was invoked. Pass `true` for `immediate` to cause debounce to invoke `func` on the leading, instead of the trailing, edge of the `wait` timeout. Subsequent calls to the debounced function will return the result of the last `func` call.
+Creates a function that will delay the execution of `func` until after `wait` milliseconds have elapsed since the last time it was invoked. Pass `true` for `immediate` to cause debounce to invoke `func` on the leading, instead of the trailing, edge of the `wait` timeout. Subsequent calls to the debounced function will return the result of the last `func` call.
#### Arguments
1. `func` *(Function)*: The function to debounce.
@@ -512,7 +492,7 @@ jQuery(window).on('resize', lazyLayout);
### `_.defaults(object [, default1, default2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1194 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1138 "View in source") [Ⓣ][1]
Assigns enumerable properties of the default object(s) to the `destination` object for all `destination` properties that resolve to `null`/`undefined`. Once a property is set, additional defaults of the same property will be ignored.
@@ -538,7 +518,7 @@ _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' });
### `_.defer(func [, arg1, arg2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3557 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3298 "View in source") [Ⓣ][1]
Defers executing the `func` function until the current call stack has cleared. Additional arguments will be passed to `func` when it is invoked.
@@ -563,7 +543,7 @@ _.defer(function() { alert('deferred'); });
### `_.delay(func, wait [, arg1, arg2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3537 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3278 "View in source") [Ⓣ][1]
Executes the `func` function after `wait` milliseconds. Additional arguments will be passed to `func` when it is invoked.
@@ -590,9 +570,9 @@ _.delay(log, 1000, 'logged later');
### `_.difference(array [, array1, array2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2561 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2441 "View in source") [Ⓣ][1]
-Creates a new array of `array` elements not present in the other arrays using strict equality for comparisons, i.e. `===`.
+Creates an array of `array` elements not present in the other arrays using strict equality for comparisons, i.e. `===`.
#### Arguments
1. `array` *(Array)*: The array to process.
@@ -615,7 +595,7 @@ _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
### `_.escape(string)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3754 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3518 "View in source") [Ⓣ][1]
Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their corresponding HTML entities.
@@ -639,9 +619,9 @@ _.escape('Moe, Larry & Curly');
### `_.every(collection [, callback=identity, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2041 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1951 "View in source") [Ⓣ][1]
-Checks if the `callback` returns a truthy value for **all** elements of a `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*.
+Checks if the `callback` returns a truthy value for **all** elements of a `collection`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
#### Aliases
*all*
@@ -649,10 +629,10 @@ Checks if the `callback` returns a truthy value for **all** elements of a `colle
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
-*(Boolean)*: Returns `true` if all elements pass the callback check, else `false`.
+*(Boolean)*: Returns `true` if all elements pass the callback check, else `false`.
#### Example
```js
@@ -668,7 +648,7 @@ _.every([true, 1, null, 'yes'], Boolean);
### `_.extend(object [, source1, source2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1214 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1158 "View in source") [Ⓣ][1]
Assigns enumerable properties of the source object(s) to the `destination` object. Subsequent sources will overwrite propery assignments of previous sources.
@@ -693,9 +673,9 @@ _.extend({ 'name': 'moe' }, { 'age': 40 });
### `_.filter(collection [, callback=identity, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2061 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1971 "View in source") [Ⓣ][1]
-Examines each element in a `collection`, returning an array of all elements the `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*.
+Examines each element in a `collection`, returning an array of all elements the `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
#### Aliases
*select*
@@ -703,10 +683,10 @@ Examines each element in a `collection`, returning an array of all elements the
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
-*(Array)*: Returns a new array of elements that passed callback check.
+*(Array)*: Returns a new array of elements that passed the callback check.
#### Example
```js
@@ -722,9 +702,9 @@ var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; })
### `_.find(collection, callback [, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2082 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1993 "View in source") [Ⓣ][1]
-Examines each element in a `collection`, returning the first one the `callback` returns truthy for. The function returns as soon as it finds an acceptable element, and does not iterate over the entire `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*.
+Examines each element in a `collection`, returning the first one the `callback` returns truthy for. The function returns as soon as it finds an acceptable element, and does not iterate over the entire `collection`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
#### Aliases
*detect*
@@ -732,10 +712,10 @@ Examines each element in a `collection`, returning the first one the `callback`
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `callback` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
-*(Mixed)*: Returns the element that passed the callback check, else `undefined`.
+*(Mixed)*: Returns the element that passed the callback check, else `undefined`.
#### Example
```js
@@ -750,8 +730,8 @@ var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-### `_.first(array [, n, guard])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2598 "View in source") [Ⓣ][1]
+### `_.first(array [, n])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2475 "View in source") [Ⓣ][1]
Gets the first element of the `array`. Pass `n` to return the first `n` elements of the `array`.
@@ -761,7 +741,6 @@ Gets the first element of the `array`. Pass `n` to return the first `n` elements
#### Arguments
1. `array` *(Array)*: The array to query.
2. `[n]` *(Number)*: The number of elements to return.
-3. `[guard]` *(Object)*: Internally used to allow this method to work with others like `_.map` without using their callback `index` argument for `n`.
#### Returns
*(Mixed)*: Returns the first element or an array of the first `n` elements of `array`.
@@ -780,7 +759,7 @@ _.first([5, 4, 3, 2, 1]);
### `_.flatten(array, shallow)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2622 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2497 "View in source") [Ⓣ][1]
Flattens a nested array *(the nesting can be to any depth)*. If `shallow` is truthy, `array` will only be flattened a single level.
@@ -808,9 +787,9 @@ _.flatten([1, [2], [3, [[4]]]], true);
### `_.forEach(collection, callback [, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2109 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2020 "View in source") [Ⓣ][1]
-Iterates over a `collection`, executing the `callback` for each element in the `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*. Callbacks may exit iteration early by explicitly returning `false`.
+Iterates over a `collection`, executing the `callback` for each element in the `collection`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. Callbacks may exit iteration early by explicitly returning `false`.
#### Aliases
*each*
@@ -818,10 +797,10 @@ Iterates over a `collection`, executing the `callback` for each element in the `
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `callback` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
-*(Array, Object)*: Returns `collection`.
+*(Array, Object, String)*: Returns `collection`.
#### Example
```js
@@ -840,14 +819,14 @@ _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
### `_.forIn(object, callback [, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1244 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1188 "View in source") [Ⓣ][1]
-Iterates over `object`'s own and inherited enumerable properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`.
+Iterates over `object`'s own and inherited enumerable properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`.
#### Arguments
1. `object` *(Object)*: The object to iterate over.
2. `callback` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Object)*: Returns `object`.
@@ -876,14 +855,14 @@ _.forIn(new Dog('Dagny'), function(value, key) {
### `_.forOwn(object, callback [, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1268 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1212 "View in source") [Ⓣ][1]
-Iterates over `object`'s own enumerable properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`.
+Iterates over `object`'s own enumerable properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`.
#### Arguments
1. `object` *(Object)*: The object to iterate over.
2. `callback` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Object)*: Returns `object`.
@@ -904,7 +883,7 @@ _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
### `_.functions(object)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1285 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1229 "View in source") [Ⓣ][1]
Creates a sorted array of all enumerable properties, own and inherited, of `object` that have function values.
@@ -931,14 +910,14 @@ _.functions(_);
### `_.groupBy(collection, callback|property [, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2137 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2048 "View in source") [Ⓣ][1]
-Creates an object composed of keys returned from running each element of `collection` through a `callback`. The corresponding value of each key is an array of elements passed to `callback` that returned the key. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*. The `callback` argument may also be the name of a property to count by *(e.g. 'length')*.
+Creates an object composed of keys returned from running each element of `collection` through a `callback`. The corresponding value of each key is an array of elements passed to `callback` that returned the key. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. The `callback` argument may also be the name of a property to count by *(e.g. 'length')*.
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `callback|property` *(Function|String)*: The function called per iteration or property name to group by.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Object)*: Returns the composed aggregate object.
@@ -963,7 +942,7 @@ _.groupBy(['one', 'two', 'three'], 'length');
### `_.has(object, property)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1308 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1252 "View in source") [Ⓣ][1]
Checks if the specified object `property` exists and is a direct property, instead of an inherited property.
@@ -988,7 +967,7 @@ _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
### `_.identity(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3774 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3538 "View in source") [Ⓣ][1]
This function returns the first argument passed to it. Note: It is used throughout Lo-Dash as a default callback.
@@ -1013,7 +992,7 @@ moe === _.identity(moe);
### `_.indexOf(array, value [, fromIndex=0])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2666 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2540 "View in source") [Ⓣ][1]
Gets the index at which the first occurrence of `value` is found using strict equality for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` for `isSorted` will run a faster binary search.
@@ -1044,15 +1023,14 @@ _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
-### `_.initial(array [, n, guard])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2706 "View in source") [Ⓣ][1]
+### `_.initial(array [, n])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2577 "View in source") [Ⓣ][1]
Gets all but the last element of `array`. Pass `n` to exclude the last `n` elements from the result.
#### Arguments
1. `array` *(Array)*: The array to query.
2. `[n]` *(Number)*: The number of elements to return.
-3. `[guard]` *(Object)*: Internally used to allow this method to work with others like `_.map` without using their callback `index` argument for `n`.
#### Returns
*(Array)*: Returns all but the last element or `n` elements of `array`.
@@ -1071,7 +1049,7 @@ _.initial([3, 2, 1]);
### `_.intersection([array1, array2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2728 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2596 "View in source") [Ⓣ][1]
Computes the intersection of all the passed-in arrays using strict equality for comparisons, i.e. `===`.
@@ -1095,7 +1073,7 @@ _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
### `_.invert(object)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1325 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L819 "View in source") [Ⓣ][1]
Creates an object composed of the inverted keys and values of the given `object`.
@@ -1119,9 +1097,9 @@ _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' });
### `_.invoke(collection, methodName [, arg1, arg2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2165 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2076 "View in source") [Ⓣ][1]
-Invokes the method named by `methodName` on each element in the `collection`. Additional arguments will be passed to each invoked method. If `methodName` is a function it will be invoked for, and `this` bound to, each element in the `collection`.
+Invokes the method named by `methodName` on each element in the `collection`, returning an array of the results of each invoked method. Additional arguments will be passed to each invoked method. If `methodName` is a function it will be invoked for, and `this` bound to, each element in the `collection`.
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
@@ -1129,7 +1107,7 @@ Invokes the method named by `methodName` on each element in the `collection`. Ad
3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to invoke the method with.
#### Returns
-*(Array)*: Returns a new array of values returned from each invoked method.
+*(Array)*: Returns a new array of the results of each invoked method.
#### Example
```js
@@ -1148,7 +1126,7 @@ _.invoke([123, 456], String.prototype.split, '');
### `_.isArguments(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L917 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L841 "View in source") [Ⓣ][1]
Checks if `value` is an `arguments` object.
@@ -1175,7 +1153,7 @@ _.isArguments([1, 2, 3]);
### `_.isArray(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L943 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L867 "View in source") [Ⓣ][1]
Checks if `value` is an array.
@@ -1202,7 +1180,7 @@ _.isArray([1, 2, 3]);
### `_.isBoolean(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1344 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1269 "View in source") [Ⓣ][1]
Checks if `value` is a boolean *(`true` or `false`)* value.
@@ -1226,7 +1204,7 @@ _.isBoolean(null);
### `_.isDate(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1361 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1286 "View in source") [Ⓣ][1]
Checks if `value` is a date.
@@ -1250,7 +1228,7 @@ _.isDate(new Date);
### `_.isElement(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1378 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1303 "View in source") [Ⓣ][1]
Checks if `value` is a DOM element.
@@ -1274,7 +1252,7 @@ _.isElement(document.body);
### `_.isEmpty(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1403 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1328 "View in source") [Ⓣ][1]
Checks if `value` is empty. Arrays, strings, or `arguments` objects with a length of `0` and objects with no own enumerable properties are considered "empty".
@@ -1303,15 +1281,14 @@ _.isEmpty('');
-### `_.isEqual(a, b [, data={}])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1444 "View in source") [Ⓣ][1]
+### `_.isEqual(a, b)`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1368 "View in source") [Ⓣ][1]
-Performs a deep comparison between two values to determine if they are equivalent to each other. If a value has an `isEqual` method it will be used to perform the comparison.
+Performs a deep comparison between two values to determine if they are equivalent to each other.
#### Arguments
1. `a` *(Mixed)*: The value to compare.
2. `b` *(Mixed)*: The other value to compare.
-3. `[data={}]` *(Object)*: Internally used track traversed objects to avoid circular references and indicate whether to perform a more thorough comparison of non-object values.
#### Returns
*(Boolean)*: Returns `true` if the values are equvalent, else `false`.
@@ -1336,7 +1313,7 @@ _.isEqual(moe, clone);
### `_.isFinite(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1619 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1525 "View in source") [Ⓣ][1]
Checks if `value` is a finite number. Note: This is not the same as native `isFinite`, which will return true for booleans and other values. See http://es5.github.com/#x15.1.2.5.
@@ -1366,7 +1343,7 @@ _.isFinite(Infinity);
### `_.isFunction(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L960 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L884 "View in source") [Ⓣ][1]
Checks if `value` is a function.
@@ -1378,7 +1355,7 @@ Checks if `value` is a function.
#### Example
```js
-_.isFunction(''.concat);
+_.isFunction(_);
// => true
```
@@ -1390,7 +1367,7 @@ _.isFunction(''.concat);
### `_.isNaN(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1674 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1583 "View in source") [Ⓣ][1]
Checks if `value` is `NaN`. Note: This is not the same as native `isNaN`, which will return true for `undefined` and other values. See http://es5.github.com/#x15.1.2.4.
@@ -1423,7 +1400,7 @@ _.isNaN(undefined);
### `_.isNull(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1697 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1606 "View in source") [Ⓣ][1]
Checks if `value` is `null`.
@@ -1450,7 +1427,7 @@ _.isNull(undefined);
### `_.isNumber(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1714 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1623 "View in source") [Ⓣ][1]
Checks if `value` is a number.
@@ -1462,7 +1439,7 @@ Checks if `value` is a number.
#### Example
```js
-_.isNumber(8.4 * 5;
+_.isNumber(8.4 * 5);
// => true
```
@@ -1474,7 +1451,7 @@ _.isNumber(8.4 * 5;
### `_.isObject(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1640 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1549 "View in source") [Ⓣ][1]
Checks if `value` is the language type of Object. *(e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)*
@@ -1489,6 +1466,9 @@ Checks if `value` is the language type of Object. *(e.g. arrays, functions, obje
_.isObject({});
// => true
+_.isObject([1, 2, 3]);
+// => true
+
_.isObject(1);
// => false
```
@@ -1498,10 +1478,45 @@ _.isObject(1);
+
+
+### `_.isPlainObject(value)`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L918 "View in source") [Ⓣ][1]
+
+Checks if a given `value` is an object created by the `Object` constructor.
+
+#### Arguments
+1. `value` *(Mixed)*: The value to check.
+
+#### Returns
+*(Boolean)*: Returns `true` if `value` is a plain object, else `false`.
+
+#### Example
+```js
+function Stooge(name, age) {
+ this.name = name;
+ this.age = age;
+}
+
+_.isPlainObject(new Stooge('moe', 40));
+// false
+
+_.isPlainObject([1, 2, 3]);
+// false
+
+_.isPlainObject({ 'name': 'moe', 'age': 40 });
+// => true
+```
+
+* * *
+
+
+
+
### `_.isRegExp(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1731 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1640 "View in source") [Ⓣ][1]
Checks if `value` is a regular expression.
@@ -1525,7 +1540,7 @@ _.isRegExp(/moe/);
### `_.isString(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1748 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1657 "View in source") [Ⓣ][1]
Checks if `value` is a string.
@@ -1549,7 +1564,7 @@ _.isString('moe');
### `_.isUndefined(value)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1766 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1675 "View in source") [Ⓣ][1]
Checks if `value` is `undefined`.
@@ -1573,7 +1588,7 @@ _.isUndefined(void 0);
### `_.keys(object)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1783 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1692 "View in source") [Ⓣ][1]
Creates an array composed of the own enumerable property names of `object`.
@@ -1596,15 +1611,14 @@ _.keys({ 'one': 1, 'two': 2, 'three': 3 });
-### `_.last(array [, n, guard])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2771 "View in source") [Ⓣ][1]
+### `_.last(array [, n])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2636 "View in source") [Ⓣ][1]
-Gets the last element of the `array`. Pass `n` to return the lasy `n` elementsvof the `array`.
+Gets the last element of the `array`. Pass `n` to return the last `n` elements of the `array`.
#### Arguments
1. `array` *(Array)*: The array to query.
2. `[n]` *(Number)*: The number of elements to return.
-3. `[guard]` *(Object)*: Internally used to allow this method to work with others like `_.map` without using their callback `index` argument for `n`.
#### Returns
*(Mixed)*: Returns the last element or an array of the last `n` elements of `array`.
@@ -1623,7 +1637,7 @@ _.last([3, 2, 1]);
### `_.lastIndexOf(array, value [, fromIndex=array.length-1])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2797 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2660 "View in source") [Ⓣ][1]
Gets the index at which the last occurrence of `value` is found using strict equality for comparisons, i.e. `===`.
@@ -1649,12 +1663,53 @@ _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+
+
+### `_.lateBind(object, methodName [, arg1, arg2, ...])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3336 "View in source") [Ⓣ][1]
+
+Creates a function that, when called, invokes `object[methodName]` and prepends any additional `lateBind` arguments to those passed to the bound function. This method differs from `_.bind` by allowing bound functions to reference methods that will be redefined or don't yet exist.
+
+#### Arguments
+1. `object` *(Object)*: The object the method belongs to.
+2. `methodName` *(String)*: The method name.
+3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to be partially applied.
+
+#### Returns
+*(Function)*: Returns the new bound function.
+
+#### Example
+```js
+var object = {
+ 'name': 'moe',
+ 'greet': function(greeting) {
+ return greeting + ' ' + this.name;
+ }
+};
+
+var func = _.lateBind(object, 'greet', 'hi');
+func();
+// => 'hi moe'
+
+object.greet = function(greeting) {
+ return greeting + ', ' + this.name + '!';
+};
+
+func();
+// => 'hi, moe!'
+```
+
+* * *
+
+
+
+
### `_.map(collection [, callback=identity, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2200 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2111 "View in source") [Ⓣ][1]
-Creates a new array of values by running each element in the `collection` through a `callback`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*.
+Creates an array of values by running each element in the `collection` through a `callback`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
#### Aliases
*collect*
@@ -1662,10 +1717,10 @@ Creates a new array of values by running each element in the `collection` throug
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
-*(Array)*: Returns a new array of elements returned by the callback.
+*(Array)*: Returns a new array of the results of each `callback` execution.
#### Example
```js
@@ -1684,14 +1739,14 @@ _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
### `_.max(array [, callback, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2837 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2697 "View in source") [Ⓣ][1]
-Retrieves the maximum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index, array)*.
+Retrieves the maximum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
#### Arguments
1. `array` *(Array)*: The array to iterate over.
2. `[callback]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Mixed)*: Returns the maximum value.
@@ -1716,9 +1771,9 @@ _.max(stooges, function(stooge) { return stooge.age; });
### `_.memoize(func [, resolver])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3580 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3358 "View in source") [Ⓣ][1]
-Creates a new function that memoizes the result of `func`. If `resolver` is passed, it will be used to determine the cache key for storing the result based on the arguments passed to the memoized function. By default, the first argument passed to the memoized function is used as the cache key.
+Creates a function that memoizes the result of `func`. If `resolver` is passed, it will be used to determine the cache key for storing the result based on the arguments passed to the memoized function. By default, the first argument passed to the memoized function is used as the cache key.
#### Arguments
1. `func` *(Function)*: The function to have its output memoized.
@@ -1741,16 +1796,14 @@ var fibonacci = _.memoize(function(n) {
-### `_.merge(object [, source1, source2, ..., indicator, data={}])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1825 "View in source") [Ⓣ][1]
+### `_.merge(object [, source1, source2, ...])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1730 "View in source") [Ⓣ][1]
Merges enumerable properties of the source object(s) into the `destination` object. Subsequent sources will overwrite propery assignments of previous sources.
#### Arguments
1. `object` *(Object)*: The destination object.
2. `[source1, source2, ...]` *(Object)*: The source objects.
-3. `[indicator]` *(Object)*: Internally used to indicate that the `stack` argument is an array of traversed objects instead of another source object.
-4. `[data={}]` *(Object)*: Internally used to track traversed objects to avoid circular references.
#### Returns
*(Object)*: Returns the destination object.
@@ -1779,14 +1832,14 @@ _.merge(stooges, ages);
### `_.min(array [, callback, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2887 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2733 "View in source") [Ⓣ][1]
-Retrieves the minimum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index, array)*.
+Retrieves the minimum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
#### Arguments
1. `array` *(Array)*: The array to iterate over.
2. `[callback]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Mixed)*: Returns the minimum value.
@@ -1805,7 +1858,7 @@ _.min([10, 5, 100, 2, 1000]);
### `_.mixin(object)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3800 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3564 "View in source") [Ⓣ][1]
Adds functions properties of `object` to the `lodash` function and chainable wrapper.
@@ -1835,7 +1888,7 @@ _('curly').capitalize();
### `_.noConflict()`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3831 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3595 "View in source") [Ⓣ][1]
Reverts the '_' variable to its previous value and returns a reference to the `lodash` function.
@@ -1855,7 +1908,7 @@ var lodash = _.noConflict();
### `_.object(keys [, values=[]])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2936 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2768 "View in source") [Ⓣ][1]
Creates an object composed from arrays of `keys` and `values`. Pass either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or two arrays, one of `keys` and one of corresponding `values`.
@@ -1880,14 +1933,14 @@ _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
### `_.omit(object, callback|[prop1, prop2, ..., thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1878 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1787 "View in source") [Ⓣ][1]
-Creates a shallow clone of `object` excluding the specified properties. Property names may be specified as individual arguments or as arrays of property names. If `callback` is passed, it will be executed for each property in the `object`, omitting the properties `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, key, object)*.
+Creates a shallow clone of `object` excluding the specified properties. Property names may be specified as individual arguments or as arrays of property names. If `callback` is passed, it will be executed for each property in the `object`, omitting the properties `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*.
#### Arguments
1. `object` *(Object)*: The source object.
2. `callback|[prop1, prop2, ...]` *(Function|String)*: The properties to omit or the function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Object)*: Returns an object without the omitted properties.
@@ -1911,9 +1964,9 @@ _.omit({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(va
### `_.once(func)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3606 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3384 "View in source") [Ⓣ][1]
-Creates a new function that is restricted to one execution. Repeat calls to the function will return the value of the first call.
+Creates a function that is restricted to one execution. Repeat calls to the function will return the value of the first call.
#### Arguments
1. `func` *(Function)*: The function to restrict.
@@ -1937,7 +1990,7 @@ initialize();
### `_.pairs(object)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1894 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1803 "View in source") [Ⓣ][1]
Creates a two dimensional array of the given object's key-value pairs, i.e. `[[key1, value1], [key2, value2]]`.
@@ -1961,9 +2014,9 @@ _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 });
### `_.partial(func [, arg1, arg2, ...])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3641 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3419 "View in source") [Ⓣ][1]
-Creates a new function that, when called, invokes `func` with any additional `partial` arguments prepended to those passed to the new function. This method is similar `bind`, except it does **not** alter the `this` binding.
+Creates a function that, when called, invokes `func` with any additional `partial` arguments prepended to those passed to the new function. This method is similar to `bind`, except it does **not** alter the `this` binding.
#### Arguments
1. `func` *(Function)*: The function to partially apply arguments to.
@@ -1988,14 +2041,14 @@ hi('moe');
### `_.pick(object, callback|[prop1, prop2, ..., thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1925 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1834 "View in source") [Ⓣ][1]
-Creates a shallow clone of `object` composed of the specified properties. Property names may be specified as individual arguments or as arrays of property names. If `callback` is passed, it will be executed for each property in the `object`, picking the properties `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, key, object)*.
+Creates a shallow clone of `object` composed of the specified properties. Property names may be specified as individual arguments or as arrays of property names. If `callback` is passed, it will be executed for each property in the `object`, picking the properties `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*.
#### Arguments
1. `object` *(Object)*: The source object.
2. `callback|[prop1, prop2, ...]` *(Function|String)*: The properties to pick or the function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Object)*: Returns an object composed of the picked properties.
@@ -2019,7 +2072,7 @@ _.pick({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(va
### `_.pluck(collection, property)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2223 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2134 "View in source") [Ⓣ][1]
Retrieves the value of a specified property from all elements in the `collection`.
@@ -2049,14 +2102,14 @@ _.pluck(stooges, 'name');
-### `_.random(min, max)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3858 "View in source") [Ⓣ][1]
+### `_.random([min=0, max=1])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3618 "View in source") [Ⓣ][1]
-Produces a random number between `min` and `max` *(inclusive)*. If only one argument is passed, a number between `0` and the given number will be returned. If no arguments are passed `_.random` will act as `Math.random`.
+Produces a random number between `min` and `max` *(inclusive)*. If only one argument is passed, a number between `0` and the given number will be returned.
#### Arguments
-1. `min` *(Number)*: The minimum possible value.
-2. `max` *(Number)*: The maximum possible value.
+1. `[min=0]` *(Number)*: The minimum possible value.
+2. `[max=1]` *(Number)*: The maximum possible value.
#### Returns
*(Number)*: Returns a random number.
@@ -2068,9 +2121,6 @@ _.random(0, 5);
_.random(5);
// => also a number between 1 and 5
-
-_.random();
-// => an integer between 0 and less than 1
```
* * *
@@ -2081,7 +2131,7 @@ _.random();
### `_.range([start=0], end [, step=1])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2983 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2812 "View in source") [Ⓣ][1]
Creates an array of numbers *(positive and/or negative)* progressing from `start` up to but not including `stop`. This method is a port of Python's `range()` function. See http://docs.python.org/library/functions.html#range.
@@ -2119,7 +2169,7 @@ _.range(0);
### `_.reduce(collection, callback [, accumulator, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2251 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2162 "View in source") [Ⓣ][1]
Boils down a `collection` to a single value. The initial state of the reduction is `accumulator` and each successive step of it should be returned by the `callback`. The `callback` is bound to `thisArg` and invoked with `4` arguments; for arrays they are *(accumulator, value, index|key, collection)*.
@@ -2130,7 +2180,7 @@ Boils down a `collection` to a single value. The initial state of the reduction
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `callback` *(Function)*: The function called per iteration.
3. `[accumulator]` *(Mixed)*: Initial value of the accumulator.
-4. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+4. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Mixed)*: Returns the accumulated value.
@@ -2149,7 +2199,7 @@ var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; });
### `_.reduceRight(collection, callback [, accumulator, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2288 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2199 "View in source") [Ⓣ][1]
The right-associative version of `_.reduce`.
@@ -2160,7 +2210,7 @@ The right-associative version of `_.reduce`.
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `callback` *(Function)*: The function called per iteration.
3. `[accumulator]` *(Mixed)*: Initial value of the accumulator.
-4. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+4. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Mixed)*: Returns the accumulated value.
@@ -2180,17 +2230,17 @@ var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
### `_.reject(collection [, callback=identity, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2344 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2236 "View in source") [Ⓣ][1]
The opposite of `_.filter`, this method returns the values of a `collection` that `callback` does **not** return truthy for.
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
-*(Array)*: Returns a new array of elements that did **not** pass the callback check.
+*(Array)*: Returns a new array of elements that did **not** pass the callback check.
#### Example
```js
@@ -2205,8 +2255,8 @@ var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-### `_.rest(array [, n, guard])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3022 "View in source") [Ⓣ][1]
+### `_.rest(array [, n])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2851 "View in source") [Ⓣ][1]
The opposite of `_.initial`, this method gets all but the first value of `array`. Pass `n` to exclude the first `n` values from the result.
@@ -2216,7 +2266,6 @@ The opposite of `_.initial`, this method gets all but the first value of `array`
#### Arguments
1. `array` *(Array)*: The array to query.
2. `[n]` *(Number)*: The number of elements to return.
-3. `[guard]` *(Object)*: Internally used to allow this method to work with others like `_.map` without using their callback `index` argument for `n`.
#### Returns
*(Array)*: Returns all but the first value or `n` values of `array`.
@@ -2235,13 +2284,13 @@ _.rest([3, 2, 1]);
### `_.result(object, property)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3897 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3657 "View in source") [Ⓣ][1]
Resolves the value of `property` on `object`. If `property` is a function it will be invoked and its result returned, else the property value is returned. If `object` is falsey, then `null` is returned.
#### Arguments
1. `object` *(Object)*: The object to inspect.
-2. `property` *(String)*: The property to get the result of.
+2. `property` *(String)*: The property to get the value of.
#### Returns
*(Mixed)*: Returns the resolved value.
@@ -2270,9 +2319,9 @@ _.result(object, 'stuff');
### `_.shuffle(array)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3043 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2869 "View in source") [Ⓣ][1]
-Creates a new array of shuffled `array` values, using a version of the Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
+Creates an array of shuffled `array` values, using a version of the Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
#### Arguments
1. `array` *(Array)*: The array to shuffle.
@@ -2294,7 +2343,7 @@ _.shuffle([1, 2, 3, 4, 5, 6]);
### `_.size(collection)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2368 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2260 "View in source") [Ⓣ][1]
Gets the size of the `collection` by returning `collection.length` for arrays and array-like objects or the number of own enumerable properties for objects.
@@ -2324,9 +2373,9 @@ _.size('curly');
### `_.some(collection [, callback=identity, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2395 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2285 "View in source") [Ⓣ][1]
-Checks if the `callback` returns a truthy value for **any** element of a `collection`. The function returns as soon as it finds passing value, and does not iterate over the entire `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*.
+Checks if the `callback` returns a truthy value for **any** element of a `collection`. The function returns as soon as it finds passing value, and does not iterate over the entire `collection`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
#### Aliases
*any*
@@ -2334,10 +2383,10 @@ Checks if the `callback` returns a truthy value for **any** element of a `collec
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
-*(Boolean)*: Returns `true` if any element passes the callback check, else `false`.
+*(Boolean)*: Returns `true` if any element passes the callback check, else `false`.
#### Example
```js
@@ -2353,14 +2402,14 @@ _.some([null, 0, 'yes', false]);
### `_.sortBy(collection, callback|property [, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2425 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2315 "View in source") [Ⓣ][1]
-Creates a new array, stable sorted in ascending order by the results of running each element of `collection` through a `callback`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index|key, collection)*. The `callback` argument may also be the name of a property to sort by *(e.g. 'length')*.
+Creates an array, stable sorted in ascending order by the results of running each element of `collection` through a `callback`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. The `callback` argument may also be the name of a property to sort by *(e.g. 'length')*.
#### Arguments
1. `collection` *(Array|Object|String)*: The collection to iterate over.
2. `callback|property` *(Function|String)*: The function called per iteration or property name to sort by.
-3. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Array)*: Returns a new array of sorted elements.
@@ -2384,35 +2433,38 @@ _.sortBy(['larry', 'brendan', 'moe'], 'length');
-### `_.sortedIndex(array, value [, callback=identity, thisArg])`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3095 "View in source") [Ⓣ][1]
+### `_.sortedIndex(array, value [, callback=identity|property, thisArg])`
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2923 "View in source") [Ⓣ][1]
-Uses a binary search to determine the smallest index at which the `value` should be inserted into `array` in order to maintain the sort order of the sorted `array`. If `callback` is passed, it will be executed for `value` and each element in `array` to compute their sort ranking. The `callback` is bound to `thisArg` and invoked with `1` argument; *(value)*.
+Uses a binary search to determine the smallest index at which the `value` should be inserted into `array` in order to maintain the sort order of the sorted `array`. If `callback` is passed, it will be executed for `value` and each element in `array` to compute their sort ranking. The `callback` is bound to `thisArg` and invoked with one argument; *(value)*. The `callback` argument may also be the name of a property to order by.
#### Arguments
1. `array` *(Array)*: The array to iterate over.
2. `value` *(Mixed)*: The value to evaluate.
-3. `[callback=identity]` *(Function)*: The function called per iteration.
-4. `[thisArg]` *(Mixed)*: The `this` binding for the callback.
+3. `[callback=identity|property]` *(Function|String)*: The function called per iteration or property name to order by.
+4. `[thisArg]` *(Mixed)*: The `this` binding of `callback`.
#### Returns
*(Number)*: Returns the index at which the value should be inserted into `array`.
#### Example
```js
-_.sortedIndex([20, 30, 40], 35);
+_.sortedIndex([20, 30, 50], 40);
+// => 2
+
+_.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
// => 2
var dict = {
- 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'thirty-five': 35, 'fourty': 40 }
+ 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
};
-_.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) {
+_.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
return dict.wordToNumber[word];
});
// => 2
-_.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) {
+_.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
return this.wordToNumber[word];
}, dict);
// => 2
@@ -2426,7 +2478,7 @@ _.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) {
### `_.tap(value, interceptor)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4212 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3945 "View in source") [Ⓣ][1]
Invokes `interceptor` with the `value` as the first argument, and then returns `value`. The purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.
@@ -2439,7 +2491,7 @@ Invokes `interceptor` with the `value` as the first argument, and then returns `
#### Example
```js
-_.chain([1,2,3,200])
+_.chain([1, 2, 3, 200])
.filter(function(num) { return num % 2 == 0; })
.tap(alert)
.map(function(num) { return num * num })
@@ -2456,7 +2508,7 @@ _.chain([1,2,3,200])
### `_.template(text, data, options)`
-# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3970 "View in source") [Ⓣ][1]
+# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3727 "View in source") [Ⓣ][1]
A micro-templating method that handles arbitrary delimiters, preserves whitespace, and correctly escapes quotes within interpolated code. Note: In the development build `_.template` utilizes sourceURLs for easier debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp` build and avoiding `_.template` use, or loading Lo-Dash in a sandboxed page. See http://developer.chrome.com/trunk/extensions/sandboxingEval.html
@@ -2475,7 +2527,7 @@ var compiled = _.template('hello: <%= name %>');
compiled({ 'name': 'moe' });
// => 'hello: moe'
-var list = '<% _.forEach(people, function(name) { %> <%= name %> <% }); %>';
+var list = '<% _.forEach(people, function(name) { %><%= name %><% }); %>';
_.template(list, { 'people': ['moe', 'larry', 'curly'] });
// => 'moelarrycurly'
@@ -2484,12 +2536,12 @@ _.template('<%- value %>', { 'value': '"
);
iDoc.close();
@@ -550,6 +499,7 @@ $(document).ready(function() {
ok(!_.isNaN(0), '0 is not NaN');
ok(_.isNaN(NaN), 'but NaN is');
ok(_.isNaN(iNaN), 'even from another frame');
+ ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN');
});
test("isNull", function() {
diff --git a/vendor/underscore/test/utility.js b/vendor/underscore/test/utility.js
index d5fb9603ad..c9be20ad79 100644
--- a/vendor/underscore/test/utility.js
+++ b/vendor/underscore/test/utility.js
@@ -241,4 +241,9 @@ $(document).ready(function() {
deepEqual(settings, {});
});
+ test('#779 - delimeters are applied to unescaped text.', 1, function() {
+ var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g});
+ strictEqual(template(), '<<\nx\n>>');
+ });
+
});
diff --git a/vendor/underscore/underscore-min.js b/vendor/underscore/underscore-min.js
index 29cb190099..6889f810c9 100644
--- a/vendor/underscore/underscore-min.js
+++ b/vendor/underscore/underscore-min.js
@@ -1,33 +1,5 @@
-// Underscore.js 1.3.3
-// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
-// Underscore may be freely distributed under the MIT license.
-// Portions of Underscore are inspired or borrowed from Prototype,
-// Oliver Steele's Functional, and John Resig's Micro-Templating.
-// For all details and documentation:
-// http://documentcloud.github.com/underscore
-(function(){var s=this,K=s._,o={},k=Array.prototype,p=Object.prototype,L=k.push,g=k.slice,l=p.toString,M=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,N=Object.keys,t=Function.prototype.bind,b=function(a){if(a instanceof b)return a;if(!(this instanceof b))return new b(a);this._wrapped=a};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;
-b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,h=a.length;e2;a==null&&(a=[]);if(A&&
-a.reduce===A){e&&(c=b.bind(c,e));return h?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,g){if(h)d=c.call(e,d,a,b,g);else{d=a;h=true}});if(!h)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var h=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return h?a.reduceRight(c,d):a.reduceRight(c)}var f=b.toArray(a).reverse();e&&!h&&(c=b.bind(c,e));return h?b.reduce(f,c,d,e):b.reduce(f,c)};b.find=b.detect=function(a,
-c,b){var e;G(a,function(a,f,i){if(c.call(b,a,f,i)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,f,i){c.call(b,a,f,i)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,f,i){c.call(b,a,f,i)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,d){c||(c=b.identity);var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,d);j(a,function(a,b,
-i){if(!(e=e&&c.call(d,a,b,i)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,i){if(e||(e=c.call(d,a,b,i)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=g.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c:a[c]).apply(a,
-d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,i){b=c?c.call(d,a,b,i):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,
-function(a,b,i){b=c?c.call(d,a,b,i):a;bd?1:0}),"value")};var H=function(a,c){return b.isFunction(c)?c:function(a){return a[c]}},
-I=function(a,c,b){var e={},h=H(a,c);j(a,function(a,c){var g=h(a,c);b(e,g,a)});return e};b.groupBy=function(a,c){return I(a,c,function(a,c,b){(a[c]||(a[c]=[])).push(b)})};b.countBy=function(a,c){return I(a,c,function(a,c){a[c]||(a[c]=0);a[c]++})};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var c=d(c),e=0,h=a.length;e>1;d(a[f])=0})})};b.difference=function(a){var c=r(g.call(arguments,1),true,[]);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=g.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};
-b.keys=N||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.pairs=function(a){return b.map(a,function(a,b){return[b,a]})};b.invert=function(a){return b.reduce(a,function(a,b,e){a[b]=e;return a},{})};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(g.call(arguments,1),function(b){for(var d in b)a[d]=
-b[d]});return a};b.pick=function(a){var c={},d=b.flatten(g.call(arguments,1));j(d,function(b){b in a&&(c[b]=a[b])});return c};b.omit=function(a){var c={},d=b.flatten(g.call(arguments,1)),e;for(e in a)b.include(d,e)||(c[e]=a[e]);return c};b.defaults=function(a){j(g.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};var u=function(a,c,d,e){if(a===c)return a!==
-0||1/a==1/c;if(a==null||c==null)return a===c;if(a instanceof b)a=a._wrapped;if(c instanceof b)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var h=l.call(a);if(h!=l.call(c))return false;switch(h){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==c.source&&a.global==c.global&&
-a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return e[f]==c;d.push(a);e.push(c);var f=0,i=true;if(h=="[object Array]"){f=a.length;if(i=f==c.length)for(;f--;)if(!(i=f in a==f in c&&u(a[f],c[f],d,e)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var g in a)if(b.has(a,g)){f++;if(!(i=b.has(c,g)&&u(a[g],c[g],d,e)))break}if(i){for(g in c)if(b.has(c,g)&&!f--)break;
-i=!f}}d.pop();e.pop();return i};b.isEqual=function(a,b){return u(a,b,[],[])};b.isEmpty=function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};j("Arguments,Function,String,Number,Date,RegExp".split(","),function(a){b["is"+a]=function(b){return l.call(b)=="[object "+
-a+"]"}});b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return M.call(a,b)};b.noConflict=function(){s._=K;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=
-0;e":">",'"':""","'":"'","/":"/"}};m.unescape=b.invert(m.escape);var O={escape:RegExp("["+b.keys(m.escape).join("")+"]","g"),unescape:RegExp("("+b.keys(m.unescape).join("|")+")","g")};b.each(["escape","unescape"],function(a){b[a]=function(b){return b==null?"":(""+b).replace(O[a],function(b){return m[a][b]})}});b.result=function(a,c){if(a==null)return null;var d=
-a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){var d=b[c]=a[c];b.prototype[c]=function(){var a=g.call(arguments);a.unshift(this._wrapped);a=d.apply(b,a);return this._chain?b(a).chain():a}})};var P=0;b.uniqueId=function(a){var b=P++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var v=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},w;for(w in n)n[n[w]]=
-w;var Q=/\\|'|\r|\n|\t|\u2028|\u2029/g,R=/\\(\\|'|r|n|t|u2028|u2029)/g,x=function(a){return a.replace(R,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults({},d,b.templateSettings);a="__p+='"+a.replace(Q,function(a){return"\\"+n[a]}).replace(d.escape||v,function(a,b){return"'+\n((__t=("+x(b)+"))==null?'':_.escape(__t))+\n'"}).replace(d.interpolate||v,function(a,b){return"'+\n((__t=("+x(b)+"))==null?'':__t)+\n'"}).replace(d.evaluate||v,function(a,b){return"';\n"+x(b)+"\n__p+='"})+
-"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");a="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{var e=new Function(d.variable||"obj","_",a)}catch(g){g.source=a;throw g;}if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};b.chain=function(a){return b(a).chain()};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var c=k[a];b.prototype[a]=
-function(){var d=this._wrapped;c.apply(d,arguments);(a=="shift"||a=="splice")&&d.length===0&&delete d[0];return this._chain?b(d).chain():d}});j(["concat","join","slice"],function(a){var c=k[a];b.prototype[a]=function(){var a=c.apply(this._wrapped,arguments);return this._chain?b(a).chain():a}});b.extend(b.prototype,{chain:function(){this._chain=true;return this},value:function(){return this._wrapped}})}).call(this);
+// Underscore.js 1.4.0
+// http://underscorejs.org
+// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore may be freely distributed under the MIT license.
+(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=r.unshift,l=i.toString,c=i.hasOwnProperty,h=r.forEach,p=r.map,d=r.reduce,v=r.reduceRight,m=r.filter,g=r.every,y=r.some,b=r.indexOf,w=r.lastIndexOf,E=Array.isArray,S=Object.keys,x=s.bind,T=function(e){if(e instanceof T)return e;if(!(this instanceof T))return new T(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=T),exports._=T):e._=T,T.VERSION="1.4.0";var N=T.each=T.forEach=function(e,t,r){if(h&&e.forEach===h)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i2;if(d&&e.reduce===d)return r&&(t=T.bind(t,r)),i?e.reduce(t,n):e.reduce(t);N(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.reduceRight=T.foldr=function(e,t,n,r){var i=arguments.length>2;if(v&&e.reduceRight===v)return r&&(t=T.bind(t,r)),arguments.length>2?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=T.keys(e);s=o.length}N(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.find=T.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},T.filter=T.select=function(e,t,n){var r=[];return m&&e.filter===m?e.filter(t,n):(N(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},T.reject=function(e,t,n){var r=[];return N(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r},T.every=T.all=function(e,t,r){t||(t=T.identity);var i=!0;return g&&e.every===g?e.every(t,r):(N(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=T.some=T.any=function(e,t,r){t||(t=T.identity);var i=!1;return y&&e.some===y?e.some(t,r):(N(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};T.contains=T.include=function(e,t){var n=!1;return b&&e.indexOf===b?e.indexOf(t)!=-1:(n=C(e,function(e){return e===t}),n)},T.invoke=function(e,t){var n=u.call(arguments,2);return T.map(e,function(e){return(T.isFunction(t)?t:e[t]).apply(e,n)})},T.pluck=function(e,t){return T.map(e,function(e){return e[t]})},T.where=function(e,t){return T.isEmpty(t)?[]:T.filter(e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},T.max=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&T.isEmpty(e))return-Infinity;var r={computed:-Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},T.min=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&T.isEmpty(e))return Infinity;var r={computed:Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;or||n===void 0)return 1;if(n>>1;n.call(r,e[u])=0})})},T.difference=function(e){var t=a.apply(r,u.call(arguments,1));return T.filter(e,function(e){return!T.contains(t,e)})},T.zip=function(){var e=u.call(arguments),t=T.max(T.pluck(e,"length")),n=new Array(t);for(var r=0;r=0;n--)t=[e[n].apply(this,t)];return t[0]}},T.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},T.keys=S||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)T.has(e,n)&&(t[t.length]=n);return t},T.values=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push(e[n]);return t},T.pairs=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push([n,e[n]]);return t},T.invert=function(e){var t={};for(var n in e)T.has(e,n)&&(t[e[n]]=n);return t},T.functions=T.methods=function(e){var t=[];for(var n in e)T.isFunction(e[n])&&t.push(n);return t.sort()},T.extend=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]=t[n]}),e},T.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return N(n,function(n){n in e&&(t[n]=e[n])}),t},T.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)T.contains(n,i)||(t[i]=e[i]);return t},T.defaults=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]==null&&(e[n]=t[n])}),e},T.clone=function(e){return T.isObject(e)?T.isArray(e)?e.slice():T.extend({},e):e},T.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof T&&(e=e._wrapped),t instanceof T&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,f=t.constructor;if(a!==f&&!(T.isFunction(a)&&a instanceof a&&T.isFunction(f)&&f instanceof f))return!1;for(var c in e)if(T.has(e,c)){o++;if(!(u=T.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(T.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};T.isEqual=function(e,t){return M(e,t,[],[])},T.isEmpty=function(e){if(e==null)return!0;if(T.isArray(e)||T.isString(e))return e.length===0;for(var t in e)if(T.has(e,t))return!1;return!0},T.isElement=function(e){return!!e&&e.nodeType===1},T.isArray=E||function(e){return l.call(e)=="[object Array]"},T.isObject=function(e){return e===Object(e)},N(["Arguments","Function","String","Number","Date","RegExp"],function(e){T["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),T.isArguments(arguments)||(T.isArguments=function(e){return!!e&&!!T.has(e,"callee")}),typeof /./!="function"&&(T.isFunction=function(e){return typeof e=="function"}),T.isFinite=function(e){return T.isNumber(e)&&isFinite(e)},T.isNaN=function(e){return T.isNumber(e)&&e!=+e},T.isBoolean=function(e){return e===!0||e===!1||l.call(e)=="[object Boolean]"},T.isNull=function(e){return e===null},T.isUndefined=function(e){return e===void 0},T.has=function(e,t){return c.call(e,t)},T.noConflict=function(){return e._=t,this},T.identity=function(e){return e},T.times=function(e,t,n){for(var r=0;r":">",'"':""","'":"'","/":"/"}};_.unescape=T.invert(_.escape);var D={escape:new RegExp("["+T.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+T.keys(_.unescape).join("|")+")","g")};T.each(["escape","unescape"],function(e){T[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),T.result=function(e,t){if(e==null)return null;var n=e[t];return T.isFunction(n)?n.call(e):n},T.mixin=function(e){N(T.functions(e),function(t){var n=T[t]=e[t];T.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(T,e))}})};var P=0;T.uniqueId=function(e){var t=P++;return e?e+t:t},T.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;T.template=function(e,t,n){n=T.defaults({},n,T.templateSettings);var r=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),i=0,s="__p+='";e.replace(r,function(t,n,r,o,u){s+=e.slice(i,u).replace(j,function(e){return"\\"+B[e]}),s+=n?"'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?"'+\n((__t=("+r+"))==null?'':__t)+\n'":o?"';\n"+o+"\n__p+='":"",i=u+t.length}),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{var o=new Function(n.variable||"obj","_",s)}catch(u){throw u.source=s,u}if(t)return o(t,T);var a=function(e){return o.call(this,e,T)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},T.chain=function(e){return T(e).chain()};var F=function(e){return this._chain?T(e).chain():e};T.mixin(T),N(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];T.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),N(["concat","join","slice"],function(e){var t=r[e];T.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),T.extend(T.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
\ No newline at end of file
diff --git a/vendor/underscore/underscore.js b/vendor/underscore/underscore.js
index c0eb8ece2c..013dcadbed 100644
--- a/vendor/underscore/underscore.js
+++ b/vendor/underscore/underscore.js
@@ -1,10 +1,7 @@
-// Underscore.js 1.3.3
+// Underscore.js 1.4.0
+// http://underscorejs.org
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore may be freely distributed under the MIT license.
-// Portions of Underscore are inspired or borrowed from Prototype,
-// Oliver Steele's Functional, and John Resig's Micro-Templating.
-// For all details and documentation:
-// http://documentcloud.github.com/underscore
(function() {
@@ -26,6 +23,7 @@
// 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;
@@ -67,7 +65,7 @@
}
// Current version.
- _.VERSION = '1.3.3';
+ _.VERSION = '1.4.0';
// Collection Functions
// --------------------
@@ -76,7 +74,6 @@
// 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;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
@@ -96,7 +93,6 @@
// Delegates to **ECMAScript 5**'s native `map` if available.
_.map = _.collect = function(obj, iterator, context) {
var results = [];
- if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function(value, index, list) {
results[results.length] = iterator.call(context, value, index, list);
@@ -108,7 +104,6 @@
// 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 = [];
if (nativeReduce && obj.reduce === nativeReduce) {
if (context) iterator = _.bind(iterator, context);
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
@@ -129,14 +124,26 @@
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
var initial = arguments.length > 2;
- if (obj == null) obj = [];
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+ return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
}
- var reversed = _.toArray(obj).reverse();
- if (context && !initial) iterator = _.bind(iterator, context);
- return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
+ var length = obj.length;
+ if (length !== +length) {
+ var keys = _.keys(obj);
+ length = keys.length;
+ }
+ each(obj, function(value, index, list) {
+ index = keys ? keys[--length] : --length;
+ if (!initial) {
+ memo = obj[index];
+ initial = true;
+ } else {
+ memo = iterator.call(context, memo, obj[index], index, list);
+ }
+ });
+ if (!initial) throw new TypeError('Reduce of empty array with no initial value');
+ return memo;
};
// Return the first value which passes a truth test. Aliased as `detect`.
@@ -156,7 +163,6 @@
// Aliased as `select`.
_.filter = _.select = function(obj, iterator, context) {
var results = [];
- if (obj == null) return results;
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
each(obj, function(value, index, list) {
if (iterator.call(context, value, index, list)) results[results.length] = value;
@@ -167,7 +173,6 @@
// 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;
});
@@ -180,7 +185,6 @@
_.every = _.all = function(obj, iterator, context) {
iterator || (iterator = _.identity);
var result = true;
- if (obj == null) return result;
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
each(obj, function(value, index, list) {
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
@@ -194,7 +198,6 @@
var any = _.some = _.any = function(obj, iterator, context) {
iterator || (iterator = _.identity);
var result = false;
- if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) {
if (result || (result = iterator.call(context, value, index, list))) return breaker;
@@ -202,11 +205,10 @@
return !!result;
};
- // Determine if a given value is included in the array or object using `===`.
- // Aliased as `contains`.
- _.include = _.contains = function(obj, target) {
+ // 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 (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
found = any(obj, function(value) {
return value === target;
@@ -227,6 +229,18 @@
return _.map(obj, function(value){ return value[key]; });
};
+ // Convenience version of a common use case of `filter`: selecting only objects
+ // with specific `key:value` pairs.
+ _.where = function(obj, attrs) {
+ if (_.isEmpty(attrs)) return [];
+ return _.filter(obj, function(value) {
+ for (var key in attrs) {
+ if (attrs[key] !== value[key]) return false;
+ }
+ return true;
+ });
+ };
+
// Return the maximum element or (element-based computation).
// Can't optimize arrays of integers longer than 65,535 elements.
// See: https://bugs.webkit.org/show_bug.cgi?id=80797
@@ -263,40 +277,44 @@
var index = 0;
var shuffled = [];
each(obj, function(value) {
- rand = Math.floor(Math.random() * ++index);
+ rand = _.random(index++);
shuffled[index - 1] = shuffled[rand];
shuffled[rand] = value;
});
return shuffled;
};
+ // An internal function to generate lookup iterators.
+ var lookupIterator = function(value) {
+ return _.isFunction(value) ? value : function(obj){ return obj[value]; };
+ };
+
// Sort the object's values by a criterion produced by an iterator.
- _.sortBy = function(obj, val, context) {
- var iterator = lookupIterator(obj, val);
+ _.sortBy = function(obj, value, context) {
+ var iterator = lookupIterator(value);
return _.pluck(_.map(obj, function(value, index, list) {
return {
value : value,
+ index : index,
criteria : iterator.call(context, value, index, list)
};
}).sort(function(left, right) {
- var a = left.criteria, b = right.criteria;
- if (a === void 0) return 1;
- if (b === void 0) return -1;
- return a < b ? -1 : a > b ? 1 : 0;
+ var a = left.criteria;
+ var b = right.criteria;
+ if (a !== b) {
+ if (a > b || a === void 0) return 1;
+ if (a < b || b === void 0) return -1;
+ }
+ return left.index < right.index ? -1 : 1;
}), 'value');
};
- // An internal function to generate lookup iterators.
- var lookupIterator = function(obj, val) {
- return _.isFunction(val) ? val : function(obj) { return obj[val]; };
- };
-
// An internal function used for aggregate "group by" operations.
- var group = function(obj, val, behavior) {
+ var group = function(obj, value, context, behavior) {
var result = {};
- var iterator = lookupIterator(obj, val);
+ var iterator = lookupIterator(value);
each(obj, function(value, index) {
- var key = iterator(value, index);
+ var key = iterator.call(context, value, index, obj);
behavior(result, key, value);
});
return result;
@@ -304,40 +322,39 @@
// 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) {
- return group(obj, val, function(result, key, value) {
- (result[key] || (result[key] = [])).push(value);
+ _.groupBy = function(obj, value, context) {
+ return group(obj, value, context, function(result, key, value) {
+ (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
});
};
// 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, val) {
- return group(obj, val, function(result, key, value) {
- result[key] || (result[key] = 0);
+ _.countBy = function(obj, value, context) {
+ return group(obj, value, context, function(result, key, value) {
+ if (!_.has(result, key)) result[key] = 0;
result[key]++;
});
};
// Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
- _.sortedIndex = function(array, obj, iterator) {
- iterator || (iterator = _.identity);
- var value = iterator(obj);
+ _.sortedIndex = function(array, obj, iterator, context) {
+ iterator = iterator == null ? _.identity : lookupIterator(iterator);
+ var value = iterator.call(context, obj);
var low = 0, high = array.length;
while (low < high) {
- var mid = (low + high) >> 1;
- iterator(array[mid]) < value ? low = mid + 1 : high = mid;
+ var mid = (low + high) >>> 1;
+ iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
}
return low;
};
// Safely convert anything iterable into a real, live array.
_.toArray = function(obj) {
- if (!obj) return [];
- if (_.isArray(obj) || _.isArguments(obj)) return slice.call(obj);
- if (_.isFunction(obj.toArray)) return obj.toArray();
+ if (!obj) return [];
+ if (obj.length === +obj.length) return slice.call(obj);
return _.values(obj);
};
@@ -412,23 +429,23 @@
// 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) {
- var initial = iterator ? _.map(array, iterator) : array;
+ _.uniq = _.unique = function(array, isSorted, iterator, context) {
+ var initial = iterator ? _.map(array, iterator, context) : array;
var results = [];
- _.reduce(initial, function(memo, value, index) {
- if (isSorted ? (_.last(memo) !== value || !memo.length) : !_.include(memo, value)) {
- memo.push(value);
+ var seen = [];
+ each(initial, function(value, index) {
+ if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
+ seen.push(value);
results.push(array[index]);
}
- return memo;
- }, []);
+ });
return results;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
- return _.uniq(flatten(arguments, true, []));
+ return _.uniq(concat.apply(ArrayProto, arguments));
};
// Produce an array that contains every item shared between all the
@@ -445,8 +462,8 @@
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
- var rest = flatten(slice.call(arguments, 1), true, []);
- return _.filter(array, function(value){ return !_.include(rest, value); });
+ var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
+ return _.filter(array, function(value){ return !_.contains(rest, value); });
};
// Zip together multiple lists into a single array -- elements that share
@@ -483,22 +500,27 @@
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) {
- if (array == null) return -1;
- var i, l;
+ var i = 0, l = array.length;
if (isSorted) {
- i = _.sortedIndex(array, item);
- return array[i] === item ? i : -1;
+ if (typeof isSorted == 'number') {
+ i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
+ } else {
+ i = _.sortedIndex(array, item);
+ return array[i] === item ? i : -1;
+ }
}
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
- for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
+ for (; i < l; i++) if (array[i] === item) return i;
return -1;
};
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
- _.lastIndexOf = function(array, item) {
- if (array == null) return -1;
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
- var i = array.length;
+ _.lastIndexOf = function(array, item, from) {
+ var hasIndex = from != null;
+ if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
+ return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
+ }
+ var i = (hasIndex ? from : array.length);
while (i--) if (array[i] === item) return i;
return -1;
};
@@ -613,17 +635,18 @@
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
- var timeout;
+ var timeout, result;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
- if (!immediate) func.apply(context, args);
+ if (!immediate) result = func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
- if (callNow) func.apply(context, args);
+ if (callNow) result = func.apply(context, args);
+ return result;
};
};
@@ -645,7 +668,8 @@
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
return function() {
- var args = [func].concat(slice.call(arguments, 0));
+ var args = [func];
+ push.apply(args, arguments);
return wrapper.apply(this, args);
};
};
@@ -687,22 +711,23 @@
// Retrieve the values of an object's properties.
_.values = function(obj) {
- return _.map(obj, _.identity);
+ var values = [];
+ for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
+ return values;
};
// Convert an object into a list of `[key, value]` pairs.
_.pairs = function(obj) {
- return _.map(obj, function(value, key) {
- return [key, value];
- });
+ var pairs = [];
+ for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
+ return pairs;
};
// Invert the keys and values of an object. The values must be serializable.
_.invert = function(obj) {
- return _.reduce(obj, function(memo, value, key) {
- memo[value] = key;
- return memo;
- }, {});
+ var result = {};
+ for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
+ return result;
};
// Return a sorted list of the function names available on the object.
@@ -728,7 +753,7 @@
// Return a copy of the object only containing the whitelisted properties.
_.pick = function(obj) {
var copy = {};
- var keys = _.flatten(slice.call(arguments, 1));
+ var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
each(keys, function(key) {
if (key in obj) copy[key] = obj[key];
});
@@ -738,9 +763,9 @@
// Return a copy of the object without the blacklisted properties.
_.omit = function(obj) {
var copy = {};
- var keys = _.flatten(slice.call(arguments, 1));
+ var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
for (var key in obj) {
- if (!_.include(keys, key)) copy[key] = obj[key];
+ if (!_.contains(keys, key)) copy[key] = obj[key];
}
return copy;
};
@@ -779,9 +804,6 @@
// Unwrap any wrapped objects.
if (a instanceof _) a = a._wrapped;
if (b instanceof _) b = b._wrapped;
- // Invoke a custom `isEqual` method if one is provided.
- if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
- if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className != toString.call(b)) return false;
@@ -829,13 +851,17 @@
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
- // Ensure commutative equality for sparse arrays.
- if (!(result = size in a == size in b && eq(a[size], b[size], aStack, bStack))) break;
+ if (!(result = eq(a[size], b[size], aStack, bStack))) break;
}
}
} else {
- // Objects with different constructors are not equivalent.
- if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
+ // Objects with different constructors are not equivalent, but `Object`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
+ _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
+ return false;
+ }
// Deep compare objects.
for (var key in a) {
if (_.has(a, key)) {
@@ -875,7 +901,7 @@
// Is a given value a DOM element?
_.isElement = function(obj) {
- return !!(obj && obj.nodeType == 1);
+ return !!(obj && obj.nodeType === 1);
};
// Is a given value an array?
@@ -904,15 +930,21 @@
};
}
+ // Optimize `isFunction` if appropriate.
+ if (typeof (/./) !== 'function') {
+ _.isFunction = function(obj) {
+ return typeof obj === 'function';
+ };
+ }
+
// Is a given object a finite number?
_.isFinite = function(obj) {
return _.isNumber(obj) && isFinite(obj);
};
- // Is the given value `NaN`?
+ // Is the given value `NaN`? (NaN is the only number which does not equal itself).
_.isNaN = function(obj) {
- // `NaN` is the only value for which `===` is not reflexive.
- return obj !== obj;
+ return _.isNumber(obj) && obj != +obj;
};
// Is a given value a boolean?
@@ -958,6 +990,10 @@
// Return a random integer between min and max (inclusive).
_.random = function(min, max) {
+ if (max == null) {
+ max = min;
+ min = 0;
+ }
return min + (0 | Math.random() * (max - min + 1));
};
@@ -1003,8 +1039,8 @@
each(_.functions(obj), function(name){
var func = _[name] = obj[name];
_.prototype[name] = function() {
- var args = slice.call(arguments);
- args.unshift(this._wrapped);
+ var args = [this._wrapped];
+ push.apply(args, arguments);
return result.call(this, func.apply(_, args));
};
});
@@ -1029,31 +1065,21 @@
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
- var noMatch = /.^/;
+ var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a
// string literal.
var escapes = {
- '\\': '\\',
- "'": "'",
- r: '\r',
- n: '\n',
- t: '\t',
- u2028: '\u2028',
- u2029: '\u2029'
+ "'": "'",
+ '\\': '\\',
+ '\r': 'r',
+ '\n': 'n',
+ '\t': 't',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
};
- for (var key in escapes) escapes[escapes[key]] = key;
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
- var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
-
- // Within an interpolation, evaluation, or escaping, remove HTML escaping
- // that had been previously added.
- var unescape = function(code) {
- return code.replace(unescaper, function(match, escape) {
- return escapes[escape];
- });
- };
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
@@ -1061,22 +1087,26 @@
_.template = function(text, data, settings) {
settings = _.defaults({}, settings, _.templateSettings);
- // Compile the template source, taking care to escape characters that
- // cannot be included in a string literal and then unescape them in code
- // blocks.
- var source = "__p+='" + text
- .replace(escaper, function(match) {
- return '\\' + escapes[match];
- })
- .replace(settings.escape || noMatch, function(match, code) {
- return "'+\n((__t=(" + unescape(code) + "))==null?'':_.escape(__t))+\n'";
- })
- .replace(settings.interpolate || noMatch, function(match, code) {
- return "'+\n((__t=(" + unescape(code) + "))==null?'':__t)+\n'";
- })
- .replace(settings.evaluate || noMatch, function(match, code) {
- return "';\n" + unescape(code) + "\n__p+='";
- }) + "';\n";
+ // Combine delimiters into one regular expression via alternation.
+ var matcher = new RegExp([
+ (settings.escape || noMatch).source,
+ (settings.interpolate || noMatch).source,
+ (settings.evaluate || noMatch).source
+ ].join('|') + '|$', 'g');
+
+ // Compile the template source, escaping string literals appropriately.
+ var index = 0;
+ var source = "__p+='";
+ 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+='" : '';
+ index = offset + match.length;
+ });
+ source += "';\n";
// If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';