lodash-rails 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -18,6 +18,6 @@ Add the necessary library to `app/assets/javascripts/application.js`:
18
18
 
19
19
  ## What's included?
20
20
 
21
- * Lo-Dash 0.8.2 (lodash, lodash.min)
21
+ * Lo-Dash 0.9.0 (lodash, lodash.min)
22
22
 
23
23
  Copyright Richard Hubers, released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  module LoDash
2
2
  module Rails
3
- VERSION = "0.8.2"
3
+ VERSION = "0.9.0"
4
4
  end
5
5
  end
@@ -1,27 +1,31 @@
1
1
  /*!
2
- * Lo-Dash v0.8.2 <http://lodash.com>
2
+ * Lo-Dash v0.9.0 <http://lodash.com>
3
3
  * (c) 2012 John-David Dalton <http://allyoucanleet.com/>
4
4
  * Based on Underscore.js 1.4.2 <http://underscorejs.org>
5
5
  * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
6
6
  * Available under MIT license <http://lodash.com/license>
7
7
  */
8
8
  ;(function(window, undefined) {
9
- 'use strict';
10
9
 
11
10
  /** Detect free variable `exports` */
12
- var freeExports = typeof exports == 'object' && exports &&
13
- (typeof global == 'object' && global && global == global.global && (window = global), exports);
11
+ var freeExports = typeof exports == 'object' && exports;
14
12
 
15
- /** Native prototype shortcuts */
16
- var ArrayProto = Array.prototype,
17
- BoolProto = Boolean.prototype,
18
- ObjectProto = Object.prototype,
19
- NumberProto = Number.prototype,
20
- StringProto = String.prototype;
13
+ /** Detect free variable `global` and use it as `window` */
14
+ var freeGlobal = typeof global == 'object' && global;
15
+ if (freeGlobal.global === freeGlobal) {
16
+ window = freeGlobal;
17
+ }
18
+
19
+ /** Used for array and object method references */
20
+ var arrayRef = [],
21
+ objectRef = {};
21
22
 
22
23
  /** Used to generate unique IDs */
23
24
  var idCounter = 0;
24
25
 
26
+ /** Used internally to indicate various things */
27
+ var indicatorObject = {};
28
+
25
29
  /** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */
26
30
  var largeArraySize = 30;
27
31
 
@@ -47,7 +51,7 @@
47
51
 
48
52
  /** Used to detect if a method is native */
49
53
  var reNative = RegExp('^' +
50
- (ObjectProto.valueOf + '')
54
+ (objectRef.valueOf + '')
51
55
  .replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&')
52
56
  .replace(/valueOf|for [^\]]+/g, '.+?') + '$'
53
57
  );
@@ -72,14 +76,14 @@
72
76
 
73
77
  /** Native method shortcuts */
74
78
  var ceil = Math.ceil,
75
- concat = ArrayProto.concat,
79
+ concat = arrayRef.concat,
76
80
  floor = Math.floor,
77
81
  getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
78
- hasOwnProperty = ObjectProto.hasOwnProperty,
79
- push = ArrayProto.push,
80
- propertyIsEnumerable = ObjectProto.propertyIsEnumerable,
81
- slice = ArrayProto.slice,
82
- toString = ObjectProto.toString;
82
+ hasOwnProperty = objectRef.hasOwnProperty,
83
+ push = arrayRef.push,
84
+ propertyIsEnumerable = objectRef.propertyIsEnumerable,
85
+ slice = arrayRef.slice,
86
+ toString = objectRef.toString;
83
87
 
84
88
  /* Native method shortcuts for methods with the same name as other `lodash` methods */
85
89
  var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind,
@@ -101,10 +105,6 @@
101
105
  regexpClass = '[object RegExp]',
102
106
  stringClass = '[object String]';
103
107
 
104
- /** Timer shortcuts */
105
- var clearTimeout = window.clearTimeout,
106
- setTimeout = window.setTimeout;
107
-
108
108
  /**
109
109
  * Detect the JScript [[DontEnum]] bug:
110
110
  *
@@ -113,6 +113,9 @@
113
113
  */
114
114
  var hasDontEnumBug;
115
115
 
116
+ /** Detect if own properties are iterated after inherited properties (IE < 9) */
117
+ var iteratesOwnLast;
118
+
116
119
  /**
117
120
  * Detect if `Array#shift` and `Array#splice` augment array-like objects
118
121
  * incorrectly:
@@ -123,26 +126,21 @@
123
126
  * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
124
127
  * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
125
128
  */
126
- var hasObjectSpliceBug;
127
-
128
- /** Detect if own properties are iterated after inherited properties (IE < 9) */
129
- var iteratesOwnLast;
129
+ var hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 },
130
+ arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]);
130
131
 
131
132
  /** Detect if an `arguments` object's indexes are non-enumerable (IE < 9) */
132
133
  var noArgsEnum = true;
133
134
 
134
135
  (function() {
135
- var object = { '0': 1, 'length': 1 },
136
- props = [];
137
-
136
+ var props = [];
138
137
  function ctor() { this.x = 1; }
139
138
  ctor.prototype = { 'valueOf': 1, 'y': 1 };
140
139
  for (var prop in new ctor) { props.push(prop); }
141
140
  for (prop in arguments) { noArgsEnum = !prop; }
142
141
 
143
- hasDontEnumBug = (props + '').length < 4;
142
+ hasDontEnumBug = !/valueOf/.test(props);
144
143
  iteratesOwnLast = props[0] != 'x';
145
- hasObjectSpliceBug = (props.splice.call(object, 0, 1), object[0]);
146
144
  }(1));
147
145
 
148
146
  /** Detect if an `arguments` object's [[Class]] is unresolvable (Firefox < 4, IE < 9) */
@@ -174,9 +172,6 @@
174
172
  /* Detect if `Object.keys` exists and is inferred to be fast (IE, Opera, V8) */
175
173
  var isKeysFast = nativeKeys && /^.+$|true/.test(nativeKeys + !!window.attachEvent);
176
174
 
177
- /* Detect if strict mode, "use strict", is inferred to be fast (V8) */
178
- var isStrictFast = !isBindFast;
179
-
180
175
  /**
181
176
  * Detect if sourceURL syntax is usable without erroring:
182
177
  *
@@ -194,12 +189,6 @@
194
189
  var useSourceURL = (Function('//@')(), !window.attachEvent);
195
190
  } catch(e) { }
196
191
 
197
- /** Used to identify object classifications that are array-like */
198
- var arrayLikeClasses = {};
199
- arrayLikeClasses[boolClass] = arrayLikeClasses[dateClass] = arrayLikeClasses[funcClass] =
200
- arrayLikeClasses[numberClass] = arrayLikeClasses[objectClass] = arrayLikeClasses[regexpClass] = false;
201
- arrayLikeClasses[argsClass] = arrayLikeClasses[arrayClass] = arrayLikeClasses[stringClass] = true;
202
-
203
192
  /** Used to identify object classifications that `_.clone` supports */
204
193
  var cloneableClasses = {};
205
194
  cloneableClasses[argsClass] = cloneableClasses[funcClass] = false;
@@ -214,8 +203,7 @@
214
203
  'object': true,
215
204
  'number': false,
216
205
  'string': false,
217
- 'undefined': false,
218
- 'unknown': true
206
+ 'undefined': false
219
207
  };
220
208
 
221
209
  /** Used to escape characters for inclusion in compiled string literals */
@@ -311,21 +299,21 @@
311
299
  */
312
300
  var iteratorTemplate = template(
313
301
  // conditional strict mode
314
- '<% if (useStrict) { %>\'use strict\';\n<% } %>' +
302
+ '<% if (obj.useStrict) { %>\'use strict\';\n<% } %>' +
315
303
 
316
304
  // the `iteratee` may be reassigned by the `top` snippet
317
305
  'var index, value, iteratee = <%= firstArg %>, ' +
318
306
  // assign the `result` variable an initial value
319
- 'result = <%= init || firstArg %>;\n' +
307
+ 'result = <%= firstArg %>;\n' +
320
308
  // exit early if the first argument is falsey
321
309
  'if (!<%= firstArg %>) return result;\n' +
322
310
  // add code before the iteration branches
323
311
  '<%= top %>;\n' +
324
312
 
325
- // the following branch is for iterating arrays and array-like objects
326
- '<% if (arrayBranch) { %>' +
327
- 'var length = iteratee.length; index = -1;' +
328
- ' <% if (objectBranch) { %>\nif (length === +length) {<% } %>' +
313
+ // array-like iteration:
314
+ '<% if (arrayLoop) { %>' +
315
+ 'var length = iteratee.length; index = -1;\n' +
316
+ 'if (typeof length == \'number\') {' +
329
317
 
330
318
  // add support for accessing string characters by index if needed
331
319
  ' <% if (noCharByIndex) { %>\n' +
@@ -334,25 +322,22 @@
334
322
  ' }' +
335
323
  ' <% } %>\n' +
336
324
 
337
- ' <%= arrayBranch.beforeLoop %>;\n' +
325
+ // iterate over the array-like value
338
326
  ' while (++index < length) {\n' +
339
327
  ' value = iteratee[index];\n' +
340
- ' <%= arrayBranch.inLoop %>\n' +
341
- ' }' +
342
- ' <% if (objectBranch) { %>\n}<% } %>' +
343
- '<% } %>' +
344
-
345
- // the following branch is for iterating an object's own/inherited properties
346
- '<% if (objectBranch) { %>' +
347
- ' <% if (arrayBranch) { %>\nelse {' +
328
+ ' <%= arrayLoop %>\n' +
329
+ ' }\n' +
330
+ '}\n' +
331
+ 'else {' +
348
332
 
333
+ // object iteration:
349
334
  // add support for iterating over `arguments` objects if needed
350
335
  ' <% } else if (noArgsEnum) { %>\n' +
351
336
  ' var length = iteratee.length; index = -1;\n' +
352
337
  ' if (length && isArguments(iteratee)) {\n' +
353
338
  ' while (++index < length) {\n' +
354
339
  ' value = iteratee[index += \'\'];\n' +
355
- ' <%= objectBranch.inLoop %>\n' +
340
+ ' <%= objectLoop %>\n' +
356
341
  ' }\n' +
357
342
  ' } else {' +
358
343
  ' <% } %>' +
@@ -373,18 +358,16 @@
373
358
  ' var ownIndex = -1,\n' +
374
359
  ' ownProps = objectTypes[typeof iteratee] ? nativeKeys(iteratee) : [],\n' +
375
360
  ' length = ownProps.length;\n\n' +
376
- ' <%= objectBranch.beforeLoop %>;\n' +
377
361
  ' while (++ownIndex < length) {\n' +
378
362
  ' index = ownProps[ownIndex];\n' +
379
363
  ' <% if (!hasDontEnumBug) { %>if (!(skipProto && index == \'prototype\')) {\n <% } %>' +
380
364
  ' value = iteratee[index];\n' +
381
- ' <%= objectBranch.inLoop %>\n' +
365
+ ' <%= objectLoop %>\n' +
382
366
  ' <% if (!hasDontEnumBug) { %>}\n<% } %>' +
383
367
  ' }' +
384
368
 
385
369
  // else using a for-in loop
386
370
  ' <% } else { %>\n' +
387
- ' <%= objectBranch.beforeLoop %>;\n' +
388
371
  ' for (index in iteratee) {<%' +
389
372
  ' if (!hasDontEnumBug || useHas) { %>\n if (<%' +
390
373
  ' if (!hasDontEnumBug) { %>!(skipProto && index == \'prototype\')<% }' +
@@ -393,7 +376,7 @@
393
376
  ' %>) {' +
394
377
  ' <% } %>\n' +
395
378
  ' value = iteratee[index];\n' +
396
- ' <%= objectBranch.inLoop %>;' +
379
+ ' <%= objectLoop %>;' +
397
380
  ' <% if (!hasDontEnumBug || useHas) { %>\n }<% } %>\n' +
398
381
  ' }' +
399
382
  ' <% } %>' +
@@ -411,12 +394,11 @@
411
394
  ' %>!(ctor && ctor.prototype === iteratee) && <%' +
412
395
  ' } %>hasOwnProperty.call(iteratee, index)) {\n' +
413
396
  ' value = iteratee[index];\n' +
414
- ' <%= objectBranch.inLoop %>\n' +
397
+ ' <%= objectLoop %>\n' +
415
398
  ' }' +
416
399
  ' <% } %>' +
417
400
  ' <% } %>' +
418
- ' <% if (arrayBranch || noArgsEnum) { %>\n}<% } %>' +
419
- '<% } %>\n' +
401
+ ' <% if (arrayLoop || noArgsEnum) { %>\n}<% } %>\n' +
420
402
 
421
403
  // add code to the bottom of the iteration function
422
404
  '<%= bottom %>;\n' +
@@ -425,88 +407,29 @@
425
407
  );
