lodash-rails 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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__,