426
408
 
427
409
  /**
428
- * Reusable iterator options shared by
429
- * `countBy`, `every`, `filter`, `find`, `forEach`, `forIn`, `forOwn`, `groupBy`,
430
- * `map`, `reject`, `some`, and `sortBy`.
410
+ * Reusable iterator options shared by `forEach`, `forIn`, and `forOwn`.
431
411
  */
432
- var baseIteratorOptions = {
412
+ var forEachIteratorOptions = {
433
413
  'args': 'collection, callback, thisArg',
434
414
  'top': 'callback = createCallback(callback, thisArg)',
435
- 'inLoop': 'if (callback(value, index, collection) === false) return result'
415
+ 'arrayLoop': 'if (callback(value, index, collection) === false) return result',
416
+ 'objectLoop': 'if (callback(value, index, collection) === false) return result'
436
417
  };
437
418
 
438
- /** Reusable iterator options for `countBy`, `groupBy`, and `sortBy` */
439
- var countByIteratorOptions = {
440
- 'init': '{}',
441
- 'top': 'callback = createCallback(callback, thisArg)',
442
- 'inLoop':
443
- 'var prop = callback(value, index, collection);\n' +
444
- '(hasOwnProperty.call(result, prop) ? result[prop]++ : result[prop] = 1)'
445
- };
446
-
447
- /** Reusable iterator options for `every` and `some` */
448
- var everyIteratorOptions = {
449
- 'init': 'true',
450
- 'inLoop': 'if (!callback(value, index, collection)) return !result'
451
- };
452
-
453
- /** Reusable iterator options for `defaults` and `extend` */
419
+ /** Reusable iterator options for `defaults`, and `extend` */
454
420
  var extendIteratorOptions = {
455
421
  'useHas': false,
456
- 'useStrict': false,
457
422
  'args': 'object',
458
423
  'top':
459
424
  'for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {\n' +
460
425
  ' if (iteratee = arguments[argsIndex]) {',
461
- 'inLoop': 'result[index] = value',
426
+ 'objectLoop': 'result[index] = value',
462
427
  'bottom': ' }\n}'
463
428
  };
464
429
 
465
- /** Reusable iterator options for `filter`, `reject`, and `where` */
466
- var filterIteratorOptions = {
467
- 'init': '[]',
468
- 'inLoop': 'callback(value, index, collection) && result.push(value)'
469
- };
470
-
471
- /** Reusable iterator options for `find`, `forEach`, `forIn`, and `forOwn` */
472
- var forEachIteratorOptions = {
473
- 'top': 'callback = createCallback(callback, thisArg)'
474
- };
475
-
476
430
  /** Reusable iterator options for `forIn` and `forOwn` */
477
431
  var forOwnIteratorOptions = {
478
- 'inLoop': {
479
- 'object': baseIteratorOptions.inLoop
480
- }
481
- };
482
-
483
- /** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */
484
- var mapIteratorOptions = {
485
- 'init': 'collection || []',
486
- 'beforeLoop': {
487
- 'array': 'result = Array(length)',
488
- 'object': 'result = ' + (isKeysFast ? 'Array(length)' : '[]')
489
- },
490
- 'inLoop': {
491
- 'array': 'result[index] = callback(value, index, collection)',
492
- 'object': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '(callback(value, index, collection))'
493
- }
494
- };
495
-
496
- /** Reusable iterator options for `omit` and `pick` */
497
- var omitIteratorOptions = {
498
- 'useHas': false,
499
- 'args': 'object, callback, thisArg',
500
- 'init': '{}',
501
- 'top':
502
- 'var isFunc = typeof callback == \'function\';\n' +
503
- 'if (isFunc) callback = createCallback(callback, thisArg);\n' +
504
- 'else var props = concat.apply(ArrayProto, arguments)',
505
- 'inLoop':
506
- 'if (isFunc\n' +
507
- ' ? !callback(value, index, object)\n' +
508
- ' : indexOf(props, index) < 0\n' +
509
- ') result[index] = value'
432
+ 'arrayLoop': null
510
433
  };
511
434
 
512
435
  /*--------------------------------------------------------------------------*/
@@ -657,89 +580,52 @@
657
580
  }
658
581
 
659
582
  /**
660
- * Creates compiled iteration functions. The iteration function will be created
661
- * to iterate over only objects if the first argument of `options.args` is
662
- * "object" or `options.inLoop.array` is falsey.
583
+ * Creates compiled iteration functions.
663
584
  *
664
585
  * @private
665
- * @param {Object} [options1, options2, ...] The compile options objects.
666
- *
586
+ * @param {Object} [options1, options2, ...] The compile options object(s).
667
587
  * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop.
668
- *
669
- * useStrict - A boolean to specify including the "use strict" directive.
670
- *
671
588
  * args - A string of comma separated arguments the iteration function will accept.
672
- *
673
- * init - A string to specify the initial value of the `result` variable.
674
- *
675
589
  * top - A string of code to execute before the iteration branches.
676
- *
677
- * beforeLoop - A string or object containing an "array" or "object" property
678
- * of code to execute before the array or object loops.
679
- *
680
- * inLoop - A string or object containing an "array" or "object" property
681
- * of code to execute in the array or object loops.
682
- *
683
- * bottom - A string of code to execute after the iteration branches but
684
- * before the `result` is returned.
590
+ * arrayLoop - A string of code to execute in the array loop.
591
+ * objectLoop - A string of code to execute in the object loop.
592
+ * bottom - A string of code to execute after the iteration branches.
685
593
  *
686
594
  * @returns {Function} Returns the compiled function.
687
595
  */
688
596
  function createIterator() {
689
597
  var data = {
598
+ 'arrayLoop': '',
690
599
  'bottom': '',
691
600
  'hasDontEnumBug': hasDontEnumBug,
692
- 'init': '',
693
601
  'isKeysFast': isKeysFast,
602
+ 'objectLoop': '',
694
603
  'noArgsEnum': noArgsEnum,
695
604
  'noCharByIndex': noCharByIndex,
696
605
  'shadowed': shadowed,
697
606
  'top': '',
698
- 'useHas': true,
699
- 'useStrict': isStrictFast,
700
- 'arrayBranch': { 'beforeLoop': '' },
701
- 'objectBranch': { 'beforeLoop': '' }
607
+ 'useHas': true
702
608
  };
703
609
 
704
- var object,
705
- index = -1;
706
-
707
610
  // merge options into a template data object
708
- while (object = arguments[++index]) {
709
- for (var prop in object) {
710
- var value = object[prop];
711
- // keep this regexp explicit for the build pre-process
712
- if (/beforeLoop|inLoop/.test(prop)) {
713
- if (typeof value == 'string') {
714
- value = { 'array': value, 'object': value };
715
- }
716
- data.arrayBranch[prop] = value.array;
717
- data.objectBranch[prop] = value.object;
718
- } else {
719
- data[prop] = value;
720
- }
611
+ for (var object, index = 0; object = arguments[index]; index++) {
612
+ for (var key in object) {
613
+ data[key] = object[key];
721
614
  }
722
615
  }
723
- // set additional template `data` properties
724
616
  var args = data.args;
725
- if ((data.firstArg = /^[^,]+/.exec(args)[0]) != 'collection' || !data.arrayBranch.inLoop) {
726
- data.arrayBranch = null;
727
- }
617
+ data.firstArg = /^[^,]+/.exec(args)[0];
618
+
728
619
  // create the function factory
729
620
  var factory = Function(
730
- 'arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback, ' +
731
- 'forIn, hasOwnProperty, indexOf, isArguments, isArray, isFunction, ' +
732
- 'isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable, ' +
733
- 'slice, stringClass, toString, undefined',
734
- 'var callee = function(' + args + ') {\n' + iteratorTemplate(data) + '\n};\n' +
735
- 'return callee'
621
+ 'createCallback, hasOwnProperty, isArguments, objectTypes, nativeKeys, ' +
622
+ 'propertyIsEnumerable, stringClass, toString',
623
+ 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
736
624
  );
737
625
  // return the compiled function
738
626
  return factory(
739
- arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback,
740
- forIn, hasOwnProperty, indexOf, isArguments, isArray, isFunction,
741
- isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable,
742
- slice, stringClass, toString
627
+ createCallback, hasOwnProperty, isArguments, objectTypes, nativeKeys,
628
+ propertyIsEnumerable, stringClass, toString
743
629
  );
744
630
  }
745
631
 
@@ -788,25 +674,6 @@
788
674
 
789
675
  /*--------------------------------------------------------------------------*/
790
676
 
791
- /**
792
- * Creates an object composed of the inverted keys and values of the given `object`.
793
- *
794
- * @static
795
- * @memberOf _
796
- * @category Objects
797
- * @param {Object} object The object to invert.
798
- * @returns {Object} Returns the created inverted object.
799
- * @example
800
- *
801
- * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' });
802
- * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed)
803
- */
804
- var invert = createIterator({
805
- 'args': 'object',
806
- 'init': '{}',
807
- 'inLoop': 'result[value] = index'
808
- });
809
-
810
677
  /**
811
678
  * Checks if `value` is an `arguments` object.
812
679
  *
@@ -834,83 +701,58 @@
834
701
  }
835
702
 
836
703
  /**
837
- * Checks if `value` is an array.
704
+ * Iterates over `object`'s own and inherited enumerable properties, executing
705
+ * the `callback` for each property. The `callback` is bound to `thisArg` and
706
+ * invoked with three arguments; (value, key, object). Callbacks may exit iteration
707
+ * early by explicitly returning `false`.
838
708
  *
839
709
  * @static
840
710
  * @memberOf _
841
711
  * @category Objects
842
- * @param {Mixed} value The value to check.
843
- * @returns {Boolean} Returns `true` if the `value` is an array, else `false`.
712
+ * @param {Object} object The object to iterate over.
713
+ * @param {Function} callback The function called per iteration.
714
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
715
+ * @returns {Object} Returns `object`.
844
716
  * @example
845
717
  *
846
- * (function() { return _.isArray(arguments); })();
847
- * // => false
848
- *
849
- * _.isArray([1, 2, 3]);
850
- * // => true
851
- */
852
- var isArray = nativeIsArray || function(value) {
853
- return toString.call(value) == arrayClass;
854
- };
855
-
856
- /**
857
- * Checks if `value` is a function.
718
+ * function Dog(name) {
719
+ * this.name = name;
720
+ * }
858
721
  *
859
- * @static
860
- * @memberOf _
861
- * @category Objects
862
- * @param {Mixed} value The value to check.
863
- * @returns {Boolean} Returns `true` if the `value` is a function, else `false`.
864
- * @example
722
+ * Dog.prototype.bark = function() {
723
+ * alert('Woof, woof!');
724
+ * };
865
725
  *
866
- * _.isFunction(_);
867
- * // => true
726
+ * _.forIn(new Dog('Dagny'), function(value, key) {
727
+ * alert(key);
728
+ * });
729
+ * // => alerts 'name' and 'bark' (order is not guaranteed)
868
730
  */
869
- function isFunction(value) {
870
- return typeof value == 'function';
871
- }
872
- // fallback for older versions of Chrome and Safari
873
- if (isFunction(/x/)) {
874
- isFunction = function(value) {
875
- return toString.call(value) == funcClass;
876
- };
877
- }
731
+ var forIn = createIterator(forEachIteratorOptions, forOwnIteratorOptions, {
732
+ 'useHas': false
733
+ });
878
734
 
879
735
  /**
880
- * Checks if a given `value` is an object created by the `Object` constructor.
736
+ * Iterates over `object`'s own enumerable properties, executing the `callback`
737
+ * for each property. The `callback` is bound to `thisArg` and invoked with three
738
+ * arguments; (value, key, object). Callbacks may exit iteration early by explicitly
739
+ * returning `false`.
881
740
  *
882
741
  * @static
883
742
  * @memberOf _
884
743
  * @category Objects
885
- * @param {Mixed} value The value to check.
886
- * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
744
+ * @param {Object} object The object to iterate over.
745
+ * @param {Function} callback The function called per iteration.
746
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
747
+ * @returns {Object} Returns `object`.
887
748
  * @example
888
749
  *
889
- * function Stooge(name, age) {
890
- * this.name = name;
891
- * this.age = age;
892
- * }
893
- *
894
- * _.isPlainObject(new Stooge('moe', 40));
895
- * // false
896
- *
897
- * _.isPlainObject([1, 2, 3]);
898
- * // false
899
- *
900
- * _.isPlainObject({ 'name': 'moe', 'age': 40 });
901
- * // => true
750
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
751
+ * alert(key);
752
+ * });
753
+ * // => alerts '0', '1', and 'length' (order is not guaranteed)
902
754
  */
903
- var isPlainObject = !getPrototypeOf ? isPlainFallback : function(value) {
904
- if (!(value && typeof value == 'object')) {
905
- return false;
906
- }
907
- var valueOf = value.valueOf,
908
- objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
909
-
910
- return objProto
911
- ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value))
912
- : isPlainFallback(value);
913
- };
755
+ var forOwn = createIterator(forEachIteratorOptions, forOwnIteratorOptions);
914
756
 
915
757
  /**
916
758
  * A fallback implementation of `isPlainObject` that checks if a given `value`
@@ -922,7 +764,7 @@
922
764
  * @param {Mixed} value The value to check.
923
765
  * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
924
766
  */
925
- function isPlainFallback(value) {
767
+ function shimIsPlainObject(value) {
926
768
  // avoid non-objects and false positives for `arguments` objects
927
769
  var result = false;
928
770
  if (!(value && typeof value == 'object') || isArguments(value)) {
@@ -956,18 +798,20 @@
956
798
  }
957
799
 
958
800
  /**
959
- * A shim implementation of `Object.keys` that produces an array of the given
960
- * object's own enumerable property names.
801
+ * A fallback implementation of `Object.keys` that produces an array of the
802
+ * given object's own enumerable property names.
961
803
  *
962
804
  * @private
963
805
  * @param {Object} object The object to inspect.
964
806
  * @returns {Array} Returns a new array of property names.
965
807
  */
966
- var shimKeys = createIterator({
967
- 'args': 'object',
968
- 'init': '[]',
969
- 'inLoop': 'result.push(index)'
970
- });
808
+ function shimKeys(object) {
809
+ var result = [];
810
+ forOwn(object, function(value, key) {
811
+ result.push(key);
812
+ });
813
+ return result;
814
+ }
971
815
 
972
816
  /**
973
817
  * Used to convert characters to HTML entities:
@@ -1110,7 +954,7 @@
1110
954
  * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' }
1111
955
  */
1112
956
  var defaults = createIterator(extendIteratorOptions, {
1113
- 'inLoop': 'if (result[index] == null) ' + extendIteratorOptions.inLoop
957
+ 'objectLoop': 'if (result[index] == null) ' + extendIteratorOptions.objectLoop
1114
958
  });
1115
959
 
1116
960
  /**
@@ -1132,100 +976,89 @@
1132
976
  var extend = createIterator(extendIteratorOptions);
1133
977
 
1134
978
  /**
1135
- * Iterates over `object`'s own and inherited enumerable properties, executing
1136
- * the `callback` for each property. The `callback` is bound to `thisArg` and
1137
- * invoked with three arguments; (value, key, object). Callbacks may exit iteration
1138
- * early by explicitly returning `false`.
979
+ * Creates a sorted array of all enumerable properties, own and inherited,
980
+ * of `object` that have function values.
1139
981
  *
1140
982
  * @static
1141
983
  * @memberOf _
984
+ * @alias methods
1142
985
  * @category Objects
1143
- * @param {Object} object The object to iterate over.
1144
- * @param {Function} callback The function called per iteration.
1145
- * @param {Mixed} [thisArg] The `this` binding of `callback`.
1146
- * @returns {Object} Returns `object`.
986
+ * @param {Object} object The object to inspect.
987
+ * @returns {Array} Returns a new array of property names that have function values.
1147
988
  * @example
1148
989
  *
1149
- * function Dog(name) {
1150
- * this.name = name;
1151
- * }
1152
- *
1153
- * Dog.prototype.bark = function() {
1154
- * alert('Woof, woof!');
1155
- * };
1156
- *
1157
- * _.forIn(new Dog('Dagny'), function(value, key) {
1158
- * alert(key);
1159
- * });
1160
- * // => alerts 'name' and 'bark' (order is not guaranteed)
990
+ * _.functions(_);
991
+ * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
1161
992
  */
1162
- var forIn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions, {
1163
- 'useHas': false
1164
- });
993
+ function functions(object) {
994
+ var result = [];
995
+ forIn(object, function(value, key) {
996
+ if (isFunction(value)) {
997
+ result.push(key);
998
+ }
999
+ });
1000
+ return result.sort();
1001
+ }
1165
1002
 
1166
1003
  /**
1167
- * Iterates over `object`'s own enumerable properties, executing the `callback`
1168
- * for each property. The `callback` is bound to `thisArg` and invoked with three
1169
- * arguments; (value, key, object). Callbacks may exit iteration early by explicitly
1170
- * returning `false`.
1004
+ * Checks if the specified object `property` exists and is a direct property,
1005
+ * instead of an inherited property.
1171
1006
  *
1172
1007
  * @static
1173
1008
  * @memberOf _
1174
1009
  * @category Objects
1175
- * @param {Object} object The object to iterate over.
1176
- * @param {Function} callback The function called per iteration.
1177
- * @param {Mixed} [thisArg] The `this` binding of `callback`.
1178
- * @returns {Object} Returns `object`.
1010
+ * @param {Object} object The object to check.
1011
+ * @param {String} property The property to check for.
1012
+ * @returns {Boolean} Returns `true` if key is a direct property, else `false`.
1179
1013
  * @example
1180
1014
  *
1181
- * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
1182
- * alert(key);
1183
- * });
1184
- * // => alerts '0', '1', and 'length' (order is not guaranteed)
1015
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
1016
+ * // => true
1185
1017
  */
1186
- var forOwn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions);
1018
+ function has(object, property) {
1019
+ return object ? hasOwnProperty.call(object, property) : false;
1020
+ }
1187
1021
 
1188
1022
  /**
1189
- * Creates a sorted array of all enumerable properties, own and inherited,
1190
- * of `object` that have function values.
1023
+ * Creates an object composed of the inverted keys and values of the given `object`.
1191
1024
  *
1192
1025
  * @static
1193
1026
  * @memberOf _
1194
- * @alias methods
1195
1027
  * @category Objects
1196
- * @param {Object} object The object to inspect.
1197
- * @returns {Array} Returns a new array of property names that have function values.
1028
+ * @param {Object} object The object to invert.
1029
+ * @returns {Object} Returns the created inverted object.
1198
1030
  * @example
1199
1031
  *
1200
- * _.functions(_);
1201
- * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
1032
+ * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' });
1033
+ * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed)
1202
1034
  */
1203
- var functions = createIterator({
1204
- 'useHas': false,
1205
- 'args': 'object',
1206
- 'init': '[]',
1207
- 'inLoop': 'isFunction(value) && result.push(index)',
1208
- 'bottom': 'result.sort()'
1209
- });
1035
+ function invert(object) {
1036
+ var result = {};
1037
+ forOwn(object, function(value, key) {
1038
+ result[value] = key;
1039
+ });
1040
+ return result;
1041
+ }
1210
1042
 
1211
1043
  /**
1212
- * Checks if the specified object `property` exists and is a direct property,
1213
- * instead of an inherited property.
1044
+ * Checks if `value` is an array.
1214
1045
  *
1215
1046
  * @static
1216
1047
  * @memberOf _
1217
1048
  * @category Objects
1218
- * @param {Object} object The object to check.
1219
- * @param {String} property The property to check for.
1220
- * @returns {Boolean} Returns `true` if key is a direct property, else `false`.
1049
+ * @param {Mixed} value The value to check.
1050
+ * @returns {Boolean} Returns `true` if the `value` is an array, else `false`.
1221
1051
  * @example
1222
1052
  *
1223
- * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
1053
+ * (function() { return _.isArray(arguments); })();
1054
+ * // => false
1055
+ *
1056
+ * _.isArray([1, 2, 3]);
1224
1057
  * // => true
1225
1058
  */
1226
- function has(object, property) {
1227
- return object ? hasOwnProperty.call(object, property) : false;
1228
- }
1059
+ var isArray = nativeIsArray || function(value) {
1060
+ return toString.call(value) == arrayClass;
1061
+ };
1229
1062
 
1230
1063
  /**
1231
1064
  * Checks if `value` is a boolean (`true` or `false`) value.
@@ -1299,21 +1132,24 @@
1299
1132
  * _.isEmpty('');
1300
1133
  * // => true
1301
1134
  */
1302
- var isEmpty = createIterator({
1303
- 'args': 'value',
1304
- 'init': 'true',
1305
- 'top':
1306
- 'var className = toString.call(value),\n' +
1307
- ' length = value.length;\n' +
1308
- 'if (arrayLikeClasses[className]' +
1309
- (noArgsClass ? ' || isArguments(value)' : '') + ' ||\n' +
1310
- ' (className == objectClass && length === +length &&\n' +
1311
- ' isFunction(value.splice))' +
1312
- ') return !length',
1313
- 'inLoop': {
1314
- 'object': 'return false'
1135
+ function isEmpty(value) {
1136
+ var result = true;
1137
+ if (!value) {
1138
+ return result;
1315
1139
  }
1316
- });
1140
+ var className = toString.call(value),
1141
+ length = value.length;
1142
+
1143
+ if ((className == arrayClass || className == stringClass ||
1144
+ className == argsClass || (noArgsClass && isArguments(value))) ||
1145
+ (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
1146
+ return !length;
1147
+ }
1148
+ forOwn(value, function() {
1149
+ return (result = false);
1150
+ });
1151
+ return result;
1152
+ }
1317
1153
 
1318
1154
  /**
1319
1155
  * Performs a deep comparison between two values to determine if they are
@@ -1339,19 +1175,14 @@
1339
1175
  * // => true
1340
1176
  */
1341
1177
  function isEqual(a, b, stackA, stackB) {
1342
- // a strict comparison is necessary because `null == undefined`
1343
- if (a == null || b == null) {
1344
- return a === b;
1345
- }
1346
1178
  // exit early for identical values
1347
1179
  if (a === b) {
1348
1180
  // treat `+0` vs. `-0` as not equal
1349
1181
  return a !== 0 || (1 / a == 1 / b);
1350
1182
  }
1351
- // unwrap any `lodash` wrapped values
1352
- if (objectTypes[typeof a] || objectTypes[typeof b]) {
1353
- a = a.__wrapped__ || a;
1354
- b = b.__wrapped__ || b;
1183
+ // a strict comparison is necessary because `null == undefined`
1184
+ if (a == null || b == null) {
1185
+ return a === b;
1355
1186
  }
1356
1187
  // compare [[Class]] names
1357
1188
  var className = toString.call(a);
@@ -1379,17 +1210,32 @@
1379
1210
  return a == b + '';
1380
1211
  }
1381
1212
  // exit early, in older browsers, if `a` is array-like but not `b`
1382
- var isArr = arrayLikeClasses[className];
1213
+ var isArr = className == arrayClass || className == argsClass;
1383
1214
  if (noArgsClass && !isArr && (isArr = isArguments(a)) && !isArguments(b)) {
1384
1215
  return false;
1385
1216
  }
1386
- // exit for functions and DOM nodes
1387
- if (!isArr && (className != objectClass || (noNodeClass && (
1388
- (typeof a.toString != 'function' && typeof (a + '') == 'string') ||
1389
- (typeof b.toString != 'function' && typeof (b + '') == 'string'))))) {
1390
- return false;
1217
+ if (!isArr) {
1218
+ // unwrap any `lodash` wrapped values
1219
+ if (a.__wrapped__ || b.__wrapped__) {
1220
+ return isEqual(a.__wrapped__ || a, b.__wrapped__ || b);
1221
+ }
1222
+ // exit for functions and DOM nodes
1223
+ if (className != objectClass || (noNodeClass && (
1224
+ (typeof a.toString != 'function' && typeof (a + '') == 'string') ||
1225
+ (typeof b.toString != 'function' && typeof (b + '') == 'string')))) {
1226
+ return false;
1227
+ }
1228
+ var ctorA = a.constructor,
1229
+ ctorB = b.constructor;
1230
+
1231
+ // non `Object` object instances with different constructors are not equal
1232
+ if (ctorA != ctorB && !(
1233
+ isFunction(ctorA) && ctorA instanceof ctorA &&
1234
+ isFunction(ctorB) && ctorB instanceof ctorB
1235
+ )) {
1236
+ return false;
1237
+ }
1391
1238
  }
1392
-
1393
1239
  // assume cyclic structures are equal
1394
1240
  // the algorithm for detecting cyclic structures is adapted from ES 5.1
1395
1241
  // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
@@ -1427,34 +1273,23 @@
1427
1273
  }
1428
1274
  return result;
1429
1275
  }
1430
-
1431
- var ctorA = a.constructor,
1432
- ctorB = b.constructor;
1433
-
1434
- // non `Object` object instances with different constructors are not equal
1435
- if (ctorA != ctorB && !(
1436
- isFunction(ctorA) && ctorA instanceof ctorA &&
1437
- isFunction(ctorB) && ctorB instanceof ctorB
1438
- )) {
1439
- return false;
1440
- }
1441
1276
  // deep compare objects
1442
- for (var prop in a) {
1443
- if (hasOwnProperty.call(a, prop)) {
1277
+ for (var key in a) {
1278
+ if (hasOwnProperty.call(a, key)) {
1444
1279
  // count the number of properties.
1445
1280
  size++;
1446
1281
  // deep compare each property value.
1447
- if (!(hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stackA, stackB))) {
1282
+ if (!(hasOwnProperty.call(b, key) && isEqual(a[key], b[key], stackA, stackB))) {
1448
1283
  return false;
1449
1284
  }
1450
1285
  }
1451
1286
  }
1452
1287
  // ensure both objects have the same number of properties
1453
- for (prop in b) {
1288
+ for (key in b) {
1454
1289
  // The JS engine in Adobe products, like InDesign, has a bug that causes
1455
1290
  // `!size--` to throw an error so it must be wrapped in parentheses.
1456
1291
  // https://github.com/documentcloud/underscore/issues/355
1457
- if (hasOwnProperty.call(b, prop) && !(size--)) {
1292
+ if (hasOwnProperty.call(b, key) && !(size--)) {
1458
1293
  // `size` will be `-1` if `b` has more properties than `a`
1459
1294
  return false;
1460
1295
  }
@@ -1462,9 +1297,9 @@
1462
1297
  // handle JScript [[DontEnum]] bug
1463
1298
  if (hasDontEnumBug) {
1464
1299
  while (++index < 7) {
1465
- prop = shadowed[index];
1466
- if (hasOwnProperty.call(a, prop) &&
1467
- !(hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stackA, stackB))) {
1300
+ key = shadowed[index];
1301
+ if (hasOwnProperty.call(a, key) &&
1302
+ !(hasOwnProperty.call(b, key) && isEqual(a[key], b[key], stackA, stackB))) {
1468
1303
  return false;
1469
1304
  }
1470
1305
  }
@@ -1473,10 +1308,10 @@
1473
1308
  }
1474
1309
 
1475
1310
  /**
1476
- * Checks if `value` is a finite number.
1311
+ * Checks if `value` is, or can be coerced to, a finite number.
1477
1312
  *
1478
1313
  * Note: This is not the same as native `isFinite`, which will return true for
1479
- * booleans and other values. See http://es5.github.com/#x15.1.2.5.
1314
+ * booleans and empty strings. See http://es5.github.com/#x15.1.2.5.
1480
1315
  *
1481
1316
  * @deprecated
1482
1317
  * @static
@@ -1490,13 +1325,42 @@
1490
1325
  * // => true
1491
1326
  *
1492
1327
  * _.isFinite('10');
1328
+ * // => true
1329
+ *
1330
+ * _.isFinite(true);
1331
+ * // => false
1332
+ *
1333
+ * _.isFinite('');
1493
1334
  * // => false
1494
1335
  *
1495
1336
  * _.isFinite(Infinity);
1496
1337
  * // => false
1497
1338
  */
1498
1339
  function isFinite(value) {
1499
- return nativeIsFinite(value) && toString.call(value) == numberClass;
1340
+ return nativeIsFinite(value ? +value : parseFloat(value));
1341
+ }
1342
+
1343
+ /**
1344
+ * Checks if `value` is a function.
1345
+ *
1346
+ * @static
1347
+ * @memberOf _
1348
+ * @category Objects
1349
+ * @param {Mixed} value The value to check.
1350
+ * @returns {Boolean} Returns `true` if the `value` is a function, else `false`.
1351
+ * @example
1352
+ *
1353
+ * _.isFunction(_);
1354
+ * // => true
1355
+ */
1356
+ function isFunction(value) {
1357
+ return typeof value == 'function';
1358
+ }
1359
+ // fallback for older versions of Chrome and Safari
1360
+ if (isFunction(/x/)) {
1361
+ isFunction = function(value) {
1362
+ return toString.call(value) == funcClass;
1363
+ };
1500
1364
  }
1501
1365
 
1502
1366
  /**
@@ -1597,6 +1461,42 @@
1597
1461
  return toString.call(value) == numberClass;
1598
1462
  }
1599
1463
 
1464
+ /**
1465
+ * Checks if a given `value` is an object created by the `Object` constructor.
1466
+ *
1467
+ * @static
1468
+ * @memberOf _
1469
+ * @category Objects
1470
+ * @param {Mixed} value The value to check.
1471
+ * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
1472
+ * @example
1473
+ *
1474
+ * function Stooge(name, age) {
1475
+ * this.name = name;
1476
+ * this.age = age;
1477
+ * }
1478
+ *
1479
+ * _.isPlainObject(new Stooge('moe', 40));
1480
+ * // => false
1481
+ *
1482
+ * _.isPlainObject([1, 2, 3]);
1483
+ * // => false
1484
+ *
1485
+ * _.isPlainObject({ 'name': 'moe', 'age': 40 });
1486
+ * // => true
1487
+ */
1488
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
1489
+ if (!(value && typeof value == 'object')) {
1490
+ return false;
1491
+ }
1492
+ var valueOf = value.valueOf,
1493
+ objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
1494
+
1495
+ return objProto
1496
+ ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value))
1497
+ : shimIsPlainObject(value);
1498
+ };
1499
+
1600
1500
  /**
1601
1501
  * Checks if `value` is a regular expression.
1602
1502
  *
@@ -1687,7 +1587,7 @@
1687
1587
  * @param- {Object} [indicator] Internally used to indicate that the `stack`
1688
1588
  * argument is an array of traversed objects instead of another source object.
1689
1589
  * @param- {Array} [stackA=[]] Internally used to track traversed source objects.
1690
- * @param- {Array} [stackB=[]] Internally used to associate clones with their
1590
+ * @param- {Array} [stackB=[]] Internally used to associate values with their
1691
1591
  * source counterparts.
1692
1592
  * @returns {Object} Returns the destination object.
1693
1593
  * @example
@@ -1705,37 +1605,50 @@
1705
1605
  * _.merge(stooges, ages);
1706
1606
  * // => [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }]
1707
1607
  */
1708
- var merge = createIterator(extendIteratorOptions, {
1709
- 'args': 'object, source, indicator',
1710
- 'top':
1711
- 'var isArr, args = arguments, argsIndex = 0;\n' +
1712
- 'if (indicator == compareAscending) {\n' +
1713
- ' var argsLength = 2, stackA = args[3], stackB = args[4]\n' +
1714
- '} else {\n' +
1715
- ' var argsLength = args.length, stackA = [], stackB = []\n' +
1716
- '}\n' +
1717
- 'while (++argsIndex < argsLength) {\n' +
1718
- ' if (iteratee = args[argsIndex]) {',
1719
- 'inLoop':
1720
- 'if ((source = value) && ((isArr = isArray(source)) || isPlainObject(source))) {\n' +
1721
- ' var found = false, stackLength = stackA.length;\n' +
1722
- ' while (stackLength--) {\n' +
1723
- ' if (found = stackA[stackLength] == source) break\n' +
1724
- ' }\n' +
1725
- ' if (found) {\n' +
1726
- ' result[index] = stackB[stackLength]\n' +
1727
- ' } else {\n' +
1728
- ' stackA.push(source);\n' +
1729
- ' stackB.push(value = (value = result[index], isArr)\n' +
1730
- ' ? (isArray(value) ? value : [])\n' +
1731
- ' : (isPlainObject(value) ? value : {})\n' +
1732
- ' );\n' +
1733
- ' result[index] = callee(value, source, compareAscending, stackA, stackB)\n' +
1734
- ' }\n' +
1735
- '} else if (source != null) {\n' +
1736
- ' result[index] = source\n' +
1737
- '}'
1738
- });
1608
+ function merge(object, source, indicator) {
1609
+ var args = arguments,
1610
+ index = 0,
1611
+ length = 2,
1612
+ stackA = args[3],
1613
+ stackB = args[4];
1614
+
1615
+ if (indicator !== indicatorObject) {
1616
+ stackA = [];
1617
+ stackB = [];
1618
+ length = args.length;
1619
+ }
1620
+ while (++index < length) {
1621
+ forOwn(args[index], function(source, key) {
1622
+ var found, isArr, value;
1623
+ if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
1624
+ // avoid merging previously merged cyclic sources
1625
+ var stackLength = stackA.length;
1626
+ while (stackLength--) {
1627
+ found = stackA[stackLength] == source;
1628
+ if (found) {
1629
+ break;
1630
+ }
1631
+ }
1632
+ if (found) {
1633
+ object[key] = stackB[stackLength];
1634
+ }
1635
+ else {
1636
+ // add `source` and associated `value` to the stack of traversed objects
1637
+ stackA.push(source);
1638
+ stackB.push(value = (value = object[key], isArr)
1639
+ ? (isArray(value) ? value : [])
1640
+ : (isPlainObject(value) ? value : {})
1641
+ );
1642
+ // recursively merge objects and arrays (susceptible to call stack limits)
1643
+ object[key] = merge(value, source, indicatorObject, stackA, stackB);
1644
+ }
1645
+ } else if (source != null) {
1646
+ object[key] = source;
1647
+ }
1648
+ });
1649
+ }
1650
+ return object;
1651
+ }
1739
1652
 
1740
1653
  /**
1741
1654
  * Creates a shallow clone of `object` excluding the specified properties.
@@ -1762,7 +1675,25 @@
1762
1675
  * });
1763
1676
  * // => { 'name': 'moe' }
1764
1677
  */
1765
- var omit = createIterator(omitIteratorOptions);
1678
+ function omit(object, callback, thisArg) {
1679
+ var isFunc = typeof callback == 'function',
1680
+ result = {};
1681
+
1682
+ if (isFunc) {
1683
+ callback = createCallback(callback, thisArg);
1684
+ } else {
1685
+ var props = concat.apply(arrayRef, arguments);
1686
+ }
1687
+ forIn(object, function(value, key, object) {
1688
+ if (isFunc
1689
+ ? !callback(value, key, object)
1690
+ : indexOf(props, key, 1) < 0
1691
+ ) {
1692
+ result[key] = value;
1693
+ }
1694
+ });
1695
+ return result;
1696
+ }
1766
1697
 
1767
1698
  /**
1768
1699
  * Creates a two dimensional array of the given object's key-value pairs,
@@ -1778,11 +1709,13 @@
1778
1709
  * _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 });
1779
1710
  * // => [['moe', 30], ['larry', 40], ['curly', 50]] (order is not guaranteed)
1780
1711
  */
1781
- var pairs = createIterator({
1782
- 'args': 'object',
1783
- 'init':'[]',
1784
- 'inLoop': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '([index, value])'
1785
- });
1712
+ function pairs(object) {
1713
+ var result = [];
1714
+ forOwn(object, function(value, key) {
1715
+ result.push([key, value]);
1716
+ });
1717
+ return result;
1718
+ }
1786
1719
 
1787
1720
  /**
1788
1721
  * Creates a shallow clone of `object` composed of the specified properties.
@@ -1809,22 +1742,29 @@
1809
1742
  * });
1810
1743
  * // => { 'name': 'moe' }
1811
1744
  */
1812
- var pick = createIterator(omitIteratorOptions, {
1813
- 'top':
1814
- 'if (typeof callback != \'function\') {\n' +
1815
- ' var index = 0,\n' +
1816
- ' props = concat.apply(ArrayProto, arguments),\n' +
1817
- ' length = props.length;\n' +
1818
- ' while (++index < length) {\n' +
1819
- ' var prop = props[index];\n' +
1820
- ' if (prop in object) result[prop] = object[prop]\n' +
1821
- ' }\n' +
1822
- '} else {\n' +
1823
- ' callback = createCallback(callback, thisArg)',
1824
- 'inLoop':
1825
- 'if (callback(value, index, object)) result[index] = value',
1826
- 'bottom': '}'
1827
- });
1745
+ function pick(object, callback, thisArg) {
1746
+ var result = {};
1747
+ if (typeof callback != 'function') {
1748
+ var index = 0,
1749
+ props = concat.apply(arrayRef, arguments),
1750
+ length = props.length;
1751
+
1752
+ while (++index < length) {
1753
+ var key = props[index];
1754
+ if (key in object) {
1755
+ result[key] = object[key];
1756
+ }
1757
+ }
1758
+ } else {
1759
+ callback = createCallback(callback, thisArg);
1760
+ forIn(object, function(value, key, object) {
1761
+ if (callback(value, key, object)) {
1762
+ result[key] = value;
1763
+ }
1764
+ });
1765
+ }
1766
+ return result;
1767
+ }
1828
1768
 
1829
1769
  /**
1830
1770
  * Creates an array composed of the own enumerable property values of `object`.
@@ -1839,11 +1779,13 @@
1839
1779
  * _.values({ 'one': 1, 'two': 2, 'three': 3 });
1840
1780
  * // => [1, 2, 3]
1841
1781
  */
1842
- var values = createIterator({
1843
- 'args': 'object',
1844
- 'init': '[]',
1845
- 'inLoop': 'result.push(value)'
1846
- });
1782
+ function values(object) {
1783
+ var result = [];
1784
+ forOwn(object, function(value) {
1785
+ result.push(value);
1786
+ });
1787
+ return result;
1788
+ }
1847
1789
 
1848
1790
  /*--------------------------------------------------------------------------*/
1849
1791
 
@@ -1869,15 +1811,18 @@
1869
1811
  * _.contains('curly', 'ur');
1870
1812
  * // => true
1871
1813
  */
1872
- var contains = createIterator({
1873
- 'args': 'collection, target',
1874
- 'init': 'false',
1875
- 'noCharByIndex': false,
1876
- 'beforeLoop': {
1877
- 'array': 'if (toString.call(collection) == stringClass) return collection.indexOf(target) > -1'
1878
- },
1879
- 'inLoop': 'if (value === target) return true'
1880
- });
1814
+ function contains(collection, target) {
1815
+ var length = collection ? collection.length : 0;
1816
+ if (typeof length == 'number') {
1817
+ return (toString.call(collection) == stringClass
1818
+ ? collection.indexOf(target)
1819
+ : indexOf(collection, target)
1820
+ ) > -1;
1821
+ }
1822
+ return some(collection, function(value) {
1823
+ return value === target;
1824
+ });
1825
+ }
1881
1826
 
1882
1827
  /**
1883
1828
  * Creates an object composed of keys returned from running each element of
@@ -1905,7 +1850,15 @@
1905
1850
  * _.countBy(['one', 'two', 'three'], 'length');
1906
1851
  * // => { '3': 2, '5': 1 }
1907
1852
  */
1908
- var countBy = createIterator(baseIteratorOptions, countByIteratorOptions);
1853
+ function countBy(collection, callback, thisArg) {
1854
+ var result = {};
1855
+ callback = createCallback(callback, thisArg);
1856
+ forEach(collection, function(value, key, collection) {
1857
+ key = callback(value, key, collection);
1858
+ (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
1859
+ });
1860
+ return result;
1861
+ }
1909
1862
 
1910
1863
  /**
1911
1864
  * Checks if the `callback` returns a truthy value for **all** elements of a
@@ -1926,7 +1879,14 @@
1926
1879
  * _.every([true, 1, null, 'yes'], Boolean);
1927
1880
  * // => false
1928
1881
  */
1929
- var every = createIterator(baseIteratorOptions, everyIteratorOptions);
1882
+ function every(collection, callback, thisArg) {
1883
+ var result = true;
1884
+ callback = createCallback(callback, thisArg);
1885
+ forEach(collection, function(value, index, collection) {
1886
+ return (result = callback(value, index, collection));
1887
+ });
1888
+ return !!result;
1889
+ }
1930
1890
 
1931
1891
  /**
1932
1892
  * Examines each element in a `collection`, returning an array of all elements
@@ -1946,7 +1906,16 @@
1946
1906
  * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
1947
1907
  * // => [2, 4, 6]
1948
1908
  */
1949
- var filter = createIterator(baseIteratorOptions, filterIteratorOptions);
1909
+ function filter(collection, callback, thisArg) {
1910
+ var result = [];
1911
+ callback = createCallback(callback, thisArg);
1912
+ forEach(collection, function(value, index, collection) {
1913
+ if (callback(value, index, collection)) {
1914
+ result.push(value);
1915
+ }
1916
+ });
1917
+ return result;
1918
+ }
1950
1919
 
1951
1920
  /**
1952
1921
  * Examines each element in a `collection`, returning the first one the `callback`
@@ -1968,10 +1937,14 @@
1968
1937
  * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
1969
1938
  * // => 2
1970
1939
  */
1971
- var find = createIterator(baseIteratorOptions, forEachIteratorOptions, {
1972
- 'init': 'undefined',
1973
- 'inLoop': 'if (callback(value, index, collection)) return value'
1974
- });
1940
+ function find(collection, callback, thisArg) {
1941
+ var result;
1942
+ callback = createCallback(callback, thisArg);
1943
+ some(collection, function(value, index, collection) {
1944
+ return callback(value, index, collection) && (result = value, true);
1945
+ });
1946
+ return result;
1947
+ }
1975
1948
 
1976
1949
  /**
1977
1950
  * Iterates over a `collection`, executing the `callback` for each element in
@@ -1995,14 +1968,14 @@
1995
1968
  * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
1996
1969
  * // => alerts each number (order is not guaranteed)
1997
1970
  */
1998
- var forEach = createIterator(baseIteratorOptions, forEachIteratorOptions);
1971
+ var forEach = createIterator(forEachIteratorOptions);
1999
1972
 
2000
1973
  /**
2001
1974
  * Creates an object composed of keys returned from running each element of
2002
1975
  * `collection` through a `callback`. The corresponding value of each key is an
2003
1976
  * array of elements passed to `callback` that returned the key. The `callback`
2004
1977
  * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
2005
- * The `callback` argument may also be the name of a property to count by (e.g. 'length').
1978
+ * The `callback` argument may also be the name of a property to group by (e.g. 'length').
2006
1979
  *
2007
1980
  * @static
2008
1981
  * @memberOf _
@@ -2023,11 +1996,15 @@
2023
1996
  * _.groupBy(['one', 'two', 'three'], 'length');
2024
1997
  * // => { '3': ['one', 'two'], '5': ['three'] }
2025
1998
  */
2026
- var groupBy = createIterator(baseIteratorOptions, countByIteratorOptions, {
2027
- 'inLoop':
2028
- 'var prop = callback(value, index, collection);\n' +
2029
- '(hasOwnProperty.call(result, prop) ? result[prop] : result[prop] = []).push(value)'
2030
- });
1999
+ function groupBy(collection, callback, thisArg) {
2000
+ var result = {};
2001
+ callback = createCallback(callback, thisArg);
2002
+ forEach(collection, function(value, key, collection) {
2003
+ key = callback(value, key, collection);
2004
+ (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
2005
+ });
2006
+ return result;
2007
+ }
2031
2008
 
2032
2009
  /**
2033
2010
  * Invokes the method named by `methodName` on each element in the `collection`,
@@ -2051,19 +2028,16 @@
2051
2028
  * _.invoke([123, 456], String.prototype.split, '');
2052
2029
  * // => [['1', '2', '3'], ['4', '5', '6']]
2053
2030
  */
2054
- var invoke = createIterator(mapIteratorOptions, {
2055
- 'args': 'collection, methodName',
2056
- 'top':
2057
- 'var args = slice.call(arguments, 2),\n' +
2058
- ' isFunc = typeof methodName == \'function\'',
2059
- 'inLoop': {
2060
- 'array':
2061
- 'result[index] = (isFunc ? methodName : value[methodName]).apply(value, args)',
2062
- 'object':
2063
- 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') +
2064
- '((isFunc ? methodName : value[methodName]).apply(value, args))'
2065
- }
2066
- });
2031
+ function invoke(collection, methodName) {
2032
+ var args = slice.call(arguments, 2),
2033
+ isFunc = typeof methodName == 'function',
2034
+ result = [];
2035
+
2036
+ forEach(collection, function(value) {
2037
+ result.push((isFunc ? methodName : value[methodName]).apply(value, args));
2038
+ });
2039
+ return result;
2040
+ }
2067
2041
 
2068
2042
  /**
2069
2043
  * Creates an array of values by running each element in the `collection`
@@ -2086,7 +2060,23 @@
2086
2060
  * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
2087
2061
  * // => [3, 6, 9] (order is not guaranteed)
2088
2062
  */
2089
- var map = createIterator(baseIteratorOptions, mapIteratorOptions);
2063
+ function map(collection, callback, thisArg) {
2064
+ var index = -1,
2065
+ length = collection ? collection.length : 0,
2066
+ result = Array(typeof length == 'number' ? length : 0);
2067
+
2068
+ callback = createCallback(callback, thisArg);
2069
+ if (isArray(collection)) {
2070
+ while (++index < length) {
2071
+ result[index] = callback(collection[index], index, collection);
2072
+ }
2073
+ } else {
2074
+ forEach(collection, function(value, key, collection) {
2075
+ result[++index] = callback(value, key, collection);
2076
+ });
2077
+ }
2078
+ return result;
2079
+ }
2090
2080
 
2091
2081
  /**
2092
2082
  * Retrieves the maximum value of an `array`. If `callback` is passed,
@@ -2118,7 +2108,7 @@
2118
2108
  length = collection ? collection.length : 0,
2119
2109
  result = computed;
2120
2110
 
2121
- if (callback || length !== +length) {
2111
+ if (callback || typeof length != 'number') {
2122
2112
  callback = createCallback(callback, thisArg);
2123
2113
  forEach(collection, function(value, index, collection) {
2124
2114
  var current = callback(value, index, collection);
@@ -2161,7 +2151,7 @@
2161
2151
  length = collection ? collection.length : 0,
2162
2152
  result = computed;
2163
2153
 
2164
- if (callback || length !== +length) {
2154
+ if (callback || typeof length != 'number') {
2165
2155
  callback = createCallback(callback, thisArg);
2166
2156
  forEach(collection, function(value, index, collection) {
2167
2157
  var current = callback(value, index, collection);
@@ -2201,13 +2191,13 @@
2201
2191
  * _.pluck(stooges, 'name');
2202
2192
  * // => ['moe', 'larry', 'curly']
2203
2193
  */
2204
- var pluck = createIterator(mapIteratorOptions, {
2205
- 'args': 'collection, property',
2206
- 'inLoop': {
2207
- 'array': 'result[index] = value[property]',
2208
- 'object': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '(value[property])'
2209
- }
2210
- });
2194
+ function pluck(collection, property) {
2195
+ var result = [];
2196
+ forEach(collection, function(value) {
2197
+ result.push(value[property]);
2198
+ });
2199
+ return result;
2200
+ }
2211
2201
 
2212
2202
  /**
2213
2203
  * Boils down a `collection` to a single value. The initial state of the
@@ -2229,24 +2219,16 @@
2229
2219
  * var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; });
2230
2220
  * // => 6
2231
2221
  */
2232
- var reduce = createIterator({
2233
- 'args': 'collection, callback, accumulator, thisArg',
2234
- 'init': 'accumulator',
2235
- 'top':
2236
- 'var noaccum = arguments.length < 3;\n' +
2237
- 'callback = createCallback(callback, thisArg)',
2238
- 'beforeLoop': {
2239
- 'array': 'if (noaccum) result = iteratee[++index]'
2240
- },
2241
- 'inLoop': {
2242
- 'array':
2243
- 'result = callback(result, value, index, collection)',
2244
- 'object':
2245
- 'result = noaccum\n' +
2246
- ' ? (noaccum = false, value)\n' +
2247
- ' : callback(result, value, index, collection)'
2248
- }
2249
- });
2222
+ function reduce(collection, callback, accumulator, thisArg) {
2223
+ var noaccum = arguments.length < 3;
2224
+ callback = createCallback(callback, thisArg);
2225
+ forEach(collection, function(value, index, collection) {
2226
+ accumulator = noaccum
2227
+ ? (noaccum = false, value)
2228
+ : callback(accumulator, value, index, collection)
2229
+ });
2230
+ return accumulator;
2231
+ }
2250
2232
 
2251
2233
  /**
2252
2234
  * The right-associative version of `_.reduce`.
@@ -2271,17 +2253,17 @@
2271
2253
  length = collection ? collection.length : 0,
2272
2254
  noaccum = arguments.length < 3;
2273
2255
 
2274
- if (length !== +length) {
2256
+ if (typeof length != 'number') {
2275
2257
  var props = keys(collection);
2276
2258
  length = props.length;
2277
2259
  } else if (noCharByIndex && toString.call(collection) == stringClass) {
2278
2260
  iteratee = collection.split('');
2279
2261
  }
2280
- forEach(collection, function(value, index, object) {
2262
+ forEach(collection, function(value, index, collection) {
2281
2263
  index = props ? props[--length] : --length;
2282
2264
  accumulator = noaccum
2283
2265
  ? (noaccum = false, iteratee[index])
2284
- : callback.call(thisArg, accumulator, iteratee[index], index, object);
2266
+ : callback.call(thisArg, accumulator, iteratee[index], index, collection);
2285
2267
  });
2286
2268
  return accumulator;
2287
2269
  }
@@ -2303,9 +2285,12 @@
2303
2285
  * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
2304
2286
  * // => [1, 3, 5]
2305
2287
  */
2306
- var reject = createIterator(baseIteratorOptions, filterIteratorOptions, {
2307
- 'inLoop': '!' + filterIteratorOptions.inLoop
2308
- });
2288
+ function reject(collection, callback, thisArg) {
2289
+ callback = createCallback(callback, thisArg);
2290
+ return filter(collection, function(value, index, collection) {
2291
+ return !callback(value, index, collection);
2292
+ });
2293
+ }
2309
2294
 
2310
2295
  /**
2311
2296
  * Creates an array of shuffled `array` values, using a version of the
@@ -2355,7 +2340,7 @@
2355
2340
  */
2356
2341
  function size(collection) {
2357
2342
  var length = collection ? collection.length : 0;
2358
- return length === +length ? length : keys(collection).length;
2343
+ return typeof length == 'number' ? length : keys(collection).length;
2359
2344
  }
2360
2345
 
2361
2346
  /**
@@ -2378,10 +2363,14 @@
2378
2363
  * _.some([null, 0, 'yes', false]);
2379
2364
  * // => true
2380
2365
  */
2381
- var some = createIterator(baseIteratorOptions, everyIteratorOptions, {
2382
- 'init': 'false',
2383
- 'inLoop': everyIteratorOptions.inLoop.replace('!', '')
2384
- });
2366
+ function some(collection, callback, thisArg) {
2367
+ var result;
2368
+ callback = createCallback(callback, thisArg);
2369
+ forEach(collection, function(value, index, collection) {
2370
+ return !(result = callback(value, index, collection));
2371
+ });
2372
+ return !!result;
2373
+ }
2385
2374
 
2386
2375
  /**
2387
2376
  * Creates an array, stable sorted in ascending order by the results of
@@ -2408,28 +2397,24 @@
2408
2397
  * _.sortBy(['larry', 'brendan', 'moe'], 'length');
2409
2398
  * // => ['moe', 'larry', 'brendan']
2410
2399
  */
2411
- var sortBy = createIterator(baseIteratorOptions, countByIteratorOptions, mapIteratorOptions, {
2412
- 'inLoop': {
2413
- 'array':
2414
- 'result[index] = {\n' +
2415
- ' criteria: callback(value, index, collection),\n' +
2416
- ' index: index,\n' +
2417
- ' value: value\n' +
2418
- '}',
2419
- 'object':
2420
- 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '({\n' +
2421
- ' criteria: callback(value, index, collection),\n' +
2422
- ' index: index,\n' +
2423
- ' value: value\n' +
2424
- '})'
2425
- },
2426
- 'bottom':
2427
- 'result.sort(compareAscending);\n' +
2428
- 'length = result.length;\n' +
2429
- 'while (length--) {\n' +
2430
- ' result[length] = result[length].value\n' +
2431
- '}'
2432
- });
2400
+ function sortBy(collection, callback, thisArg) {
2401
+ var result = [];
2402
+ callback = createCallback(callback, thisArg);
2403
+ forEach(collection, function(value, index, collection) {
2404
+ result.push({
2405
+ 'criteria': callback(value, index, collection),
2406
+ 'index': index,
2407
+ 'value': value
2408
+ });
2409
+ });
2410
+
2411
+ var length = result.length;
2412
+ result.sort(compareAscending);
2413
+ while (length--) {
2414
+ result[length] = result[length].value;
2415
+ }
2416
+ return result;
2417
+ }
2433
2418
 
2434
2419
  /**
2435
2420
  * Converts the `collection`, to an array.
@@ -2445,11 +2430,7 @@
2445
2430
  * // => [2, 3, 4]
2446
2431
  */
2447
2432
  function toArray(collection) {
2448
- if (!collection) {
2449
- return [];
2450
- }
2451
- var length = collection.length;
2452
- if (length === +length) {
2433
+ if (collection && typeof collection.length == 'number') {
2453
2434
  return (noArraySliceOnStrings ? toString.call(collection) == stringClass : typeof collection == 'string')
2454
2435
  ? collection.split('')
2455
2436
  : slice.call(collection);
@@ -2465,7 +2446,7 @@
2465
2446
  * @memberOf _
2466
2447
  * @category Collections
2467
2448
  * @param {Array|Object|String} collection The collection to iterate over.
2468
- * @param {Object} properties The object of properties/values to filter by.
2449
+ * @param {Object} properties The object of property values to filter by.
2469
2450
  * @returns {Array} Returns a new array of elements that contain the given `properties`.
2470
2451
  * @example
2471
2452
  *
@@ -2478,19 +2459,22 @@
2478
2459
  * _.where(stooges, { 'age': 40 });
2479
2460
  * // => [{ 'name': 'moe', 'age': 40 }]
2480
2461
  */
2481
- var where = createIterator(filterIteratorOptions, {
2482
- 'args': 'collection, properties',
2483
- 'top':
2484
- 'var props = [];\n' +
2485
- 'forIn(properties, function(value, prop) { props.push(prop) });\n' +
2486
- 'var propsLength = props.length',
2487
- 'inLoop':
2488
- 'for (var pass = true, propIndex = 0; propIndex < propsLength; propIndex++) {\n' +
2489
- ' var prop = props[propIndex];\n' +
2490
- ' if (!(pass = value[prop] === properties[prop])) break\n' +
2491
- '}\n' +
2492
- 'pass && result.push(value)'
2493
- });
2462
+ function where(collection, properties) {
2463
+ var props = [];
2464
+ forIn(properties, function(value, prop) {
2465
+ props.push(prop);
2466
+ });
2467
+ return filter(collection, function(object) {
2468
+ var length = props.length;
2469
+ while (length--) {
2470
+ var result = object[props[length]] === properties[props[length]];
2471
+ if (!result) {
2472
+ break;
2473
+ }
2474
+ }
2475
+ return !!result;
2476
+ });
2477
+ }
2494
2478
 
2495
2479
  /*--------------------------------------------------------------------------*/
2496
2480
 
@@ -2539,14 +2523,11 @@
2539
2523
  * // => [1, 3, 4]
2540
2524
  */
2541
2525
  function difference(array) {
2542
- var result = [];
2543
- if (!array) {
2544
- return result;
2545
- }
2546
2526
  var index = -1,
2547
- length = array.length,
2548
- flattened = concat.apply(ArrayProto, arguments),
2549
- contains = cachedContains(flattened, length);
2527
+ length = array ? array.length : 0,
2528
+ flattened = concat.apply(arrayRef, arguments),
2529
+ contains = cachedContains(flattened, length),
2530
+ result = [];
2550
2531
 
2551
2532
  while (++index < length) {
2552
2533
  var value = array[index];
@@ -2699,23 +2680,22 @@
2699
2680
  * // => [1, 2]
2700
2681
  */
2701
2682
  function intersection(array) {
2702
- var argsLength = arguments.length,
2703
- cache = [],
2704
- index = -1,
2705
- length = array ? array.length : 0,
2683
+ var args = arguments,
2684
+ argsLength = args.length,
2685
+ cache = {},
2706
2686
  result = [];
2707
2687
 
2708
- array: while (++index < length) {
2709
- var value = array[index];
2688
+ forEach(array, function(value) {
2710
2689
  if (indexOf(result, value) < 0) {
2711
- for (var argsIndex = 1; argsIndex < argsLength; argsIndex++) {
2712
- if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(arguments[argsIndex])))(value)) {
2713
- continue array;
2690
+ var length = argsLength;
2691
+ while (--length) {
2692
+ if (!(cache[length] || (cache[length] = cachedContains(args[length])))(value)) {
2693
+ return;
2714
2694
  }
2715
2695
  }
2716
2696
  result.push(value);
2717
2697
  }
2718
- }
2698
+ });
2719
2699
  return result;
2720
2700
  }
2721
2701
 
@@ -2927,18 +2907,14 @@
2927
2907
  var low = 0,
2928
2908
  high = array ? array.length : low;
2929
2909
 
2930
- if (callback) {
2931
- callback = createCallback(callback, thisArg);
2932
- value = callback(value);
2933
- while (low < high) {
2934
- var mid = (low + high) >>> 1;
2935
- callback(array[mid]) < value ? low = mid + 1 : high = mid;
2936
- }
2937
- } else {
2938
- while (low < high) {
2939
- var mid = (low + high) >>> 1;
2940
- array[mid] < value ? low = mid + 1 : high = mid;
2941
- }
2910
+ // explicitly reference `identity` for better engine inlining
2911
+ callback = callback ? createCallback(callback, thisArg) : identity;
2912
+ value = callback(value);
2913
+ while (low < high) {
2914
+ var mid = (low + high) >>> 1;
2915
+ callback(array[mid]) < value
2916
+ ? low = mid + 1
2917
+ : high = mid;
2942
2918
  }
2943
2919
  return low;
2944
2920
  }
@@ -2960,7 +2936,7 @@
2960
2936
  */
2961
2937
  function union() {
2962
2938
  var index = -1,
2963
- flattened = concat.apply(ArrayProto, arguments),
2939
+ flattened = concat.apply(arrayRef, arguments),
2964
2940
  length = flattened.length,
2965
2941
  result = [];
2966
2942
 
@@ -3170,23 +3146,17 @@
3170
3146
  * jQuery('#lodash_button').on('click', buttonView.onClick);
3171
3147
  * // => When the button is clicked, `this.label` will have the correct value
3172
3148
  */
3173
- var bindAll = createIterator({
3174
- 'useHas': false,
3175
- 'useStrict': false,
3176
- 'args': 'object',
3177
- 'top':
3178
- 'var funcs = arguments,\n' +
3179
- ' index = 0,\n' +
3180
- ' length = funcs.length;\n' +
3181
- 'if (length > 1) {\n' +
3182
- ' while (++index < length) {\n' +
3183
- ' result[funcs[index]] = bind(result[funcs[index]], result)\n' +
3184
- ' }\n' +
3185
- ' return result\n' +
3186
- '}',
3187
- 'inLoop':
3188
- 'if (isFunction(value)) result[index] = bind(value, result)'
3189
- });
3149
+ function bindAll(object) {
3150
+ var funcs = arguments,
3151
+ index = funcs.length > 1 ? 0 : (funcs = functions(object), -1),
3152
+ length = funcs.length;
3153
+
3154
+ while (++index < length) {
3155
+ var key = funcs[index];
3156
+ object[key] = bind(object[key], object);
3157
+ }
3158
+ return object;
3159
+ }
3190
3160
 
3191
3161
  /**
3192
3162
  * Creates a function that is the composition of the passed functions,
@@ -3251,7 +3221,6 @@
3251
3221
  result = func.apply(thisArg, args);
3252
3222
  }
3253
3223
  }
3254
-
3255
3224
  return function() {
3256
3225
  var isImmediate = immediate && !timeoutId;
3257
3226
  args = arguments;
@@ -3286,7 +3255,7 @@
3286
3255
  */
3287
3256
  function delay(func, wait) {
3288
3257
  var args = slice.call(arguments, 2);
3289
- return setTimeout(function() { return func.apply(undefined, args); }, wait);
3258
+ return setTimeout(function() { func.apply(undefined, args); }, wait);
3290
3259
  }
3291
3260
 
3292
3261
  /**
@@ -3306,7 +3275,7 @@
3306
3275
  */
3307
3276
  function defer(func) {
3308
3277
  var args = slice.call(arguments, 1);
3309
- return setTimeout(function() { return func.apply(undefined, args); }, 1);
3278
+ return setTimeout(function() { func.apply(undefined, args); }, 1);
3310
3279
  }
3311
3280
 
3312
3281
  /**
@@ -3367,10 +3336,10 @@
3367
3336
  function memoize(func, resolver) {
3368
3337
  var cache = {};
3369
3338
  return function() {
3370
- var prop = resolver ? resolver.apply(this, arguments) : arguments[0];
3371
- return hasOwnProperty.call(cache, prop)
3372
- ? cache[prop]
3373
- : (cache[prop] = func.apply(this, arguments));
3339
+ var key = resolver ? resolver.apply(this, arguments) : arguments[0];
3340
+ return hasOwnProperty.call(cache, key)
3341
+ ? cache[key]
3342
+ : (cache[key] = func.apply(this, arguments));
3374
3343
  };
3375
3344
  }
3376
3345
 
@@ -3459,21 +3428,20 @@
3459
3428
  timeoutId = null;
3460
3429
  result = func.apply(thisArg, args);
3461
3430
  }
3462
-
3463
3431
  return function() {
3464
3432
  var now = new Date,
3465
- remain = wait - (now - lastCalled);
3433
+ remaining = wait - (now - lastCalled);
3466
3434
 
3467
3435
  args = arguments;
3468
3436
  thisArg = this;
3469
3437
 
3470
- if (remain <= 0) {
3438
+ if (remaining <= 0) {
3471
3439
  clearTimeout(timeoutId);
3472
3440
  lastCalled = now;
3473
3441
  result = func.apply(thisArg, args);
3474
3442
  }
3475
3443
  else if (!timeoutId) {
3476
- timeoutId = setTimeout(trailingCall, remain);
3444
+ timeoutId = setTimeout(trailingCall, remaining);
3477
3445
  }
3478
3446
  return result;
3479
3447
  };
@@ -3492,19 +3460,17 @@
3492
3460
  * @returns {Function} Returns the new function.
3493
3461
  * @example
3494
3462
  *
3495
- * var hello = function(name) { return 'hello: ' + name; };
3463
+ * var hello = function(name) { return 'hello ' + name; };
3496
3464
  * hello = _.wrap(hello, function(func) {
3497
3465
  * return 'before, ' + func('moe') + ', after';
3498
3466
  * });
3499
3467
  * hello();
3500
- * // => 'before, hello: moe, after'
3468
+ * // => 'before, hello moe, after'
3501
3469
  */
3502
3470
  function wrap(value, wrapper) {
3503
3471
  return function() {
3504
3472
  var args = [value];
3505
- if (arguments.length) {
3506
- push.apply(args, arguments);
3507
- }
3473
+ push.apply(args, arguments);
3508
3474
  return wrapper.apply(this, args);
3509
3475
  };
3510
3476
  }
@@ -3577,9 +3543,8 @@
3577
3543
 
3578
3544
  lodash.prototype[methodName] = function() {
3579
3545
  var args = [this.__wrapped__];
3580
- if (arguments.length) {
3581
- push.apply(args, arguments);
3582
- }
3546
+ push.apply(args, arguments);
3547
+
3583
3548
  var result = func.apply(lodash, args);
3584
3549
  if (this.__chain__) {
3585
3550
  result = new lodash(result);
@@ -3688,14 +3653,20 @@
3688
3653
  * @param {String} text The template text.
3689
3654
  * @param {Obect} data The data object used to populate the text.
3690
3655
  * @param {Object} options The options object.
3656
+ * escape - The "escape" delimiter regexp.
3657
+ * evaluate - The "evaluate" delimiter regexp.
3658
+ * interpolate - The "interpolate" delimiter regexp.
3659
+ * sourceURL - The sourceURL of the template's compiled source.
3660
+ * variable - The data object variable name.
3661
+ *
3691
3662
  * @returns {Function|String} Returns a compiled function when no `data` object
3692
3663
  * is given, else it returns the interpolated text.
3693
3664
  * @example
3694
3665
  *
3695
3666
  * // using a compiled template
3696
- * var compiled = _.template('hello: <%= name %>');
3667
+ * var compiled = _.template('hello <%= name %>');
3697
3668
  * compiled({ 'name': 'moe' });
3698
- * // => 'hello: moe'
3669
+ * // => 'hello moe'
3699
3670
  *
3700
3671
  * var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>';
3701
3672
  * _.template(list, { 'people': ['moe', 'larry', 'curly'] });
@@ -3706,23 +3677,28 @@
3706
3677
  * // => '<b>&lt;script></b>'
3707
3678
  *
3708
3679
  * // using the internal `print` function in "evaluate" delimiters
3709
- * _.template('<% print("Hello " + epithet); %>.', { 'epithet': 'stooge' });
3710
- * // => 'Hello stooge.'
3680
+ * _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' });
3681
+ * // => 'hello stooge!'
3711
3682
  *
3712
- * // using custom template delimiter settings
3683
+ * // using custom template delimiters
3713
3684
  * _.templateSettings = {
3714
3685
  * 'interpolate': /\{\{([\s\S]+?)\}\}/g
3715
3686
  * };
3716
3687
  *
3717
- * _.template('Hello {{ name }}!', { 'name': 'Mustache' });
3718
- * // => 'Hello Mustache!'
3688
+ * _.template('hello {{ name }}!', { 'name': 'mustache' });
3689
+ * // => 'hello mustache!'
3690
+ *
3691
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
3692
+ * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
3693
+ * compiled(data);
3694
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
3719
3695
  *
3720
3696
  * // using the `variable` option to ensure a with-statement isn't used in the compiled template
3721
- * var compiled = _.template('hello: <%= data.name %>', null, { 'variable': 'data' });
3697
+ * var compiled = _.template('hello <%= data.name %>!', null, { 'variable': 'data' });
3722
3698
  * compiled.source;
3723
3699
  * // => function(data) {
3724
3700
  * var __t, __p = '', __e = _.escape;
3725
- * __p += 'hello: ' + ((__t = ( data.name )) == null ? '' : __t);
3701
+ * __p += 'hello ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
3726
3702
  * return __p;
3727
3703
  * }
3728
3704
  *
@@ -3810,7 +3786,7 @@
3810
3786
  // use a sourceURL for easier debugging
3811
3787
  // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
3812
3788
  var sourceURL = useSourceURL
3813
- ? '\n//@ sourceURL=/lodash/template/source[' + (templateCounter++) + ']'
3789
+ ? '\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']')
3814
3790
  : '';
3815
3791
 
3816
3792
  try {
@@ -3865,8 +3841,9 @@
3865
3841
  }
3866
3842
 
3867
3843
  /**
3868
- * Converts the HTML entities `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#x27;`
3869
- * in `string` to their corresponding characters.
3844
+ * The opposite of `_.escape`, this method converts the HTML entities
3845
+ * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#x27;` in `string` to their
3846
+ * corresponding characters.
3870
3847
  *
3871
3848
  * @static
3872
3849
  * @memberOf _
@@ -4001,7 +3978,7 @@
4001
3978
  * @memberOf _
4002
3979
  * @type String
4003
3980
  */
4004
- lodash.VERSION = '0.8.2';
3981
+ lodash.VERSION = '0.9.0';
4005
3982
 
4006
3983
  // assign static methods
4007
3984
  lodash.after = after;
@@ -4117,9 +4094,8 @@
4117
4094
  lodash.take = first;
4118
4095
  lodash.unique = uniq;
4119
4096
 
4120
- // add pseudo private properties used and removed during the build process
4097
+ // add pseudo private property to be used and removed during the build process
4121
4098
  lodash._iteratorTemplate = iteratorTemplate;
4122
- lodash._shimKeys = shimKeys;
4123
4099
 
4124
4100
  /*--------------------------------------------------------------------------*/
4125
4101
 
@@ -4133,7 +4109,7 @@
4133
4109
 
4134
4110
  // add all mutator Array functions to the wrapper.
4135
4111
  forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
4136
- var func = ArrayProto[methodName];
4112
+ var func = arrayRef[methodName];
4137
4113
 
4138
4114
  lodash.prototype[methodName] = function() {
4139
4115
  var value = this.__wrapped__;
@@ -4154,7 +4130,7 @@
4154
4130
 
4155
4131
  // add all accessor Array functions to the wrapper.
4156
4132
  forEach(['concat', 'join', 'slice'], function(methodName) {
4157
- var func = ArrayProto[methodName];
4133
+ var func = arrayRef[methodName];
4158
4134
 
4159
4135
  lodash.prototype[methodName] = function() {
4160
4136
  var value = this.__wrapped__,