torba 0.5.1 → 0.6.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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/CHANGELOG.md +10 -0
- data/README.md +1 -1
- data/lib/torba.rb +9 -1
- data/lib/torba/css_url_to_erb_asset_path.rb +5 -1
- data/lib/torba/manifest.rb +1 -1
- data/lib/torba/package.rb +12 -8
- data/test/acceptance_test.rb +50 -64
- data/test/css_url_to_erb_asset_path_test.rb +5 -0
- data/test/fixtures/home_path/01/trumbowyg/icons-2x.png +0 -0
- data/test/fixtures/home_path/01/trumbowyg/icons.png +0 -0
- data/test/fixtures/home_path/01/trumbowyg/trumbowyg.css.erb +471 -0
- data/test/fixtures/home_path/01/trumbowyg/trumbowyg.js +1124 -0
- data/test/fixtures/home_path/02/lo_dash/lodash.js +2793 -0
- data/test/fixtures/home_path/04/bourbon/_border-image.scss +59 -0
- data/test/fixtures/home_path/04/bourbon/_font-source-declaration.scss +43 -0
- data/test/fixtures/home_path/04/bourbon/_retina-image.scss +25 -0
- data/test/fixtures/torbafiles/01_gh_release.rb +8 -0
- data/test/fixtures/torbafiles/01_targz.rb +7 -0
- data/test/fixtures/torbafiles/01_zip.rb +7 -0
- data/test/fixtures/torbafiles/02_npm.rb +1 -0
- data/test/fixtures/torbafiles/03_image_asset_not_specified.rb +7 -0
- data/test/fixtures/torbafiles/04_not_existed_assets.rb +5 -0
- data/test/package_test.rb +10 -0
- data/test/test_helper.rb +68 -7
- data/test/torba_test.rb +13 -0
- data/torba.gemspec +1 -1
- metadata +32 -2
@@ -0,0 +1,2793 @@
|
|
1
|
+
/*!
|
2
|
+
* Lo-Dash v0.1.0 <https://github.com/bestiejs/lodash>
|
3
|
+
* Copyright 2012 John-David Dalton <http://allyoucanleet.com/>
|
4
|
+
* Based on Underscore.js 1.3.3, copyright 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
5
|
+
* <http://documentcloud.github.com/underscore>
|
6
|
+
* Available under MIT license <http://mths.be/mit>
|
7
|
+
*/
|
8
|
+
;(function(window, undefined) {
|
9
|
+
'use strict';
|
10
|
+
|
11
|
+
/** Used to escape and unescape characters in templates */
|
12
|
+
var escapes = {
|
13
|
+
'\\': '\\',
|
14
|
+
"'": "'",
|
15
|
+
'r': '\r',
|
16
|
+
'n': '\n',
|
17
|
+
't': '\t',
|
18
|
+
'u2028': '\u2028',
|
19
|
+
'u2029': '\u2029'
|
20
|
+
};
|
21
|
+
|
22
|
+
// assign the result as keys and the keys as values
|
23
|
+
(function() {
|
24
|
+
for (var prop in escapes) {
|
25
|
+
escapes[escapes[prop]] = prop;
|
26
|
+
}
|
27
|
+
}());
|
28
|
+
|
29
|
+
/** Detect free variable `exports` */
|
30
|
+
var freeExports = typeof exports == 'object' && exports &&
|
31
|
+
(typeof global == 'object' && global && global == global.global && (window = global), exports);
|
32
|
+
|
33
|
+
/** Used to generate unique IDs */
|
34
|
+
var idCounter = 0;
|
35
|
+
|
36
|
+
/** Used to restore the original `_` reference in `noConflict` */
|
37
|
+
var oldDash = window._;
|
38
|
+
|
39
|
+
/** Used to replace unescape characters with their escaped counterpart */
|
40
|
+
var reEscaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Used for `templateSettings` properties such as `escape`, `evaluate`,
|
44
|
+
* or `interpolate` with explicitly assigned falsey values to ensure no match
|
45
|
+
* is made.
|
46
|
+
*/
|
47
|
+
var reNoMatch = /.^/;
|
48
|
+
|
49
|
+
/** Used to replace escaped characters with their unescaped counterpart */
|
50
|
+
var reUnescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
|
51
|
+
|
52
|
+
/** Object#toString result shortcuts */
|
53
|
+
var arrayClass = '[object Array]',
|
54
|
+
boolClass = '[object Boolean]',
|
55
|
+
dateClass = '[object Date]',
|
56
|
+
funcClass = '[object Function]',
|
57
|
+
numberClass = '[object Number]',
|
58
|
+
regexpClass = '[object RegExp]',
|
59
|
+
stringClass = '[object String]';
|
60
|
+
|
61
|
+
/** Native prototype shortcuts */
|
62
|
+
var ArrayProto = Array.prototype,
|
63
|
+
ObjProto = Object.prototype;
|
64
|
+
|
65
|
+
/** Native method shortcuts */
|
66
|
+
var concat = ArrayProto.concat,
|
67
|
+
hasOwnProperty = ObjProto.hasOwnProperty,
|
68
|
+
push = ArrayProto.push,
|
69
|
+
slice = ArrayProto.slice,
|
70
|
+
toString = ObjProto.toString,
|
71
|
+
unshift = ArrayProto.unshift;
|
72
|
+
|
73
|
+
/* Native method shortcuts for methods with the same name as other `lodash` methods */
|
74
|
+
var nativeIsArray = Array.isArray,
|
75
|
+
nativeIsFinite = window.isFinite,
|
76
|
+
nativeKeys = Object.keys;
|
77
|
+
|
78
|
+
/** Timer shortcuts */
|
79
|
+
var clearInteval = window.clearInterval,
|
80
|
+
setTimeout = window.setTimeout;
|
81
|
+
|
82
|
+
/** Compilation options for `_.difference` */
|
83
|
+
var differenceFactoryOptions = {
|
84
|
+
'args': 'array',
|
85
|
+
'top': 'var values=concat.apply([],slice.call(arguments,1))',
|
86
|
+
'init': '[]',
|
87
|
+
'inLoop': 'if(indexOf(values,array[index])<0)result.push(array[index])'
|
88
|
+
};
|
89
|
+
|
90
|
+
/** Compilation options for `_.every` */
|
91
|
+
var everyFactoryOptions = {
|
92
|
+
'init': 'true',
|
93
|
+
'inLoop': 'if(!callback(collection[index],index,collection))return !result'
|
94
|
+
};
|
95
|
+
|
96
|
+
/** Compilation options for `_.extend` */
|
97
|
+
var extendFactoryOptions = {
|
98
|
+
'args': 'object',
|
99
|
+
'init': 'object',
|
100
|
+
'beforeLoop': 'for(var source,j=1,length=arguments.length;j<length;j++){\nsource=arguments[j]',
|
101
|
+
'loopExp': 'index in source',
|
102
|
+
'inLoop': 'object[index]=source[index]',
|
103
|
+
'useHas': false,
|
104
|
+
'afterLoop': '}'
|
105
|
+
};
|
106
|
+
|
107
|
+
/** Compilation options for `_.filter` */
|
108
|
+
var filterFactoryOptions = {
|
109
|
+
'init': '[]',
|
110
|
+
'inLoop': 'callback(collection[index],index,collection)&&result.push(collection[index])'
|
111
|
+
};
|
112
|
+
|
113
|
+
/** Compilation options for `_.forEach` */
|
114
|
+
var forEachFactoryOptions = {
|
115
|
+
'args': 'collection,callback,thisArg',
|
116
|
+
'top':
|
117
|
+
'if(!callback){\ncallback=identity\n}\n' +
|
118
|
+
'else if(thisArg){\ncallback=bind(callback,thisArg)\n}',
|
119
|
+
'init': 'collection',
|
120
|
+
'inLoop': 'callback(collection[index],index,collection)'
|
121
|
+
};
|
122
|
+
|
123
|
+
/** Compilation options for `_.keys` */
|
124
|
+
var keysFactoryOptions = {
|
125
|
+
'args': 'object',
|
126
|
+
'top': 'if(object!==Object(object))throw TypeError()',
|
127
|
+
'init': '[]',
|
128
|
+
'inLoop': 'result.push(index)'
|
129
|
+
};
|
130
|
+
|
131
|
+
/** Compilation options for `_.map` */
|
132
|
+
var mapFactoryOptions = {
|
133
|
+
'init': '',
|
134
|
+
'exits': '[]',
|
135
|
+
'beforeLoop': {
|
136
|
+
'array': 'result=Array(length)',
|
137
|
+
'object': 'result=[]'
|
138
|
+
},
|
139
|
+
'inLoop': {
|
140
|
+
'array': 'result[index]=callback(collection[index],index,collection)',
|
141
|
+
'object': 'result[result.length]=callback(collection[index],index,collection)'
|
142
|
+
}
|
143
|
+
};
|
144
|
+
|
145
|
+
/** Compilation options for `_.max` */
|
146
|
+
var maxFactoryOptions = {
|
147
|
+
'top':
|
148
|
+
'var current,result=-Infinity,computed=result;\n' +
|
149
|
+
'if(!callback){\n' +
|
150
|
+
'if(isArray(collection)&&collection[0]===+collection[0])return Math.max.apply(Math,collection);\n' +
|
151
|
+
'if(isEmpty(collection))return result;\n' +
|
152
|
+
'}else if(thisArg)callback=bind(callback,thisArg)',
|
153
|
+
'inLoop':
|
154
|
+
'current=callback?callback(collection[index],index,collection):collection[index];\n' +
|
155
|
+
'if(current>=computed)computed=current,result=collection[index]'
|
156
|
+
};
|
157
|
+
|
158
|
+
/*--------------------------------------------------------------------------*/
|
159
|
+
|
160
|
+
/**
|
161
|
+
* The `lodash` function.
|
162
|
+
*
|
163
|
+
* @name _
|
164
|
+
* @param {Mixed} value The value to wrap in a `Lodash` instance.
|
165
|
+
* @returns {Object} Returns a `Lodash` instance.
|
166
|
+
*/
|
167
|
+
function lodash(value) {
|
168
|
+
// allow invoking `lodash` without the `new` operator
|
169
|
+
return new Lodash(value);
|
170
|
+
}
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Creates a `Lodash` instance that wraps a value to allow chaining.
|
174
|
+
*
|
175
|
+
* @private
|
176
|
+
* @constructor
|
177
|
+
* @param {Mixed} value The value to wrap.
|
178
|
+
*/
|
179
|
+
function Lodash(value) {
|
180
|
+
this._wrapped = value;
|
181
|
+
}
|
182
|
+
|
183
|
+
/*--------------------------------------------------------------------------*/
|
184
|
+
|
185
|
+
/**
|
186
|
+
* Checks if a `value` is an array.
|
187
|
+
*
|
188
|
+
* @static
|
189
|
+
* @memberOf _
|
190
|
+
* @category Objects
|
191
|
+
* @param {Mixed} value The value to check.
|
192
|
+
* @returns {Boolean} Returns `true` if the `value` is an array, else `false`.
|
193
|
+
* @example
|
194
|
+
*
|
195
|
+
* (function() { return _.isArray(arguments); })();
|
196
|
+
* // => false
|
197
|
+
*
|
198
|
+
* _.isArray([1, 2, 3]);
|
199
|
+
* // => true
|
200
|
+
*/
|
201
|
+
var isArray = nativeIsArray || function isArray(value) {
|
202
|
+
return toString.call(value) == arrayClass;
|
203
|
+
};
|
204
|
+
|
205
|
+
/**
|
206
|
+
* Checks if a `value` is empty. Arrays or strings with a length of 0 and
|
207
|
+
* objects with no enumerable own properties are considered "empty".
|
208
|
+
*
|
209
|
+
* @static
|
210
|
+
* @memberOf _
|
211
|
+
* @category Objects
|
212
|
+
* @param {Mixed} value The value to check.
|
213
|
+
* @returns {Boolean} Returns `true` if the `value` is empty, else `false`.
|
214
|
+
* @example
|
215
|
+
*
|
216
|
+
* _.isEmpty([1, 2, 3]);
|
217
|
+
* // => false
|
218
|
+
*
|
219
|
+
* _.isEmpty({});
|
220
|
+
* // => true
|
221
|
+
*/
|
222
|
+
var isEmpty = iterationFactory({
|
223
|
+
'args': 'value',
|
224
|
+
'iterate': 'objects',
|
225
|
+
'top': 'var className=toString.call(value)',
|
226
|
+
'init': 'true',
|
227
|
+
'beforeLoop': 'if(className==arrayClass||className==stringClass)return !value.length',
|
228
|
+
'inLoop': 'return false'
|
229
|
+
});
|
230
|
+
|
231
|
+
/*--------------------------------------------------------------------------*/
|
232
|
+
|
233
|
+
/**
|
234
|
+
* Compiles iteration functions.
|
235
|
+
*
|
236
|
+
* @private
|
237
|
+
* @param {Object} [options1, options2, ..] The compile options objects.
|
238
|
+
* @returns {Function} Returns the compiled function.
|
239
|
+
*/
|
240
|
+
function iterationFactory() {
|
241
|
+
var prop,
|
242
|
+
index = -1,
|
243
|
+
array = {},
|
244
|
+
object = {},
|
245
|
+
options = {},
|
246
|
+
props = ['beforeLoop', 'loopExp', 'inLoop', 'afterLoop'];
|
247
|
+
|
248
|
+
while (++index < arguments.length) {
|
249
|
+
for (prop in arguments[index]) {
|
250
|
+
options[prop] = arguments[index][prop];
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
while ((prop = props.pop())) {
|
255
|
+
if (typeof options[prop] == 'object') {
|
256
|
+
array[prop] = options[prop].array;
|
257
|
+
object[prop] = options[prop].object;
|
258
|
+
} else {
|
259
|
+
array[prop] = object[prop] = options[prop] || '';
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|
263
|
+
var args = options.args,
|
264
|
+
firstArg = /^[^,]+/.exec(args)[0],
|
265
|
+
init = options.init,
|
266
|
+
iterate = options.iterate,
|
267
|
+
arrayBranch = !(args == 'object' || iterate == 'objects'),
|
268
|
+
objectBranch = !(args == 'array' || iterate == 'arrays'),
|
269
|
+
useHas = options.useHas !== false;
|
270
|
+
|
271
|
+
return Function('arrayClass,bind,concat,funcClass,hasOwnProperty,identity,' +
|
272
|
+
'indexOf,Infinity,isArray,isEmpty,Math,slice,stringClass,' +
|
273
|
+
'toString,undefined',
|
274
|
+
'"use strict";' +
|
275
|
+
'return function(' + args + '){\n' +
|
276
|
+
(options.top || '') + ';\n' +
|
277
|
+
('var index, result' + (init ? '=' + init : '')) + ';\n' +
|
278
|
+
'if(' + firstArg + '==undefined)return ' + (options.exits || 'result') + ';\n' +
|
279
|
+
(arrayBranch
|
280
|
+
? 'var length=' + firstArg + '.length;\nindex=-1;\n' +
|
281
|
+
((objectBranch ? 'if(length===+length){\n' : '') +
|
282
|
+
(array.beforeLoop || '') + ';\n' +
|
283
|
+
'while(' + (array.loopExp || '++index<length') + '){\n' + array.inLoop + '\n}' +
|
284
|
+
(array.afterLoop || '') + ';\n' +
|
285
|
+
(objectBranch ? '\n}\n' : ''))
|
286
|
+
: ''
|
287
|
+
) +
|
288
|
+
(objectBranch
|
289
|
+
? ((arrayBranch ? 'else{\n' : '') +
|
290
|
+
(object.beforeLoop || '') + ';\n' +
|
291
|
+
'for(' + (object.loopExp || 'index in ' + firstArg) + '){\n' +
|
292
|
+
(useHas ? 'if(hasOwnProperty.call(' + /\S+$/.exec(object.loopExp || firstArg)[0] + ',index)){\n' : '') +
|
293
|
+
object.inLoop +
|
294
|
+
(useHas ? '\n}' : '') +
|
295
|
+
'\n}' +
|
296
|
+
(object.afterLoop || '') + ';\n' +
|
297
|
+
(arrayBranch ? '\n}\n' : ''))
|
298
|
+
: ''
|
299
|
+
) +
|
300
|
+
(options.bottom || '') + ';\n' +
|
301
|
+
'return ' + (options.returns || 'result') +
|
302
|
+
'\n}'
|
303
|
+
)(arrayClass, bind, concat, funcClass, hasOwnProperty, identity,
|
304
|
+
indexOf, Infinity, isArray, isEmpty, Math, slice, stringClass, toString);
|
305
|
+
}
|
306
|
+
|
307
|
+
/**
|
308
|
+
* Unescapes characters, previously escaped for inclusion in compiled string
|
309
|
+
* literals, so they may compiled into function bodies.
|
310
|
+
* (Used for template interpolation, evaluation, or escaping)
|
311
|
+
*
|
312
|
+
* @private
|
313
|
+
* @param {String} string The string to unescape.
|
314
|
+
* @returns {String} Returns the unescaped string.
|
315
|
+
*/
|
316
|
+
function unescape(string) {
|
317
|
+
return string.replace(reUnescaper, function(match, escaped) {
|
318
|
+
return escapes[escaped];
|
319
|
+
});
|
320
|
+
}
|
321
|
+
|
322
|
+
/*--------------------------------------------------------------------------*/
|
323
|
+
|
324
|
+
/**
|
325
|
+
* Checks if a given `target` value is present in a `collection` using strict
|
326
|
+
* equality for comparisons, i.e. `===`.
|
327
|
+
*
|
328
|
+
* @static
|
329
|
+
* @memberOf _
|
330
|
+
* @alias include
|
331
|
+
* @category Collections
|
332
|
+
* @param {Array|Object} collection The collection to iterate over.
|
333
|
+
* @param {Mixed} target The value to check for.
|
334
|
+
* @returns {Boolean} Returns `true` if `target` value is found, else `false`.
|
335
|
+
* @example
|
336
|
+
*
|
337
|
+
* _.contains([1, 2, 3], 3);
|
338
|
+
* // => true
|
339
|
+
*/
|
340
|
+
var contains = iterationFactory({
|
341
|
+
'args': 'collection,target',
|
342
|
+
'init': 'false',
|
343
|
+
'inLoop': 'if(collection[index]===target)return true'
|
344
|
+
});
|
345
|
+
|
346
|
+
/**
|
347
|
+
* Checks if the `callback` returns truthy for **all** values of a `collection`.
|
348
|
+
* The `callback` is invoked with 3 arguments; for arrays they are
|
349
|
+
* (value, index, array) and for objects they are (value, key, object).
|
350
|
+
*
|
351
|
+
* @static
|
352
|
+
* @memberOf _
|
353
|
+
* @alias all
|
354
|
+
* @category Collections
|
355
|
+
* @param {Array|Object} collection The collection to iterate over.
|
356
|
+
* @param {Function} callback The function called per iteration.
|
357
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
358
|
+
* @returns {Boolean} Returns `true` if all values pass the callback check, else `false`.
|
359
|
+
* @example
|
360
|
+
*
|
361
|
+
* _.every([true, 1, null, 'yes'], Boolean);
|
362
|
+
* => false
|
363
|
+
*/
|
364
|
+
var every = iterationFactory(forEachFactoryOptions, everyFactoryOptions);
|
365
|
+
|
366
|
+
/**
|
367
|
+
* Examines each value in a `collection`, returning an array of all values the
|
368
|
+
* `callback` returns truthy for. The `callback` is invoked with 3 arguments;
|
369
|
+
* for arrays they are (value, index, array) and for objects they are
|
370
|
+
* (value, key, object).
|
371
|
+
*
|
372
|
+
* @static
|
373
|
+
* @memberOf _
|
374
|
+
* @alias select
|
375
|
+
* @category Collections
|
376
|
+
* @param {Array|Object} collection The collection to iterate over.
|
377
|
+
* @param {Function} callback The function called per iteration.
|
378
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
379
|
+
* @returns {Array} Returns a new array of values that passed callback check.
|
380
|
+
* @example
|
381
|
+
*
|
382
|
+
* var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
383
|
+
* // => [2, 4, 6]
|
384
|
+
*/
|
385
|
+
var filter = iterationFactory(forEachFactoryOptions, filterFactoryOptions);
|
386
|
+
|
387
|
+
/**
|
388
|
+
* Examines each value in a `collection`, returning the first one the `callback`
|
389
|
+
* returns truthy for. The function returns as soon as it finds an acceptable
|
390
|
+
* value, and does not iterate over the entire `collection`. The `callback` is
|
391
|
+
* invoked with 3 arguments; for arrays they are (value, index, array) and for
|
392
|
+
* objects they are (value, key, object).
|
393
|
+
*
|
394
|
+
* @static
|
395
|
+
* @memberOf _
|
396
|
+
* @alias detect
|
397
|
+
* @category Collections
|
398
|
+
* @param {Array|Object} collection The collection to iterate over.
|
399
|
+
* @param {Function} callback The function called per iteration.
|
400
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
401
|
+
* @returns {Mixed} Returns the value that passed the callback check, else `undefined`.
|
402
|
+
* @example
|
403
|
+
*
|
404
|
+
* var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
405
|
+
* // => 2
|
406
|
+
*/
|
407
|
+
var find = iterationFactory(forEachFactoryOptions, {
|
408
|
+
'inLoop': 'if(callback(collection[index],index,collection))return collection[index]'
|
409
|
+
});
|
410
|
+
|
411
|
+
/**
|
412
|
+
* Iterates over a `collection`, executing the `callback` for each value in the
|
413
|
+
* `collection`. The `callback` is bound to the `thisArg` value, if one is passed.
|
414
|
+
* The `callback` is invoked with 3 arguments; for arrays they are
|
415
|
+
* (value, index, array) and for objects they are (value, key, object).
|
416
|
+
*
|
417
|
+
* @static
|
418
|
+
* @memberOf _
|
419
|
+
* @alias each
|
420
|
+
* @category Collections
|
421
|
+
* @param {Array|Object} collection The collection to iterate over.
|
422
|
+
* @param {Function} callback The function called per iteration.
|
423
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
424
|
+
* @returns {Array|Object} Returns the `collection`.
|
425
|
+
* @example
|
426
|
+
*
|
427
|
+
* _.forEach([1, 2, 3], function(num) { alert(num); });
|
428
|
+
* // => alerts each number in turn...
|
429
|
+
*
|
430
|
+
* _.forEach({ 'one': 1, 'two': 2, 'three': 3}, function(num) { alert(num); });
|
431
|
+
* // => alerts each number in turn...
|
432
|
+
*/
|
433
|
+
var forEach = iterationFactory(forEachFactoryOptions);
|
434
|
+
|
435
|
+
/**
|
436
|
+
* Splits a `collection` into sets, grouped by the result of running each value
|
437
|
+
* through `callback`. The `callback` is invoked with 3 arguments; for arrays
|
438
|
+
* they are (value, index, array) and for objects they are (value, key, object).
|
439
|
+
* The `callback` argument may also be the name of a property to group by.
|
440
|
+
*
|
441
|
+
* @static
|
442
|
+
* @memberOf _
|
443
|
+
* @category Collections
|
444
|
+
* @param {Array|Object} collection The collection to iterate over.
|
445
|
+
* @param {Function|String} callback The function called per iteration or
|
446
|
+
* property name to group by.
|
447
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
448
|
+
* @returns {Object} Returns an object of grouped values.
|
449
|
+
* @example
|
450
|
+
*
|
451
|
+
* _.groupBy([1.3, 2.1, 2.4], function(num) { return Math.floor(num); });
|
452
|
+
* // => { '1': [1.3], '2': [2.1, 2.4] }
|
453
|
+
*
|
454
|
+
* _.groupBy(['one', 'two', 'three'], 'length');
|
455
|
+
* // => { '3': ['one', 'two'], '5': ['three'] }
|
456
|
+
*/
|
457
|
+
function groupBy(collection, callback, thisArg) {
|
458
|
+
var result = {};
|
459
|
+
if (!isFunction(callback)) {
|
460
|
+
var prop = callback;
|
461
|
+
callback = function(collection) { return collection[prop]; };
|
462
|
+
}
|
463
|
+
forEach(collection, function(value, index, collection) {
|
464
|
+
var prop = callback(value, index, collection);
|
465
|
+
(result[prop] || (result[prop] = [])).push(value);
|
466
|
+
});
|
467
|
+
return result;
|
468
|
+
}
|
469
|
+
|
470
|
+
/**
|
471
|
+
* Calls the method named by `methodName` for each value of the `collection`.
|
472
|
+
* Additional arguments will be passed to each invoked method.
|
473
|
+
*
|
474
|
+
* @static
|
475
|
+
* @memberOf _
|
476
|
+
* @category Collections
|
477
|
+
* @param {Array|Object} collection The collection to iterate over.
|
478
|
+
* @param {String} methodName The name of the method to invoke.
|
479
|
+
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
|
480
|
+
* @returns {Array} Returns a new array of values returned from each invoked method.
|
481
|
+
* @example
|
482
|
+
*
|
483
|
+
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
|
484
|
+
* // => [[1, 5, 7], [1, 2, 3]]
|
485
|
+
*/
|
486
|
+
function invoke(collection, methodName) {
|
487
|
+
var args = slice.call(arguments, 2),
|
488
|
+
isFunc = isFunction(methodName);
|
489
|
+
|
490
|
+
return map(collection, function(value) {
|
491
|
+
return (isFunc ? methodName || value : value[methodName]).apply(value, args);
|
492
|
+
});
|
493
|
+
}
|
494
|
+
|
495
|
+
/**
|
496
|
+
* Produces a new array of values by mapping each value in the `collection`
|
497
|
+
* through a transformation `callback`. The `callback` is bound to the `thisArg`
|
498
|
+
* value, if one is passed. The `callback` is invoked with 3 arguments; for
|
499
|
+
* arrays they are (value, index, array) and for objects they are (value, key, object).
|
500
|
+
*
|
501
|
+
* @static
|
502
|
+
* @memberOf _
|
503
|
+
* @alias collect
|
504
|
+
* @category Collections
|
505
|
+
* @param {Array|Object} collection The collection to iterate over.
|
506
|
+
* @param {Function} callback The function called per iteration.
|
507
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
508
|
+
* @returns {Array} Returns a new array of values returned by the callback.
|
509
|
+
* @example
|
510
|
+
*
|
511
|
+
* _.map([1, 2, 3], function(num) { return num * 3; });
|
512
|
+
* // => [3, 6, 9]
|
513
|
+
*
|
514
|
+
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
|
515
|
+
* // => [3, 6, 9]
|
516
|
+
*/
|
517
|
+
var map = iterationFactory(forEachFactoryOptions, mapFactoryOptions);
|
518
|
+
|
519
|
+
/**
|
520
|
+
* Retrieves the maximum value of a `collection`. If `callback` is passed,
|
521
|
+
* it will be executed for each value in the `collection` to generate the
|
522
|
+
* criterion by which the value is ranked. The `callback` is invoked with 3
|
523
|
+
* arguments; for arrays they are (value, index, array) and for objects they
|
524
|
+
* are (value, key, object).
|
525
|
+
*
|
526
|
+
* @static
|
527
|
+
* @memberOf _
|
528
|
+
* @category Collections
|
529
|
+
* @param {Array|Object} collection The collection to iterate over.
|
530
|
+
* @param {Function} [callback] The function called per iteration.
|
531
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
532
|
+
* @returns {Mixed} Returns the maximum value.
|
533
|
+
* @example
|
534
|
+
*
|
535
|
+
* var stooges = [
|
536
|
+
* { 'name': 'moe', 'age': 40 },
|
537
|
+
* { 'name': 'larry', 'age': 50 },
|
538
|
+
* { 'name': 'curly', 'age': 60 }
|
539
|
+
* ];
|
540
|
+
*
|
541
|
+
* _.max(stooges, function(stooge) { return stooge.age; });
|
542
|
+
* // => { 'name': 'curly', 'age': 60 };
|
543
|
+
*/
|
544
|
+
var max = iterationFactory(forEachFactoryOptions, maxFactoryOptions);
|
545
|
+
|
546
|
+
/**
|
547
|
+
* Retrieves the minimum value of a `collection`. If `callback` is passed,
|
548
|
+
* it will be executed for each value in the `collection` to generate the
|
549
|
+
* criterion by which the value is ranked. The `callback` is invoked with 3
|
550
|
+
* arguments; for arrays they are (value, index, array) and for objects they
|
551
|
+
* are (value, key, object).
|
552
|
+
*
|
553
|
+
* @static
|
554
|
+
* @memberOf _
|
555
|
+
* @category Collections
|
556
|
+
* @param {Array|Object} collection The collection to iterate over.
|
557
|
+
* @param {Function} [callback] The function called per iteration.
|
558
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
559
|
+
* @returns {Mixed} Returns the minimum value.
|
560
|
+
* @example
|
561
|
+
*
|
562
|
+
* _.min([10, 5, 100, 2, 1000]);
|
563
|
+
* // => 2
|
564
|
+
*/
|
565
|
+
var min = iterationFactory(forEachFactoryOptions, maxFactoryOptions, {
|
566
|
+
'top': maxFactoryOptions.top.replace('-', '').replace('max', 'min'),
|
567
|
+
'inLoop': maxFactoryOptions.inLoop.replace('>=', '<')
|
568
|
+
});
|
569
|
+
|
570
|
+
/**
|
571
|
+
* Retrieves the value of a specified property from all values in a `collection`.
|
572
|
+
*
|
573
|
+
* @static
|
574
|
+
* @memberOf _
|
575
|
+
* @category Collections
|
576
|
+
* @param {Array|Object} collection The collection to iterate over.
|
577
|
+
* @param {String} property The property to pluck.
|
578
|
+
* @returns {Array} Returns a new array of property values.
|
579
|
+
* @example
|
580
|
+
*
|
581
|
+
* var stooges = [
|
582
|
+
* { 'name': 'moe', 'age': 40 },
|
583
|
+
* { 'name': 'larry', 'age': 50 },
|
584
|
+
* { 'name': 'curly', 'age': 60 }
|
585
|
+
* ];
|
586
|
+
*
|
587
|
+
* _.pluck(stooges, 'name');
|
588
|
+
* // => ['moe', 'larry', 'curly']
|
589
|
+
*/
|
590
|
+
var pluck = iterationFactory(mapFactoryOptions, {
|
591
|
+
'args': 'collection,property',
|
592
|
+
'inLoop': {
|
593
|
+
'array': 'result[index]=collection[index][property]',
|
594
|
+
'object': 'result[result.length]=collection[index][property]'
|
595
|
+
}
|
596
|
+
});
|
597
|
+
|
598
|
+
/**
|
599
|
+
* Boils down a `collection` to a single value. The initial state of the
|
600
|
+
* reduction is `accumulator` and each successive step of it should be returned
|
601
|
+
* by the `callback`. The `callback` is bound to the `thisArg` value, if one is
|
602
|
+
* passed. The `callback` is invoked with 4 arguments; for arrays they are
|
603
|
+
* (accumulator, value, index, array) and for objects they are
|
604
|
+
* (accumulator, value, key, object).
|
605
|
+
*
|
606
|
+
* @static
|
607
|
+
* @memberOf _
|
608
|
+
* @alias foldl, inject
|
609
|
+
* @category Collections
|
610
|
+
* @param {Array|Object} collection The collection to iterate over.
|
611
|
+
* @param {Function} callback The function called per iteration.
|
612
|
+
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
613
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
614
|
+
* @returns {Mixed} Returns the accumulated value.
|
615
|
+
* @example
|
616
|
+
*
|
617
|
+
* var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; });
|
618
|
+
* // => 6
|
619
|
+
*/
|
620
|
+
var reduce = iterationFactory({
|
621
|
+
'args':
|
622
|
+
'collection,callback,accumulator,thisArg',
|
623
|
+
'top':
|
624
|
+
'var initial=arguments.length>2;\n' +
|
625
|
+
'if(thisArg)callback=bind(callback,thisArg)',
|
626
|
+
'init':
|
627
|
+
'accumulator',
|
628
|
+
'beforeLoop': {
|
629
|
+
'array': 'if(!initial)result=collection[++index]'
|
630
|
+
},
|
631
|
+
'inLoop': {
|
632
|
+
'array':
|
633
|
+
'result=callback(result,collection[index],index,collection)',
|
634
|
+
'object':
|
635
|
+
'result=initial\n' +
|
636
|
+
'?callback(result,collection[index],index,collection)\n' +
|
637
|
+
':(initial=true,collection[index])'
|
638
|
+
}
|
639
|
+
});
|
640
|
+
|
641
|
+
/**
|
642
|
+
* The right-associative version of `_.reduce`. The `callback` is bound to the
|
643
|
+
* `thisArg` value, if one is passed. The `callback` is invoked with 4 arguments;
|
644
|
+
* for arrays they are (accumulator, value, index, array) and for objects they
|
645
|
+
* are (accumulator, value, key, object).
|
646
|
+
*
|
647
|
+
* @static
|
648
|
+
* @memberOf _
|
649
|
+
* @alias foldr
|
650
|
+
* @category Collections
|
651
|
+
* @param {Array|Object} collection The collection to iterate over.
|
652
|
+
* @param {Function} callback The function called per iteration.
|
653
|
+
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
654
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
655
|
+
* @returns {Mixed} Returns the accumulated value.
|
656
|
+
* @example
|
657
|
+
*
|
658
|
+
* var list = [[0, 1], [2, 3], [4, 5]];
|
659
|
+
* var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
|
660
|
+
* // => [4, 5, 2, 3, 0, 1]
|
661
|
+
*/
|
662
|
+
function reduceRight(collection, callback, result, thisArg) {
|
663
|
+
var initial = arguments.length > 2;
|
664
|
+
if (collection == undefined) {
|
665
|
+
return result;
|
666
|
+
}
|
667
|
+
if(thisArg) {
|
668
|
+
callback = bind(callback, thisArg);
|
669
|
+
}
|
670
|
+
var length = collection.length;
|
671
|
+
if (length === +length) {
|
672
|
+
if (length && !initial) {
|
673
|
+
result = collection[--length];
|
674
|
+
}
|
675
|
+
while (length--) {
|
676
|
+
result = callback(result, collection[length], length, collection);
|
677
|
+
}
|
678
|
+
return result;
|
679
|
+
}
|
680
|
+
|
681
|
+
var prop,
|
682
|
+
props = keys(collection);
|
683
|
+
|
684
|
+
length = props.length;
|
685
|
+
if (length && !initial) {
|
686
|
+
result = collection[props[--length]];
|
687
|
+
}
|
688
|
+
while (length--) {
|
689
|
+
prop = props[length];
|
690
|
+
result = callback(result, collection[prop], prop, collection);
|
691
|
+
}
|
692
|
+
return result;
|
693
|
+
}
|
694
|
+
|
695
|
+
/**
|
696
|
+
* The opposite of `_.filter`, this method returns the values of a `collection`
|
697
|
+
* that `callback` does **not** return truthy for. The `callback` is invoked
|
698
|
+
* with 3 arguments; for arrays they are (value, index, array) and for objects
|
699
|
+
* they are (value, key, object).
|
700
|
+
*
|
701
|
+
* @static
|
702
|
+
* @memberOf _
|
703
|
+
* @category Collections
|
704
|
+
* @param {Array|Object} collection The collection to iterate over.
|
705
|
+
* @param {Function} callback The function called per iteration.
|
706
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
707
|
+
* @returns {Array} Returns a new array of values that did **not** pass the callback check.
|
708
|
+
* @example
|
709
|
+
*
|
710
|
+
* var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
711
|
+
* // => [1, 3, 5]
|
712
|
+
*/
|
713
|
+
var reject = iterationFactory(forEachFactoryOptions, filterFactoryOptions, {
|
714
|
+
'inLoop': '!' + filterFactoryOptions.inLoop
|
715
|
+
});
|
716
|
+
|
717
|
+
/**
|
718
|
+
* Produces a new array of shuffled `collection` values, using a version of the
|
719
|
+
* Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
|
720
|
+
*
|
721
|
+
* @static
|
722
|
+
* @memberOf _
|
723
|
+
* @category Collections
|
724
|
+
* @param {Array|Object} collection The collection to shuffle.
|
725
|
+
* @returns {Array} Returns a new shuffled array.
|
726
|
+
* @example
|
727
|
+
*
|
728
|
+
* _.shuffle([1, 2, 3, 4, 5, 6]);
|
729
|
+
* // => [4, 1, 6, 3, 5, 2]
|
730
|
+
*/
|
731
|
+
function shuffle(collection) {
|
732
|
+
var rand,
|
733
|
+
result = [];
|
734
|
+
|
735
|
+
forEach(collection, function(value, index) {
|
736
|
+
rand = Math.floor(Math.random() * (index + 1));
|
737
|
+
result[index] = result[rand];
|
738
|
+
result[rand] = value;
|
739
|
+
});
|
740
|
+
return result;
|
741
|
+
}
|
742
|
+
|
743
|
+
/**
|
744
|
+
* Gets the number of values in the `collection`.
|
745
|
+
*
|
746
|
+
* @static
|
747
|
+
* @memberOf _
|
748
|
+
* @category Collections
|
749
|
+
* @param {Array|Object} collection The collection inspect.
|
750
|
+
* @returns {Number} Returns the number of values in the collection.
|
751
|
+
* @example
|
752
|
+
*
|
753
|
+
* _.size({ 'one': 1, 'two': 2, 'three': 3 });
|
754
|
+
* // => 3
|
755
|
+
*/
|
756
|
+
function size(collection) {
|
757
|
+
var className = toString.call(collection);
|
758
|
+
return className == arrayClass || className == stringClass
|
759
|
+
? collection.length
|
760
|
+
: keys(collection).length;
|
761
|
+
}
|
762
|
+
|
763
|
+
/**
|
764
|
+
* Produces a new sorted array, ranked in ascending order by the results of
|
765
|
+
* running each value of a `collection` through `callback`. The `callback` is
|
766
|
+
* invoked with 3 arguments; for arrays they are (value, index, array) and for
|
767
|
+
* objects they are (value, key, object). The `callback` argument may also be
|
768
|
+
* the name of a property to sort by (e.g. 'length').
|
769
|
+
*
|
770
|
+
* @static
|
771
|
+
* @memberOf _
|
772
|
+
* @category Collections
|
773
|
+
* @param {Array|Object} collection The collection to iterate over.
|
774
|
+
* @param {Function|String} callback The function called per iteration or
|
775
|
+
* property name to sort by.
|
776
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
777
|
+
* @returns {Array} Returns a new array of sorted values.
|
778
|
+
* @example
|
779
|
+
*
|
780
|
+
* _.sortBy([1, 2, 3, 4, 5, 6], function(num) { return Math.sin(num); });
|
781
|
+
* // => [5, 4, 6, 3, 1, 2]
|
782
|
+
*/
|
783
|
+
function sortBy(collection, callback, thisArg) {
|
784
|
+
if (!isFunction(callback)) {
|
785
|
+
var prop = callback;
|
786
|
+
callback = function(collection) { return collection[prop]; };
|
787
|
+
} else if (thisArg) {
|
788
|
+
callback = bind(callback, thisArg);
|
789
|
+
}
|
790
|
+
return pluck(map(collection, function(value, index) {
|
791
|
+
return {
|
792
|
+
'criteria': callback(value, index, collection),
|
793
|
+
'value': value
|
794
|
+
};
|
795
|
+
}).sort(function(left, right) {
|
796
|
+
var a = left.criteria,
|
797
|
+
b = right.criteria;
|
798
|
+
|
799
|
+
if (a === undefined) {
|
800
|
+
return 1;
|
801
|
+
}
|
802
|
+
if (b === undefined) {
|
803
|
+
return -1;
|
804
|
+
}
|
805
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
806
|
+
}), 'value');
|
807
|
+
}
|
808
|
+
|
809
|
+
/**
|
810
|
+
* Checks if the `callback` returns truthy for **any** value of a `collection`.
|
811
|
+
* The function returns as soon as it finds passing value, and does not iterate
|
812
|
+
* over the entire `collection`. The `callback` is invoked with 3 arguments; for
|
813
|
+
* arrays they are (value, index, array) and for objects they are
|
814
|
+
* (value, key, object).
|
815
|
+
*
|
816
|
+
* @static
|
817
|
+
* @memberOf _
|
818
|
+
* @alias any
|
819
|
+
* @category Collections
|
820
|
+
* @param {Array|Object} collection The collection to iterate over.
|
821
|
+
* @param {Function} callback The function called per iteration.
|
822
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
823
|
+
* @returns {Boolean} Returns `true` if any value passes the callback check, else `false`.
|
824
|
+
* @example
|
825
|
+
*
|
826
|
+
* _.some([null, 0, 'yes', false]);
|
827
|
+
* // => true
|
828
|
+
*/
|
829
|
+
var some = iterationFactory(forEachFactoryOptions, everyFactoryOptions, {
|
830
|
+
'init': 'false',
|
831
|
+
'inLoop': everyFactoryOptions.inLoop.replace('!', '')
|
832
|
+
});
|
833
|
+
|
834
|
+
/**
|
835
|
+
* Uses a binary search to determine the smallest index at which the `value`
|
836
|
+
* should be inserted into the `collection` in order to maintain the sort order
|
837
|
+
* of the `collection`. If `callback` is passed, it will be executed for each
|
838
|
+
* value in the `collection` to compute their sort ranking. The `callback` is
|
839
|
+
* invoked with 1 argument.
|
840
|
+
*
|
841
|
+
* @static
|
842
|
+
* @memberOf _
|
843
|
+
* @category Collections
|
844
|
+
* @param {Array} array The array to iterate over.
|
845
|
+
* @param {Mixed} value The value to evaluate.
|
846
|
+
* @param {Function} [callback] The function called per iteration.
|
847
|
+
* @returns {Number} Returns the index at which the value should be inserted
|
848
|
+
* into the collection.
|
849
|
+
* @example
|
850
|
+
*
|
851
|
+
* _.sortedIndex([10, 20, 30, 40, 50], 35);
|
852
|
+
* // => 3
|
853
|
+
*/
|
854
|
+
function sortedIndex(array, object, callback) {
|
855
|
+
var low = 0,
|
856
|
+
high = array.length;
|
857
|
+
|
858
|
+
callback || (callback = identity);
|
859
|
+
while (low < high) {
|
860
|
+
var mid = (low + high) >> 1;
|
861
|
+
callback(array[mid]) < callback(object) ? (low = mid + 1) : (high = mid);
|
862
|
+
}
|
863
|
+
return low;
|
864
|
+
}
|
865
|
+
|
866
|
+
/**
|
867
|
+
* Converts the `collection`, into an array. Useful for converting the
|
868
|
+
* `arguments` object.
|
869
|
+
*
|
870
|
+
* @static
|
871
|
+
* @memberOf _
|
872
|
+
* @category Collections
|
873
|
+
* @param {Array|Object} collection The collection to convert.
|
874
|
+
* @returns {Array} Returns the new converted array.
|
875
|
+
* @example
|
876
|
+
*
|
877
|
+
* (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
|
878
|
+
* // => [2, 3, 4]
|
879
|
+
*/
|
880
|
+
function toArray(collection) {
|
881
|
+
if (!collection) {
|
882
|
+
return [];
|
883
|
+
}
|
884
|
+
if (isFunction(collection.toArray)) {
|
885
|
+
return collection.toArray();
|
886
|
+
}
|
887
|
+
var length = collection.length;
|
888
|
+
if (length === +length) {
|
889
|
+
return slice.call(collection);
|
890
|
+
}
|
891
|
+
return values(collection);
|
892
|
+
}
|
893
|
+
|
894
|
+
/**
|
895
|
+
* Produces an array of enumerable own property values of the `collection`.
|
896
|
+
*
|
897
|
+
* @static
|
898
|
+
* @memberOf _
|
899
|
+
* @alias methods
|
900
|
+
* @category Collections
|
901
|
+
* @param {Array|Object} collection The collection to inspect.
|
902
|
+
* @returns {Array} Returns a new array of property values.
|
903
|
+
* @example
|
904
|
+
*
|
905
|
+
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
|
906
|
+
* // => [1, 2, 3]
|
907
|
+
*/
|
908
|
+
var values = iterationFactory(mapFactoryOptions, {
|
909
|
+
'args': 'collection',
|
910
|
+
'inLoop': {
|
911
|
+
'array': 'result[index]=collection[index]',
|
912
|
+
'object': 'result[result.length]=collection[index]'
|
913
|
+
}
|
914
|
+
});
|
915
|
+
|
916
|
+
/*--------------------------------------------------------------------------*/
|
917
|
+
|
918
|
+
/**
|
919
|
+
* Produces a new array with all falsey values of `array` removed. The values
|
920
|
+
* `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.
|
921
|
+
*
|
922
|
+
* @static
|
923
|
+
* @memberOf _
|
924
|
+
* @category Arrays
|
925
|
+
* @param {Array} array The array to compact.
|
926
|
+
* @returns {Array} Returns a new filtered array.
|
927
|
+
* @example
|
928
|
+
*
|
929
|
+
* _.compact([0, 1, false, 2, '', 3]);
|
930
|
+
* // => [1, 2, 3]
|
931
|
+
*/
|
932
|
+
var compact = iterationFactory({
|
933
|
+
'args': 'array',
|
934
|
+
'init': '[]',
|
935
|
+
'inLoop': 'if(array[index])result.push(array[index])'
|
936
|
+
});
|
937
|
+
|
938
|
+
/**
|
939
|
+
* Produces a new array of `array` values not present in the other arrays
|
940
|
+
* using strict equality for comparisons, i.e. `===`.
|
941
|
+
*
|
942
|
+
* @static
|
943
|
+
* @memberOf _
|
944
|
+
* @category Arrays
|
945
|
+
* @param {Array} array The array to process.
|
946
|
+
* @param {Mixed} [array1, array2, ...] Arrays to check.
|
947
|
+
* @returns {Array} Returns a new array of `array` values not present in the
|
948
|
+
* other arrays.
|
949
|
+
* @example
|
950
|
+
*
|
951
|
+
* _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
|
952
|
+
* // => [1, 3, 4]
|
953
|
+
*/
|
954
|
+
var difference = iterationFactory(differenceFactoryOptions);
|
955
|
+
|
956
|
+
/**
|
957
|
+
* Gets the first value of the `array`. Pass `n` to return the first `n` values
|
958
|
+
* of the `array`.
|
959
|
+
*
|
960
|
+
* @static
|
961
|
+
* @memberOf _
|
962
|
+
* @alias head, take
|
963
|
+
* @category Arrays
|
964
|
+
* @param {Array} array The array to query.
|
965
|
+
* @param {Number} [n] The number of elements to return.
|
966
|
+
* @param {Object} [guard] Internally used to allow this method to work with
|
967
|
+
* others like `_.map` without using their callback `index` argument for `n`.
|
968
|
+
* @returns {Mixed} Returns the first value or an array of the first `n` values
|
969
|
+
* of the `array`.
|
970
|
+
* @example
|
971
|
+
*
|
972
|
+
* _.first([5, 4, 3, 2, 1]);
|
973
|
+
* // => 5
|
974
|
+
*/
|
975
|
+
function first(array, n, guard) {
|
976
|
+
return (n == undefined || guard) ? array[0] : slice.call(array, 0, n);
|
977
|
+
}
|
978
|
+
|
979
|
+
/**
|
980
|
+
* Flattens a nested array (the nesting can be to any depth). If `shallow` is
|
981
|
+
* truthy, `array` will only be flattened a single level.
|
982
|
+
*
|
983
|
+
* @static
|
984
|
+
* @memberOf _
|
985
|
+
* @category Arrays
|
986
|
+
* @param {Array} array The array to compact.
|
987
|
+
* @param {Boolean} shallow A flag to indicate only flattening a single level.
|
988
|
+
* @returns {Array} Returns a new flattened array.
|
989
|
+
* @example
|
990
|
+
*
|
991
|
+
* _.flatten([1, [2], [3, [[4]]]]);
|
992
|
+
* // => [1, 2, 3, 4];
|
993
|
+
*
|
994
|
+
* _.flatten([1, [2], [3, [[4]]]], true);
|
995
|
+
* // => [1, 2, 3, [[4]]];
|
996
|
+
*/
|
997
|
+
function flatten(array, shallow) {
|
998
|
+
if (shallow) {
|
999
|
+
return concat.apply([], array);
|
1000
|
+
}
|
1001
|
+
return reduce(array, function(accumulator, value) {
|
1002
|
+
if (isArray(value)) {
|
1003
|
+
push.apply(accumulator, flatten(value));
|
1004
|
+
return accumulator;
|
1005
|
+
}
|
1006
|
+
accumulator.push(value);
|
1007
|
+
return accumulator;
|
1008
|
+
}, []);
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
/**
|
1012
|
+
* Gets the index at which the first occurrence of `value` is found using
|
1013
|
+
* strict equality for comparisons, i.e. `===`. If the `array` is already
|
1014
|
+
* sorted, passing `true` for `isSorted` will run a faster binary search.
|
1015
|
+
*
|
1016
|
+
* @static
|
1017
|
+
* @memberOf _
|
1018
|
+
* @category Arrays
|
1019
|
+
* @param {Array} array The array to search.
|
1020
|
+
* @param {Mixed} value The value to search for.
|
1021
|
+
* @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted.
|
1022
|
+
* @returns {Number} Returns the index of the matched value or `-1`.
|
1023
|
+
* @example
|
1024
|
+
*
|
1025
|
+
* _.indexOf([1, 2, 3], 2);
|
1026
|
+
* // => 1
|
1027
|
+
*/
|
1028
|
+
function indexOf(array, value, isSorted) {
|
1029
|
+
var index, length;
|
1030
|
+
if (array == undefined) {
|
1031
|
+
return -1;
|
1032
|
+
}
|
1033
|
+
if (isSorted) {
|
1034
|
+
index = sortedIndex(array, value);
|
1035
|
+
return array[index] === value ? index : -1;
|
1036
|
+
}
|
1037
|
+
for (index = 0, length = array.length; index < length; index++) {
|
1038
|
+
if (array[index] === value) {
|
1039
|
+
return index;
|
1040
|
+
}
|
1041
|
+
}
|
1042
|
+
return -1;
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
/**
|
1046
|
+
* Gets all but the last value of the `array`. Pass `n` to exclude the last `n`
|
1047
|
+
* values from the result.
|
1048
|
+
*
|
1049
|
+
* @static
|
1050
|
+
* @memberOf _
|
1051
|
+
* @category Arrays
|
1052
|
+
* @param {Array} array The array to query.
|
1053
|
+
* @param {Number} [n] The number of elements to return.
|
1054
|
+
* @param {Object} [guard] Internally used to allow this method to work with
|
1055
|
+
* others like `_.map` without using their callback `index` argument for `n`.
|
1056
|
+
* @returns {Array} Returns all but the last value or `n` values of the `array`.
|
1057
|
+
* @example
|
1058
|
+
*
|
1059
|
+
* _.initial([5, 4, 3, 2, 1]);
|
1060
|
+
* // => [5, 4, 3, 2]
|
1061
|
+
*/
|
1062
|
+
function initial(array, n, guard) {
|
1063
|
+
return slice.call(array, 0, -((n == undefined || guard) ? 1 : n));
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
/**
|
1067
|
+
* Computes the intersection of all the passed-in arrays.
|
1068
|
+
*
|
1069
|
+
* @static
|
1070
|
+
* @memberOf _
|
1071
|
+
* @alias intersect
|
1072
|
+
* @category Arrays
|
1073
|
+
* @param {Mixed} [array1, array2, ...] Arrays to process.
|
1074
|
+
* @returns {Array} Returns a new array of unique values, in order, that are
|
1075
|
+
* present in **all** of the arrays.
|
1076
|
+
* @example
|
1077
|
+
*
|
1078
|
+
* _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
1079
|
+
* // => [1, 2]
|
1080
|
+
*/
|
1081
|
+
function intersection(array) {
|
1082
|
+
var rest = slice.call(arguments, 1);
|
1083
|
+
return filter(uniq(array), function(value) {
|
1084
|
+
return every(rest, function(other) {
|
1085
|
+
return indexOf(other, value) >= 0;
|
1086
|
+
});
|
1087
|
+
});
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
/**
|
1091
|
+
* Gets the last value of the `array`. Pass `n` to return the lasy `n` values
|
1092
|
+
* of the `array`.
|
1093
|
+
*
|
1094
|
+
* @static
|
1095
|
+
* @memberOf _
|
1096
|
+
* @category Arrays
|
1097
|
+
* @param {Array} array The array to query.
|
1098
|
+
* @param {Number} [n] The number of elements to return.
|
1099
|
+
* @param {Object} [guard] Internally used to allow this method to work with
|
1100
|
+
* others like `_.map` without using their callback `index` argument for `n`.
|
1101
|
+
* @returns {Array} Returns all but the last value or `n` values of the `array`.
|
1102
|
+
* @example
|
1103
|
+
*
|
1104
|
+
* _.last([5, 4, 3, 2, 1]);
|
1105
|
+
* // => 1
|
1106
|
+
*/
|
1107
|
+
function last(array, n, guard) {
|
1108
|
+
var length = array.length;
|
1109
|
+
return (n == undefined || guard) ? array[length - 1] : slice.call(array, -n || length);
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
/**
|
1113
|
+
* Gets the index at which the last occurrence of `value` is found using
|
1114
|
+
* strict equality for comparisons, i.e. `===`.
|
1115
|
+
*
|
1116
|
+
* @static
|
1117
|
+
* @memberOf _
|
1118
|
+
* @category Arrays
|
1119
|
+
* @param {Array} array The array to search.
|
1120
|
+
* @param {Mixed} value The value to search for.
|
1121
|
+
* @returns {Number} Returns the index of the matched value or `-1`.
|
1122
|
+
* @example
|
1123
|
+
*
|
1124
|
+
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
|
1125
|
+
* // => 4
|
1126
|
+
*/
|
1127
|
+
function lastIndexOf(array, value) {
|
1128
|
+
if (array == undefined) {
|
1129
|
+
return -1;
|
1130
|
+
}
|
1131
|
+
var index = array.length;
|
1132
|
+
while (index--) {
|
1133
|
+
if (array[index] === value) {
|
1134
|
+
return index;
|
1135
|
+
}
|
1136
|
+
}
|
1137
|
+
return -1;
|
1138
|
+
}
|
1139
|
+
|
1140
|
+
/**
|
1141
|
+
* Creates an array of numbers (positive and/or negative) progressing from
|
1142
|
+
* `start` up to but not including `stop`. This method is a port of Python's
|
1143
|
+
* `range()` function. See http://docs.python.org/library/functions.html#range.
|
1144
|
+
*
|
1145
|
+
* @static
|
1146
|
+
* @memberOf _
|
1147
|
+
* @category Arrays
|
1148
|
+
* @param {Number} [start=0] The start of the range.
|
1149
|
+
* @param {Number} end The end of the range.
|
1150
|
+
* @param {Number} [step=1] The value to increment or descrement by.
|
1151
|
+
* @returns {Array} Returns a new range array.
|
1152
|
+
* @example
|
1153
|
+
*
|
1154
|
+
* _.range(10);
|
1155
|
+
* // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
1156
|
+
*
|
1157
|
+
* _.range(1, 11);
|
1158
|
+
* // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
1159
|
+
*
|
1160
|
+
* _.range(0, 30, 5);
|
1161
|
+
* // => [0, 5, 10, 15, 20, 25]
|
1162
|
+
*
|
1163
|
+
* _.range(0, -10, -1);
|
1164
|
+
* // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
|
1165
|
+
*
|
1166
|
+
* _.range(0);
|
1167
|
+
* // => []
|
1168
|
+
*/
|
1169
|
+
function range(start, end, step) {
|
1170
|
+
step || (step = 1);
|
1171
|
+
if (arguments.length < 2) {
|
1172
|
+
end = start || 0;
|
1173
|
+
start = 0;
|
1174
|
+
}
|
1175
|
+
|
1176
|
+
var index = -1,
|
1177
|
+
length = Math.max(Math.ceil((end - start) / step), 0),
|
1178
|
+
result = Array(length);
|
1179
|
+
|
1180
|
+
while (++index < length) {
|
1181
|
+
result[index] = start;
|
1182
|
+
start += step;
|
1183
|
+
}
|
1184
|
+
return result;
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
/**
|
1188
|
+
* The opposite of `_.initial`, this method gets all but the first value of
|
1189
|
+
* the `array`. Pass `n` to exclude the first `n` values from the result.
|
1190
|
+
*
|
1191
|
+
* @static
|
1192
|
+
* @memberOf _
|
1193
|
+
* @alias tail
|
1194
|
+
* @category Arrays
|
1195
|
+
* @param {Array} array The array to query.
|
1196
|
+
* @param {Number} [n] The number of elements to return.
|
1197
|
+
* @param {Object} [guard] Internally used to allow this method to work with
|
1198
|
+
* others like `_.map` without using their callback `index` argument for `n`.
|
1199
|
+
* @returns {Array} Returns all but the first value or `n` values of the `array`.
|
1200
|
+
* @example
|
1201
|
+
*
|
1202
|
+
* _.rest([5, 4, 3, 2, 1]);
|
1203
|
+
* // => [4, 3, 2, 1]
|
1204
|
+
*/
|
1205
|
+
function rest(array, n, guard) {
|
1206
|
+
return slice.call(array, (n == undefined || guard) ? 1 : n);
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
/**
|
1210
|
+
* Computes the union of the passed-in arrays.
|
1211
|
+
*
|
1212
|
+
* @static
|
1213
|
+
* @memberOf _
|
1214
|
+
* @category Arrays
|
1215
|
+
* @param {Mixed} [array1, array2, ...] Arrays to process.
|
1216
|
+
* @returns {Array} Returns a new array of unique values, in order, that are
|
1217
|
+
* present in one or more of the arrays.
|
1218
|
+
* @example
|
1219
|
+
*
|
1220
|
+
* _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
1221
|
+
* // => [1, 2, 3, 101, 10]
|
1222
|
+
*/
|
1223
|
+
function union() {
|
1224
|
+
return uniq(flatten(arguments, true));
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
/**
|
1228
|
+
* Produces a duplicate-value-free version of the `array` using strict equality
|
1229
|
+
* for comparisons, i.e. `===`. If the `array` is already sorted, passing `true`
|
1230
|
+
* for `isSorted` will run a faster algorithm. If `callback` is passed,
|
1231
|
+
* each value of `array` is passed through a transformation `callback` before
|
1232
|
+
* uniqueness is computed. The `callback` is invoked with 3 arguments;
|
1233
|
+
* (value, index, array).
|
1234
|
+
*
|
1235
|
+
* @static
|
1236
|
+
* @memberOf _
|
1237
|
+
* @alias unique
|
1238
|
+
* @category Arrays
|
1239
|
+
* @param {Array} array The array to process.
|
1240
|
+
* @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted.
|
1241
|
+
* @param {Function} [callback] A
|
1242
|
+
* @returns {Array} Returns a duplicate-value-free array.
|
1243
|
+
* @example
|
1244
|
+
*
|
1245
|
+
* _.uniq([1, 2, 1, 3, 1, 4]);
|
1246
|
+
* // => [1, 2, 3, 4]
|
1247
|
+
*/
|
1248
|
+
function uniq(array, isSorted, callback) {
|
1249
|
+
var initial = callback ? map(array, callback) : array,
|
1250
|
+
result = [];
|
1251
|
+
|
1252
|
+
// the `isSorted` flag is irrelevant if the array only contains two elements.
|
1253
|
+
if (array.length < 3) {
|
1254
|
+
isSorted = true;
|
1255
|
+
}
|
1256
|
+
reduce(initial, function(accumulator, value, index) {
|
1257
|
+
if (isSorted ? last(accumulator) !== value || !accumulator.length : indexOf(accumulator, value) < 0) {
|
1258
|
+
accumulator.push(value);
|
1259
|
+
result.push(array[index]);
|
1260
|
+
}
|
1261
|
+
return accumulator;
|
1262
|
+
}, []);
|
1263
|
+
|
1264
|
+
return result;
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
/**
|
1268
|
+
* Produces a new array with all occurrences of the values removed using strict
|
1269
|
+
* equality for comparisons, i.e. `===`.
|
1270
|
+
*
|
1271
|
+
* @static
|
1272
|
+
* @memberOf _
|
1273
|
+
* @category Arrays
|
1274
|
+
* @param {Array} array The array to filter.
|
1275
|
+
* @param {Mixed} [value1, value2, ...] Values to remove.
|
1276
|
+
* @returns {Array} Returns a new filtered array.
|
1277
|
+
* @example
|
1278
|
+
*
|
1279
|
+
* _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
|
1280
|
+
* // => [2, 3, 4]
|
1281
|
+
*/
|
1282
|
+
var without = iterationFactory(differenceFactoryOptions, {
|
1283
|
+
'top': 'var values=slice.call(arguments,1)',
|
1284
|
+
'init': '[]'
|
1285
|
+
});
|
1286
|
+
|
1287
|
+
/**
|
1288
|
+
* Merges together the values of each of the arrays with the value at the
|
1289
|
+
* corresponding position. Useful for separate data sources that are coordinated
|
1290
|
+
* through matching array indexes. For a matrix of nested arrays, `_.zip.apply(...)`
|
1291
|
+
* can transpose the matrix in a similar fashion.
|
1292
|
+
*
|
1293
|
+
* @static
|
1294
|
+
* @memberOf _
|
1295
|
+
* @category Arrays
|
1296
|
+
* @param {Mixed} [array1, array2, ...] Arrays to process.
|
1297
|
+
* @returns {Array} Returns a new array of merged arrays.
|
1298
|
+
* @example
|
1299
|
+
*
|
1300
|
+
* _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
|
1301
|
+
* // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]]
|
1302
|
+
*/
|
1303
|
+
function zip() {
|
1304
|
+
var index = -1,
|
1305
|
+
length = max(pluck(arguments, 'length')),
|
1306
|
+
result = Array(length);
|
1307
|
+
|
1308
|
+
while (++index < length) {
|
1309
|
+
result[index] = pluck(arguments, index);
|
1310
|
+
}
|
1311
|
+
return result;
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
/*--------------------------------------------------------------------------*/
|
1315
|
+
|
1316
|
+
/**
|
1317
|
+
* Creates a new function that is restricted to executing only after it is
|
1318
|
+
* called a given number of `times`.
|
1319
|
+
*
|
1320
|
+
* @static
|
1321
|
+
* @memberOf _
|
1322
|
+
* @category Functions
|
1323
|
+
* @param {Number} times The number of times the function must be called before
|
1324
|
+
* it is executed.
|
1325
|
+
* @param {Function} func The function to restrict.
|
1326
|
+
* @returns {Function} Returns the new restricted function.
|
1327
|
+
* @example
|
1328
|
+
*
|
1329
|
+
* var renderNotes = _.after(notes.length, render);
|
1330
|
+
* _.forEach(notes, function(note) {
|
1331
|
+
* note.asyncSave({ 'success': renderNotes });
|
1332
|
+
* });
|
1333
|
+
* // renderNotes is run once, after all notes have saved.
|
1334
|
+
*/
|
1335
|
+
function after(times, func) {
|
1336
|
+
if (times < 1) {
|
1337
|
+
return func();
|
1338
|
+
}
|
1339
|
+
return function() {
|
1340
|
+
if (--times < 1) {
|
1341
|
+
return func.apply(this, arguments);
|
1342
|
+
}
|
1343
|
+
};
|
1344
|
+
}
|
1345
|
+
|
1346
|
+
/**
|
1347
|
+
* Creates a new function that, when called, invokes `func` with the `this`
|
1348
|
+
* binding of `thisArg` and prepends additional arguments to those passed to
|
1349
|
+
* the bound function.
|
1350
|
+
*
|
1351
|
+
* @static
|
1352
|
+
* @memberOf _
|
1353
|
+
* @category Functions
|
1354
|
+
* @param {Function} func The function to bind.
|
1355
|
+
* @param @param {Mixed} [thisArg] The `this` binding of `func`.
|
1356
|
+
* @param {Mixed} [arg1, arg2, ...] Arguments to prepend to those passed to the bound function.
|
1357
|
+
* @returns {Function} Returns the new bound function.
|
1358
|
+
* @example
|
1359
|
+
*
|
1360
|
+
* var func = function(greeting) { return greeting + ': ' + this.name; };
|
1361
|
+
* func = _.bind(func, { 'name': 'moe' }, 'hi');
|
1362
|
+
* func();
|
1363
|
+
* // => 'hi: moe'
|
1364
|
+
*/
|
1365
|
+
function bind(func, thisArg) {
|
1366
|
+
var args = slice.call(arguments, 2),
|
1367
|
+
argsLength = args.length;
|
1368
|
+
|
1369
|
+
return function() {
|
1370
|
+
args.length = argsLength;
|
1371
|
+
push.apply(args, arguments);
|
1372
|
+
return func.apply(thisArg, args);
|
1373
|
+
};
|
1374
|
+
}
|
1375
|
+
|
1376
|
+
/**
|
1377
|
+
* Binds methods on the `object` to the object, overwriting the non-bound method.
|
1378
|
+
* If no method names are provided, all the function properties of the `object`
|
1379
|
+
* will be bound.
|
1380
|
+
*
|
1381
|
+
* @static
|
1382
|
+
* @memberOf _
|
1383
|
+
* @category Functions
|
1384
|
+
* @param {Object} object The object to bind and assign the bound methods to.
|
1385
|
+
* @param {Mixed} [methodName1, methodName2, ...] Method names on the object to bind.
|
1386
|
+
* @returns {Object} Returns the `object`.
|
1387
|
+
* @example
|
1388
|
+
*
|
1389
|
+
* var buttonView = {
|
1390
|
+
* 'label': 'lodash',
|
1391
|
+
* 'onClick': function() { alert('clicked: ' + this.label); },
|
1392
|
+
* 'onHover': function() { console.log('hovering: ' + this.label); }
|
1393
|
+
* };
|
1394
|
+
*
|
1395
|
+
* _.bindAll(buttonView);
|
1396
|
+
* jQuery('#lodash_button').on('click', buttonView.onClick);
|
1397
|
+
* // => When the button is clicked, `this.label` will have the correct value
|
1398
|
+
*/
|
1399
|
+
function bindAll(object) {
|
1400
|
+
var funcs = arguments,
|
1401
|
+
index = 1;
|
1402
|
+
|
1403
|
+
if (funcs.length == 1) {
|
1404
|
+
index = 0;
|
1405
|
+
funcs = functions(object);
|
1406
|
+
}
|
1407
|
+
for (var length = funcs.length; index < length; index++) {
|
1408
|
+
object[funcs[index]] = bind(object[funcs[index]], object);
|
1409
|
+
}
|
1410
|
+
return object;
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
/**
|
1414
|
+
* Creates a new function that is the composition of the passed functions,
|
1415
|
+
* where each function consumes the return value of the function that follows.
|
1416
|
+
* In math terms, composing thefunctions `f()`, `g()`, and `h()` produces `f(g(h()))`.
|
1417
|
+
*
|
1418
|
+
* @static
|
1419
|
+
* @memberOf _
|
1420
|
+
* @category Functions
|
1421
|
+
* @param {Mixed} [func1, func2, ...] Functions to compose.
|
1422
|
+
* @returns {Function} Returns the new composed function.
|
1423
|
+
* @example
|
1424
|
+
*
|
1425
|
+
* var greet = function(name) { return 'hi: ' + name; };
|
1426
|
+
* var exclaim = function(statement) { return statement + '!'; };
|
1427
|
+
* var welcome = _.compose(exclaim, greet);
|
1428
|
+
* welcome('moe');
|
1429
|
+
* // => 'hi: moe!'
|
1430
|
+
*/
|
1431
|
+
function compose() {
|
1432
|
+
var funcs = arguments;
|
1433
|
+
return function() {
|
1434
|
+
var args = arguments,
|
1435
|
+
length = funcs.length;
|
1436
|
+
|
1437
|
+
while (length--) {
|
1438
|
+
args = [funcs[length].apply(this, args)];
|
1439
|
+
}
|
1440
|
+
return args[0];
|
1441
|
+
};
|
1442
|
+
}
|
1443
|
+
|
1444
|
+
/**
|
1445
|
+
* Creates a new function that will postpone its execution until after `wait`
|
1446
|
+
* milliseconds have elapsed since the last time it was invoked. Pass `true`
|
1447
|
+
* for `immediate` to cause debounce to invoke the function on the leading,
|
1448
|
+
* instead of the trailing, edge of the `wait` timeout.
|
1449
|
+
*
|
1450
|
+
* @static
|
1451
|
+
* @memberOf _
|
1452
|
+
* @category Functions
|
1453
|
+
* @param {Function} func The function to debounce.
|
1454
|
+
* @param {Number} wait The number of milliseconds to postone.
|
1455
|
+
* @param {Boolean} immediate A flag to indicate execution is on the leading
|
1456
|
+
* edge of the timeout.
|
1457
|
+
* @returns {Function} Returns the new debounced function.
|
1458
|
+
* @example
|
1459
|
+
*
|
1460
|
+
* var lazyLayout = _.debounce(calculateLayout, 300);
|
1461
|
+
* jQuery(window).on('resize', lazyLayout);
|
1462
|
+
*/
|
1463
|
+
function debounce(func, wait, immediate) {
|
1464
|
+
var timeout;
|
1465
|
+
return function() {
|
1466
|
+
var args = arguments,
|
1467
|
+
thisArg = this;
|
1468
|
+
|
1469
|
+
if (immediate && !timeout) {
|
1470
|
+
func.apply(thisArg, args);
|
1471
|
+
}
|
1472
|
+
clearTimeout(timeout);
|
1473
|
+
timeout = setTimeout(function() {
|
1474
|
+
timeout = undefined;
|
1475
|
+
if (!immediate) {
|
1476
|
+
func.apply(thisArg, args);
|
1477
|
+
}
|
1478
|
+
}, wait);
|
1479
|
+
};
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
/**
|
1483
|
+
* Invokes the `func` function after `wait` milliseconds. Additional arguments
|
1484
|
+
* are passed `func` when it is invoked.
|
1485
|
+
*
|
1486
|
+
* @static
|
1487
|
+
* @memberOf _
|
1488
|
+
* @category Functions
|
1489
|
+
* @param {Function} func The function to delay.
|
1490
|
+
* @param {Number} wait The number of milliseconds to delay execution.
|
1491
|
+
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
1492
|
+
* @returns {Number} Returns the `setTimeout` timeout id.
|
1493
|
+
* @example
|
1494
|
+
*
|
1495
|
+
* var log = _.bind(console.log, console);
|
1496
|
+
* _.delay(log, 1000, 'logged later');
|
1497
|
+
* // => 'logged later' (Appears after one second.)
|
1498
|
+
*/
|
1499
|
+
function delay(func, wait) {
|
1500
|
+
var args = slice.call(arguments, 2);
|
1501
|
+
return setTimeout(function() { return func.apply(undefined, args); }, wait);
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
/**
|
1505
|
+
* Defers invoking the `func` function until the current call stack has cleared.
|
1506
|
+
* Additional arguments are passed to `func` when it is invoked.
|
1507
|
+
*
|
1508
|
+
* @static
|
1509
|
+
* @memberOf _
|
1510
|
+
* @category Functions
|
1511
|
+
* @param {Function} func The function to defer.
|
1512
|
+
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
1513
|
+
* @returns {Number} Returns the `setTimeout` timeout id.
|
1514
|
+
* @example
|
1515
|
+
*
|
1516
|
+
* _.defer(function() { alert('deferred'); });
|
1517
|
+
* // Returns from the function before the alert runs.
|
1518
|
+
*/
|
1519
|
+
function defer(func) {
|
1520
|
+
var args = slice.call(arguments, 1);
|
1521
|
+
return setTimeout(function() { return func.apply(undefined, args); }, 1);
|
1522
|
+
}
|
1523
|
+
|
1524
|
+
/**
|
1525
|
+
* Creates a new function that memoizes the result of `func`. If `resolver` is
|
1526
|
+
* passed, it will be used to determine the cache key for storing the result
|
1527
|
+
* based on the arguments passed to the memoized function. By default, the first
|
1528
|
+
* argument passed to the memoized function is used as the cache key.
|
1529
|
+
*
|
1530
|
+
* @static
|
1531
|
+
* @memberOf _
|
1532
|
+
* @category Functions
|
1533
|
+
* @param {Function} func The function to have its output memoized.
|
1534
|
+
* @param {Function} [resolver] A function used to resolve the cache key.
|
1535
|
+
* @returns {Function} Returns the new memoizing function.
|
1536
|
+
* @example
|
1537
|
+
*
|
1538
|
+
* var fibonacci = _.memoize(function(n) {
|
1539
|
+
* return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
|
1540
|
+
* });
|
1541
|
+
*/
|
1542
|
+
function memoize(func, resolver) {
|
1543
|
+
var cache = {};
|
1544
|
+
return function() {
|
1545
|
+
var prop = resolver ? resolver.apply(this, arguments) : arguments[0];
|
1546
|
+
return hasOwnProperty.call(cache, prop)
|
1547
|
+
? cache[prop]
|
1548
|
+
: (cache[prop] = func.apply(this, arguments));
|
1549
|
+
};
|
1550
|
+
}
|
1551
|
+
|
1552
|
+
/**
|
1553
|
+
* Creates a new function that is restricted to one execution. Repeat calls to
|
1554
|
+
* the function will return the value of the first call.
|
1555
|
+
*
|
1556
|
+
* @static
|
1557
|
+
* @memberOf _
|
1558
|
+
* @category Functions
|
1559
|
+
* @param {Function} func The function to restrict.
|
1560
|
+
* @returns {Function} Returns the new restricted function.
|
1561
|
+
* @example
|
1562
|
+
*
|
1563
|
+
* var initialize = _.once(createApplication);
|
1564
|
+
* initialize();
|
1565
|
+
* initialize();
|
1566
|
+
* // Application is only created once.
|
1567
|
+
*/
|
1568
|
+
function once(func) {
|
1569
|
+
var result,
|
1570
|
+
ran = false;
|
1571
|
+
|
1572
|
+
return function() {
|
1573
|
+
if (ran) {
|
1574
|
+
return result;
|
1575
|
+
}
|
1576
|
+
ran = true;
|
1577
|
+
result = func.apply(this, arguments);
|
1578
|
+
return result;
|
1579
|
+
};
|
1580
|
+
}
|
1581
|
+
|
1582
|
+
/**
|
1583
|
+
* Creates a new function that, when invoked, will only call the original
|
1584
|
+
* function at most once per every `wait` milliseconds.
|
1585
|
+
*
|
1586
|
+
* @static
|
1587
|
+
* @memberOf _
|
1588
|
+
* @category Functions
|
1589
|
+
* @param {Function} func The function to throttle.
|
1590
|
+
* @param {Number} wait The number of milliseconds to throttle executions to.
|
1591
|
+
* @returns {Function} Returns the new throttled function.
|
1592
|
+
* @example
|
1593
|
+
*
|
1594
|
+
* var throttled = _.throttle(updatePosition, 100);
|
1595
|
+
* jQuery(window).on('scroll', throttled);
|
1596
|
+
*/
|
1597
|
+
function throttle(func, wait) {
|
1598
|
+
var args, more, result, thisArg, throttling, timeout,
|
1599
|
+
whenDone = debounce(function() { more = throttling = false; }, wait);
|
1600
|
+
|
1601
|
+
return function() {
|
1602
|
+
args = arguments;
|
1603
|
+
thisArg = this;
|
1604
|
+
|
1605
|
+
if (!timeout) {
|
1606
|
+
timeout = setTimeout(function() {
|
1607
|
+
timeout = undefined;
|
1608
|
+
if (more) {
|
1609
|
+
func.apply(thisArg, args);
|
1610
|
+
}
|
1611
|
+
whenDone();
|
1612
|
+
}, wait);
|
1613
|
+
}
|
1614
|
+
if (throttling) {
|
1615
|
+
more = true;
|
1616
|
+
} else {
|
1617
|
+
result = func.apply(thisArg, args);
|
1618
|
+
}
|
1619
|
+
whenDone();
|
1620
|
+
throttling = true;
|
1621
|
+
return result;
|
1622
|
+
};
|
1623
|
+
}
|
1624
|
+
|
1625
|
+
/**
|
1626
|
+
* Create a new function that passes the `func` function to the `wrapper`
|
1627
|
+
* function as its first argument. Additional arguments are appended to those
|
1628
|
+
* passed to the `wrapper` function.
|
1629
|
+
*
|
1630
|
+
* @static
|
1631
|
+
* @memberOf _
|
1632
|
+
* @category Functions
|
1633
|
+
* @param {Function} func The function to wrap.
|
1634
|
+
* @param {Function} wrapper The wrapper function.
|
1635
|
+
* @param {Mixed} [arg1, arg2, ...] Arguments to append to those passed to the wrapper.
|
1636
|
+
* @returns {Function} Returns the new function.
|
1637
|
+
* @example
|
1638
|
+
*
|
1639
|
+
* var hello = function(name) { return 'hello: ' + name; };
|
1640
|
+
* hello = _.wrap(hello, function(func) {
|
1641
|
+
* return 'before, ' + func('moe') + ', after';
|
1642
|
+
* });
|
1643
|
+
* hello();
|
1644
|
+
* // => 'before, hello: moe, after'
|
1645
|
+
*/
|
1646
|
+
function wrap(func, wrapper) {
|
1647
|
+
return function() {
|
1648
|
+
var args = [func];
|
1649
|
+
push.apply(args, arguments);
|
1650
|
+
return wrapper.apply(this, args);
|
1651
|
+
};
|
1652
|
+
}
|
1653
|
+
|
1654
|
+
/*--------------------------------------------------------------------------*/
|
1655
|
+
|
1656
|
+
/**
|
1657
|
+
* Create a shallow clone of the `value`. Any nested objects or arrays will be
|
1658
|
+
* assigned by reference and not cloned.
|
1659
|
+
*
|
1660
|
+
* @static
|
1661
|
+
* @memberOf _
|
1662
|
+
* @category Objects
|
1663
|
+
* @param {Mixed} value The value to clone.
|
1664
|
+
* @returns {Mixed} Returns the cloned `value`.
|
1665
|
+
* @example
|
1666
|
+
*
|
1667
|
+
* _.clone({ 'name': 'moe' });
|
1668
|
+
* // => { 'name': 'moe' };
|
1669
|
+
*/
|
1670
|
+
function clone(value) {
|
1671
|
+
if (value !== Object(value)) {
|
1672
|
+
return value;
|
1673
|
+
}
|
1674
|
+
return isArray(value) ? value.slice() : extend({}, value);
|
1675
|
+
}
|
1676
|
+
|
1677
|
+
/**
|
1678
|
+
* Assigns missing properties in `object` with default values from the defaults
|
1679
|
+
* objects. As soon as a property is set, additional defaults of the same
|
1680
|
+
* property will be ignored.
|
1681
|
+
*
|
1682
|
+
* @static
|
1683
|
+
* @memberOf _
|
1684
|
+
* @category Objects
|
1685
|
+
* @param {Object} object The object to populate.
|
1686
|
+
* @param {Object} [defaults1, defaults2, ..] The defaults objects to apply to `object`.
|
1687
|
+
* @returns {Object} Returns `object`.
|
1688
|
+
* @example
|
1689
|
+
*
|
1690
|
+
* var iceCream = { 'flavor': 'chocolate' };
|
1691
|
+
* _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'lots' });
|
1692
|
+
* // => { 'flavor': 'chocolate', 'sprinkles': 'lots' }
|
1693
|
+
*/
|
1694
|
+
var defaults = iterationFactory(extendFactoryOptions, {
|
1695
|
+
'inLoop': 'if(object[index]==undefined)' + extendFactoryOptions.inLoop
|
1696
|
+
});
|
1697
|
+
|
1698
|
+
/**
|
1699
|
+
* Copies enumerable properties from the source objects to the `destination` object.
|
1700
|
+
* Subsequent sources will overwrite propery assignments of previous sources.
|
1701
|
+
*
|
1702
|
+
* @static
|
1703
|
+
* @memberOf _
|
1704
|
+
* @category Objects
|
1705
|
+
* @param {Object} object The destination object.
|
1706
|
+
* @param {Object} [source1, source2, ..] The source objects.
|
1707
|
+
* @returns {Object} Returns the destination object.
|
1708
|
+
* @example
|
1709
|
+
*
|
1710
|
+
* _.extend({ 'name': 'moe' }, { 'age': 40 });
|
1711
|
+
* // => { 'name': 'moe', 'age': 40 }
|
1712
|
+
*/
|
1713
|
+
var extend = iterationFactory(extendFactoryOptions);
|
1714
|
+
|
1715
|
+
/**
|
1716
|
+
* Produces a sorted array of the properties, own and inherited, of `object`
|
1717
|
+
* that have function values.
|
1718
|
+
*
|
1719
|
+
* @static
|
1720
|
+
* @memberOf _
|
1721
|
+
* @alias methods
|
1722
|
+
* @category Objects
|
1723
|
+
* @param {Object} object The object to inspect.
|
1724
|
+
* @returns {Array} Returns a new array of property names that have function values.
|
1725
|
+
* @example
|
1726
|
+
*
|
1727
|
+
* _.functions(_);
|
1728
|
+
* // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
|
1729
|
+
*/
|
1730
|
+
var functions = iterationFactory(keysFactoryOptions, {
|
1731
|
+
'top': '',
|
1732
|
+
'useHas': false,
|
1733
|
+
'inLoop': 'if(toString.call(object[index])==funcClass)result.push(index)',
|
1734
|
+
'returns': 'result.sort()'
|
1735
|
+
});
|
1736
|
+
|
1737
|
+
/**
|
1738
|
+
* Checks if the specified object `property` exists and is a direct property,
|
1739
|
+
* instead of an inherited property.
|
1740
|
+
*
|
1741
|
+
* @static
|
1742
|
+
* @memberOf _
|
1743
|
+
* @category Objects
|
1744
|
+
* @param {Object} object The object to check.
|
1745
|
+
* @param {String} property The property to check for.
|
1746
|
+
* @returns {Boolean} Returns `true` if key is a direct property, else `false`.
|
1747
|
+
* @example
|
1748
|
+
*
|
1749
|
+
* _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
|
1750
|
+
* // => true
|
1751
|
+
*/
|
1752
|
+
function has(object, prop) {
|
1753
|
+
return hasOwnProperty.call(object, prop);
|
1754
|
+
}
|
1755
|
+
|
1756
|
+
/**
|
1757
|
+
* Checks if a `value` is an `arguments` object.
|
1758
|
+
*
|
1759
|
+
* @static
|
1760
|
+
* @memberOf _
|
1761
|
+
* @category Objects
|
1762
|
+
* @param {Mixed} value The value to check.
|
1763
|
+
* @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
|
1764
|
+
* @example
|
1765
|
+
*
|
1766
|
+
* (function() { return _.isArguments(arguments); })(1, 2, 3);
|
1767
|
+
* // => true
|
1768
|
+
*
|
1769
|
+
* _.isArguments([1, 2, 3]);
|
1770
|
+
* // => false
|
1771
|
+
*/
|
1772
|
+
var isArguments = function isArguments(value) {
|
1773
|
+
return toString.call(value) == '[object Arguments]';
|
1774
|
+
};
|
1775
|
+
// fallback for browser like IE<9 which detect `arguments` as `[object Object]`
|
1776
|
+
if (!isArguments(arguments)) {
|
1777
|
+
isArguments = function isArguments(value) {
|
1778
|
+
return !!(value && hasOwnProperty.call(value, 'callee'));
|
1779
|
+
};
|
1780
|
+
}
|
1781
|
+
|
1782
|
+
/**
|
1783
|
+
* Checks if a `value` is a boolean (`true` or `false`) value.
|
1784
|
+
*
|
1785
|
+
* @static
|
1786
|
+
* @memberOf _
|
1787
|
+
* @category Objects
|
1788
|
+
* @param {Mixed} value The value to check.
|
1789
|
+
* @returns {Boolean} Returns `true` if the `value` is a boolean value, else `false`.
|
1790
|
+
* @example
|
1791
|
+
*
|
1792
|
+
* _.isBoolean(null);
|
1793
|
+
* // => false
|
1794
|
+
*/
|
1795
|
+
function isBoolean(value) {
|
1796
|
+
return value === true || value === false || toString.call(value) == boolClass;
|
1797
|
+
}
|
1798
|
+
|
1799
|
+
/**
|
1800
|
+
* Checks if a `value` is a date.
|
1801
|
+
*
|
1802
|
+
* @static
|
1803
|
+
* @memberOf _
|
1804
|
+
* @category Objects
|
1805
|
+
* @param {Mixed} value The value to check.
|
1806
|
+
* @returns {Boolean} Returns `true` if the `value` is a date, else `false`.
|
1807
|
+
* @example
|
1808
|
+
*
|
1809
|
+
* _.isDate(new Date);
|
1810
|
+
* // => true
|
1811
|
+
*/
|
1812
|
+
function isDate(value) {
|
1813
|
+
return toString.call(value) == dateClass;
|
1814
|
+
}
|
1815
|
+
|
1816
|
+
/**
|
1817
|
+
* Checks if a `value` is a DOM element.
|
1818
|
+
*
|
1819
|
+
* @static
|
1820
|
+
* @memberOf _
|
1821
|
+
* @category Objects
|
1822
|
+
* @param {Mixed} value The value to check.
|
1823
|
+
* @returns {Boolean} Returns `true` if the `value` is a DOM element, else `false`.
|
1824
|
+
* @example
|
1825
|
+
*
|
1826
|
+
* _.isElement(document.body);
|
1827
|
+
* // => true
|
1828
|
+
*/
|
1829
|
+
function isElement(value) {
|
1830
|
+
return !!(value && value.nodeType == 1);
|
1831
|
+
}
|
1832
|
+
|
1833
|
+
/**
|
1834
|
+
* Performs a deep comparison between two values to determine if they are
|
1835
|
+
* equivalent to each other.
|
1836
|
+
*
|
1837
|
+
* @static
|
1838
|
+
* @memberOf _
|
1839
|
+
* @category Objects
|
1840
|
+
* @param {Mixed} a The value to compare.
|
1841
|
+
* @param {Mixed} b The other value to compare.
|
1842
|
+
* @param {Array} [stack] Internally used to keep track of "seen" objects to
|
1843
|
+
* avoid circular references.
|
1844
|
+
* @returns {Boolean} Returns `true` if the values are equvalent, else `false`.
|
1845
|
+
* @example
|
1846
|
+
*
|
1847
|
+
* var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] };
|
1848
|
+
* var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] };
|
1849
|
+
*
|
1850
|
+
* moe == clone;
|
1851
|
+
* // => false
|
1852
|
+
*
|
1853
|
+
* _.isEqual(moe, clone);
|
1854
|
+
* // => true
|
1855
|
+
*/
|
1856
|
+
function isEqual(a, b, stack) {
|
1857
|
+
stack || (stack = []);
|
1858
|
+
|
1859
|
+
// exit early for identical values
|
1860
|
+
if (a === b) {
|
1861
|
+
// treat `+0` vs. `-0` as not equal
|
1862
|
+
return a !== 0 || (1 / a == 1 / b);
|
1863
|
+
}
|
1864
|
+
// a strict comparison is necessary because `null == undefined`
|
1865
|
+
if (a == undefined || b == undefined) {
|
1866
|
+
return a === b;
|
1867
|
+
}
|
1868
|
+
// unwrap any wrapped objects
|
1869
|
+
if (a._chain) {
|
1870
|
+
a = a._wrapped;
|
1871
|
+
}
|
1872
|
+
if (b._chain) {
|
1873
|
+
b = b._wrapped;
|
1874
|
+
}
|
1875
|
+
// invoke a custom `isEqual` method if one is provided
|
1876
|
+
if (a.isEqual && isFunction(a.isEqual)) {
|
1877
|
+
return a.isEqual(b);
|
1878
|
+
}
|
1879
|
+
if (b.isEqual && isFunction(b.isEqual)) {
|
1880
|
+
return b.isEqual(a);
|
1881
|
+
}
|
1882
|
+
// compare [[Class]] names
|
1883
|
+
var className = toString.call(a);
|
1884
|
+
if (className != toString.call(b)) {
|
1885
|
+
return false;
|
1886
|
+
}
|
1887
|
+
switch (className) {
|
1888
|
+
// strings, numbers, dates, and booleans are compared by value
|
1889
|
+
case stringClass:
|
1890
|
+
// primitives and their corresponding object instances are equivalent;
|
1891
|
+
// thus, `'5'` is quivalent to `new String('5')`
|
1892
|
+
return a == String(b);
|
1893
|
+
|
1894
|
+
case numberClass:
|
1895
|
+
// treat `NaN` vs. `NaN` as equal
|
1896
|
+
return a != +a
|
1897
|
+
? b != +b
|
1898
|
+
// but treat `+0` vs. `-0` as not equal
|
1899
|
+
: (a == 0 ? (1 / a == 1 / b) : a == +b);
|
1900
|
+
|
1901
|
+
case boolClass:
|
1902
|
+
case dateClass:
|
1903
|
+
// coerce dates and booleans to numeric values, dates to milliseconds and booleans to 1 or 0;
|
1904
|
+
// treat invalid dates coerced to `NaN` as not equal
|
1905
|
+
return +a == +b;
|
1906
|
+
|
1907
|
+
// regexps are compared by their source and flags
|
1908
|
+
case regexpClass:
|
1909
|
+
return a.source == b.source &&
|
1910
|
+
a.global == b.global &&
|
1911
|
+
a.multiline == b.multiline &&
|
1912
|
+
a.ignoreCase == b.ignoreCase;
|
1913
|
+
}
|
1914
|
+
if (typeof a != 'object' || typeof b != 'object') {
|
1915
|
+
return false;
|
1916
|
+
}
|
1917
|
+
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
1918
|
+
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
1919
|
+
var length = stack.length;
|
1920
|
+
while (length--) {
|
1921
|
+
// Linear search. Performance is inversely proportional to the number of
|
1922
|
+
// unique nested structures.
|
1923
|
+
if (stack[length] == a) {
|
1924
|
+
return true;
|
1925
|
+
}
|
1926
|
+
}
|
1927
|
+
|
1928
|
+
var result = true,
|
1929
|
+
size = 0;
|
1930
|
+
|
1931
|
+
// add the first collection to the stack of traversed objects
|
1932
|
+
stack.push(a);
|
1933
|
+
|
1934
|
+
// recursively compare objects and arrays
|
1935
|
+
if (className == arrayClass) {
|
1936
|
+
// compare array lengths to determine if a deep comparison is necessary
|
1937
|
+
size = a.length;
|
1938
|
+
result = size == b.length;
|
1939
|
+
|
1940
|
+
if (result) {
|
1941
|
+
// deep compare the contents, ignoring non-numeric properties
|
1942
|
+
while (size--) {
|
1943
|
+
// ensure commutative equality for sparse arrays
|
1944
|
+
if (!(result = size in a == size in b && isEqual(a[size], b[size], stack))) {
|
1945
|
+
break;
|
1946
|
+
}
|
1947
|
+
}
|
1948
|
+
}
|
1949
|
+
} else {
|
1950
|
+
// objects with different constructors are not equivalent
|
1951
|
+
if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) {
|
1952
|
+
return false;
|
1953
|
+
}
|
1954
|
+
// deep compare objects
|
1955
|
+
for (var prop in a) {
|
1956
|
+
if (hasOwnProperty.call(a, prop)) {
|
1957
|
+
// count the expected number of properties
|
1958
|
+
size++;
|
1959
|
+
// deep compare each member
|
1960
|
+
if (!(result = hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stack))) {
|
1961
|
+
break;
|
1962
|
+
}
|
1963
|
+
}
|
1964
|
+
}
|
1965
|
+
// ensure that both objects contain the same number of properties
|
1966
|
+
if (result) {
|
1967
|
+
for (prop in b) {
|
1968
|
+
if (hasOwnProperty.call(b, prop) && !(size--)) {
|
1969
|
+
break;
|
1970
|
+
}
|
1971
|
+
}
|
1972
|
+
result = !size;
|
1973
|
+
}
|
1974
|
+
}
|
1975
|
+
// remove the first collection from the stack of traversed objects
|
1976
|
+
stack.pop();
|
1977
|
+
return result;
|
1978
|
+
}
|
1979
|
+
|
1980
|
+
/**
|
1981
|
+
* Checks if a `value` is a finite number.
|
1982
|
+
*
|
1983
|
+
* @static
|
1984
|
+
* @memberOf _
|
1985
|
+
* @category Objects
|
1986
|
+
* @param {Mixed} value The value to check.
|
1987
|
+
* @returns {Boolean} Returns `true` if the `value` is a finite number, else `false`.
|
1988
|
+
* @example
|
1989
|
+
*
|
1990
|
+
* _.isFinite(-101);
|
1991
|
+
* // => true
|
1992
|
+
*
|
1993
|
+
* _.isFinite('10');
|
1994
|
+
* // => false
|
1995
|
+
*
|
1996
|
+
* _.isFinite(Infinity);
|
1997
|
+
* // => false
|
1998
|
+
*/
|
1999
|
+
function isFinite(value) {
|
2000
|
+
return nativeIsFinite(value) && toString.call(value) == numberClass;
|
2001
|
+
}
|
2002
|
+
|
2003
|
+
/**
|
2004
|
+
* Checks if a `value` is a function.
|
2005
|
+
*
|
2006
|
+
* @static
|
2007
|
+
* @memberOf _
|
2008
|
+
* @category Objects
|
2009
|
+
* @param {Mixed} value The value to check.
|
2010
|
+
* @returns {Boolean} Returns `true` if the `value` is a function, else `false`.
|
2011
|
+
* @example
|
2012
|
+
*
|
2013
|
+
* _.isFunction(''.concat);
|
2014
|
+
* // => true
|
2015
|
+
*/
|
2016
|
+
function isFunction(value) {
|
2017
|
+
return toString.call(value) == funcClass;
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
/**
|
2021
|
+
* Checks if a `value` is an object.
|
2022
|
+
*
|
2023
|
+
* @static
|
2024
|
+
* @memberOf _
|
2025
|
+
* @category Objects
|
2026
|
+
* @param {Mixed} value The value to check.
|
2027
|
+
* @returns {Boolean} Returns `true` if the `value` is an object, else `false`.
|
2028
|
+
* @example
|
2029
|
+
*
|
2030
|
+
* _.isObject({});
|
2031
|
+
* // => true
|
2032
|
+
*
|
2033
|
+
* _.isObject(1);
|
2034
|
+
* // => false
|
2035
|
+
*/
|
2036
|
+
function isObject(value) {
|
2037
|
+
return value === Object(value);
|
2038
|
+
}
|
2039
|
+
|
2040
|
+
/**
|
2041
|
+
* Checks if a `value` is `NaN`.
|
2042
|
+
* Note: this is not the same as native `isNaN`, which will return true for
|
2043
|
+
* `undefined` and other values. See http://es5.github.com/#x15.1.2.4.
|
2044
|
+
*
|
2045
|
+
* @static
|
2046
|
+
* @memberOf _
|
2047
|
+
* @category Objects
|
2048
|
+
* @param {Mixed} value The value to check.
|
2049
|
+
* @returns {Boolean} Returns `true` if the `value` is `NaN`, else `false`.
|
2050
|
+
* @example
|
2051
|
+
*
|
2052
|
+
* _.isNaN(NaN);
|
2053
|
+
* // => true
|
2054
|
+
*
|
2055
|
+
* _.isNaN(new Number(NaN));
|
2056
|
+
* // => true
|
2057
|
+
*
|
2058
|
+
* isNaN(undefined);
|
2059
|
+
* // => true
|
2060
|
+
*
|
2061
|
+
* _.isNaN(undefined);
|
2062
|
+
* // => false
|
2063
|
+
*/
|
2064
|
+
function isNaN(value) {
|
2065
|
+
// `NaN` as a primitive is the only value that is not equal to itself
|
2066
|
+
// (perform the [[Class]] check first to avoid errors with some host objects in IE)
|
2067
|
+
return toString.call(value) == numberClass && value != +value
|
2068
|
+
}
|
2069
|
+
|
2070
|
+
/**
|
2071
|
+
* Checks if a `value` is `null`.
|
2072
|
+
*
|
2073
|
+
* @static
|
2074
|
+
* @memberOf _
|
2075
|
+
* @category Objects
|
2076
|
+
* @param {Mixed} value The value to check.
|
2077
|
+
* @returns {Boolean} Returns `true` if the `value` is `null`, else `false`.
|
2078
|
+
* @example
|
2079
|
+
*
|
2080
|
+
* _.isNull(null);
|
2081
|
+
* // => true
|
2082
|
+
*
|
2083
|
+
* _.isNull(undefined);
|
2084
|
+
* // => false
|
2085
|
+
*/
|
2086
|
+
function isNull(value) {
|
2087
|
+
return value === null;
|
2088
|
+
}
|
2089
|
+
|
2090
|
+
/**
|
2091
|
+
* Checks if a `value` is a number.
|
2092
|
+
*
|
2093
|
+
* @static
|
2094
|
+
* @memberOf _
|
2095
|
+
* @category Objects
|
2096
|
+
* @param {Mixed} value The value to check.
|
2097
|
+
* @returns {Boolean} Returns `true` if the `value` is a number, else `false`.
|
2098
|
+
* @example
|
2099
|
+
*
|
2100
|
+
* _.isNumber(8.4 * 5;
|
2101
|
+
* // => true
|
2102
|
+
*/
|
2103
|
+
function isNumber(value) {
|
2104
|
+
return toString.call(value) == numberClass;
|
2105
|
+
}
|
2106
|
+
|
2107
|
+
/**
|
2108
|
+
* Checks if a `value` is a regular expression.
|
2109
|
+
*
|
2110
|
+
* @static
|
2111
|
+
* @memberOf _
|
2112
|
+
* @category Objects
|
2113
|
+
* @param {Mixed} value The value to check.
|
2114
|
+
* @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`.
|
2115
|
+
* @example
|
2116
|
+
*
|
2117
|
+
* _.isRegExp(/moe/);
|
2118
|
+
* // => true
|
2119
|
+
*/
|
2120
|
+
function isRegExp(value) {
|
2121
|
+
return toString.call(value) == regexpClass;
|
2122
|
+
}
|
2123
|
+
|
2124
|
+
/**
|
2125
|
+
* Checks if a `value` is a string.
|
2126
|
+
*
|
2127
|
+
* @static
|
2128
|
+
* @memberOf _
|
2129
|
+
* @category Objects
|
2130
|
+
* @param {Mixed} value The value to check.
|
2131
|
+
* @returns {Boolean} Returns `true` if the `value` is a string, else `false`.
|
2132
|
+
* @example
|
2133
|
+
*
|
2134
|
+
* _.isString('moe');
|
2135
|
+
* // => true
|
2136
|
+
*/
|
2137
|
+
function isString(value) {
|
2138
|
+
return toString.call(value) == stringClass;
|
2139
|
+
}
|
2140
|
+
|
2141
|
+
/**
|
2142
|
+
* Checks if a `value` is `undefined`.
|
2143
|
+
*
|
2144
|
+
* @static
|
2145
|
+
* @memberOf _
|
2146
|
+
* @category Objects
|
2147
|
+
* @param {Mixed} value The value to check.
|
2148
|
+
* @returns {Boolean} Returns `true` if the `value` is `undefined`, else `false`.
|
2149
|
+
* @example
|
2150
|
+
*
|
2151
|
+
* _.isUndefined(void 0);
|
2152
|
+
* // => true
|
2153
|
+
*/
|
2154
|
+
function isUndefined(value) {
|
2155
|
+
return value === undefined;
|
2156
|
+
}
|
2157
|
+
|
2158
|
+
/**
|
2159
|
+
* Produces an array of the `object`'s enumerable own property names.
|
2160
|
+
*
|
2161
|
+
* @static
|
2162
|
+
* @memberOf _
|
2163
|
+
* @category Objects
|
2164
|
+
* @param {Object} object The object to inspect.
|
2165
|
+
* @returns {Array} Returns a new array of property names.
|
2166
|
+
* @example
|
2167
|
+
*
|
2168
|
+
* _.keys({ 'one': 1, 'two': 2, 'three': 3 });
|
2169
|
+
* // => ['one', 'two', 'three']
|
2170
|
+
*/
|
2171
|
+
var keys = nativeKeys || iterationFactory(keysFactoryOptions);
|
2172
|
+
|
2173
|
+
/**
|
2174
|
+
* Creates an object composed of the specified properties. Property names may
|
2175
|
+
* be specified as individual arguments or as arrays of property names.
|
2176
|
+
*
|
2177
|
+
* @static
|
2178
|
+
* @memberOf _
|
2179
|
+
* @category Objects
|
2180
|
+
* @param {Object} object The object to pluck.
|
2181
|
+
* @param {Object} [prop1, prop2, ..] The properties to pick.
|
2182
|
+
* @returns {Object} Returns an object composed of the picked properties.
|
2183
|
+
* @example
|
2184
|
+
*
|
2185
|
+
* _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age');
|
2186
|
+
* // => { 'name': 'moe', 'age': 40 }
|
2187
|
+
*/
|
2188
|
+
function pick(object) {
|
2189
|
+
var prop,
|
2190
|
+
index = -1,
|
2191
|
+
props = flatten(slice.call(arguments, 1)),
|
2192
|
+
length = props.length,
|
2193
|
+
result = {};
|
2194
|
+
|
2195
|
+
while (++index < length) {
|
2196
|
+
prop = props[index];
|
2197
|
+
if (prop in object) {
|
2198
|
+
result[prop] = object[prop];
|
2199
|
+
}
|
2200
|
+
}
|
2201
|
+
return result;
|
2202
|
+
}
|
2203
|
+
|
2204
|
+
/**
|
2205
|
+
* Invokes `interceptor` with the `value` as the first argument, and then returns
|
2206
|
+
* `value`. The primary purpose of this method is to "tap into" a method chain,
|
2207
|
+
* in order to performoperations on intermediate results within the chain.
|
2208
|
+
*
|
2209
|
+
* @static
|
2210
|
+
* @memberOf _
|
2211
|
+
* @category Objects
|
2212
|
+
* @param {Mixed} value The value to pass to `callback`.
|
2213
|
+
* @param {Function} interceptor The function to invoke.
|
2214
|
+
* @returns {Mixed} Returns `value`.
|
2215
|
+
* @example
|
2216
|
+
*
|
2217
|
+
* _.chain([1,2,3,200])
|
2218
|
+
* .filter(function(num) { return num % 2 == 0; })
|
2219
|
+
* .tap(alert)
|
2220
|
+
* .map(function(num) { return num * num })
|
2221
|
+
* .value();
|
2222
|
+
* // => // [2, 200] (alerted)
|
2223
|
+
* // => [4, 40000]
|
2224
|
+
*/
|
2225
|
+
function tap(value, interceptor) {
|
2226
|
+
interceptor(value);
|
2227
|
+
return value;
|
2228
|
+
}
|
2229
|
+
|
2230
|
+
/*--------------------------------------------------------------------------*/
|
2231
|
+
|
2232
|
+
/**
|
2233
|
+
* Escapes a string for insertion into HTML, replacing `&`, `<`, `>`, `"`, `'`,
|
2234
|
+
* and `/` characters.
|
2235
|
+
*
|
2236
|
+
* @static
|
2237
|
+
* @memberOf _
|
2238
|
+
* @category Utilities
|
2239
|
+
* @param {String} string The string to escape.
|
2240
|
+
* @returns {String} Returns the escaped string.
|
2241
|
+
* @example
|
2242
|
+
*
|
2243
|
+
* _.escape('Curly, Larry & Moe');
|
2244
|
+
* // => "Curly, Larry & Moe"
|
2245
|
+
*/
|
2246
|
+
function escape(string) {
|
2247
|
+
return (string + '')
|
2248
|
+
.replace(/&/g, '&')
|
2249
|
+
.replace(/</g, '<')
|
2250
|
+
.replace(/>/g, '>')
|
2251
|
+
.replace(/"/g, '"')
|
2252
|
+
.replace(/'/g, ''')
|
2253
|
+
.replace(/\//g,'/');
|
2254
|
+
}
|
2255
|
+
|
2256
|
+
/**
|
2257
|
+
* This function simply returns the first argument passed to it.
|
2258
|
+
* Note: It is used throughout Lo-Dash as a default callback.
|
2259
|
+
*
|
2260
|
+
* @static
|
2261
|
+
* @memberOf _
|
2262
|
+
* @category Utilities
|
2263
|
+
* @param {Mixed} value Any value.
|
2264
|
+
* @returns {Mixed} Returns `value`.
|
2265
|
+
* @example
|
2266
|
+
*
|
2267
|
+
* var moe = { 'name': 'moe' };
|
2268
|
+
* moe === _.identity(moe);
|
2269
|
+
* // => true
|
2270
|
+
*/
|
2271
|
+
function identity(value) {
|
2272
|
+
return value;
|
2273
|
+
}
|
2274
|
+
|
2275
|
+
/**
|
2276
|
+
* Adds functions properties of `object` to the `lodash` function and chainable
|
2277
|
+
* wrapper.
|
2278
|
+
*
|
2279
|
+
* @static
|
2280
|
+
* @memberOf _
|
2281
|
+
* @category Utilities
|
2282
|
+
* @param {Object} object The object of function properties to add to `lodash`.
|
2283
|
+
* @example
|
2284
|
+
*
|
2285
|
+
* _.mixin({
|
2286
|
+
* 'capitalize': function(string) {
|
2287
|
+
* return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
2288
|
+
* }
|
2289
|
+
* });
|
2290
|
+
*
|
2291
|
+
* _.capitalize('curly');
|
2292
|
+
* // => 'Curly'
|
2293
|
+
*
|
2294
|
+
* _('larry').capitalize();
|
2295
|
+
* // => 'Larry'
|
2296
|
+
*/
|
2297
|
+
function mixin(object) {
|
2298
|
+
forEach(functions(object), function(methodName) {
|
2299
|
+
var func = lodash[methodName] = object[methodName];
|
2300
|
+
|
2301
|
+
lodash.prototype[methodName] = function() {
|
2302
|
+
// In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()`
|
2303
|
+
// generically to augment the `arguments` object will pave the value at
|
2304
|
+
// index `0` without incrimenting the other values's indexes.
|
2305
|
+
// https://github.com/documentcloud/underscore/issues/9
|
2306
|
+
var args = slice.call(arguments);
|
2307
|
+
unshift.call(args, this._wrapped);
|
2308
|
+
|
2309
|
+
var result = func.apply(lodash, args);
|
2310
|
+
return this._chain ? new Lodash(result).chain() : result;
|
2311
|
+
};
|
2312
|
+
});
|
2313
|
+
}
|
2314
|
+
|
2315
|
+
/**
|
2316
|
+
* Reverts the '_' variable to its previous value and returns a reference to
|
2317
|
+
* the `lodash` function.
|
2318
|
+
*
|
2319
|
+
* @static
|
2320
|
+
* @memberOf _
|
2321
|
+
* @category Utilities
|
2322
|
+
* @returns {Function} Returns the `lodash` function.
|
2323
|
+
* @example
|
2324
|
+
*
|
2325
|
+
* var lodash = _.noConflict();
|
2326
|
+
*/
|
2327
|
+
function noConflict() {
|
2328
|
+
window._ = oldDash;
|
2329
|
+
return this;
|
2330
|
+
}
|
2331
|
+
|
2332
|
+
/**
|
2333
|
+
* Resolves the value of `property` on `object`. If the property is a function
|
2334
|
+
* it will be invoked and its result returned, else the property value is returned.
|
2335
|
+
*
|
2336
|
+
* @static
|
2337
|
+
* @memberOf _
|
2338
|
+
* @category Utilities
|
2339
|
+
* @param {Object} object The object to inspect.
|
2340
|
+
* @param {String} property The property to get the result of.
|
2341
|
+
* @returns {Mixed} Returns the resolved.
|
2342
|
+
* @example
|
2343
|
+
*
|
2344
|
+
* var object = {
|
2345
|
+
* 'cheese': 'crumpets',
|
2346
|
+
* 'stuff': function() {
|
2347
|
+
* return 'nonsense';
|
2348
|
+
* }
|
2349
|
+
* };
|
2350
|
+
*
|
2351
|
+
* _.result(object, 'cheese');
|
2352
|
+
* // => 'crumpets'
|
2353
|
+
*
|
2354
|
+
* _.result(object, 'stuff');
|
2355
|
+
* // => 'nonsense'
|
2356
|
+
*/
|
2357
|
+
function result(object, property) {
|
2358
|
+
if (object == undefined) {
|
2359
|
+
return null;
|
2360
|
+
}
|
2361
|
+
var value = object[property];
|
2362
|
+
return isFunction(value) ? object[property]() : value;
|
2363
|
+
}
|
2364
|
+
|
2365
|
+
/**
|
2366
|
+
* Executes the `callback` function `n` times.
|
2367
|
+
*
|
2368
|
+
* @static
|
2369
|
+
* @memberOf _
|
2370
|
+
* @category Utilities
|
2371
|
+
* @param {Number} n The number of times to execute the callback.
|
2372
|
+
* @param {Function} callback The function called per iteration.
|
2373
|
+
* @param {Mixed} [thisArg] The `this` binding for the callback.
|
2374
|
+
* @example
|
2375
|
+
*
|
2376
|
+
* _.times(3, function() { genie.grantWish(); });
|
2377
|
+
*/
|
2378
|
+
function times(n, callback, thisArg) {
|
2379
|
+
if (thisArg) {
|
2380
|
+
callback = bind(callback, thisArg);
|
2381
|
+
}
|
2382
|
+
for (var index = 0; index < n; index++) {
|
2383
|
+
callback(index);
|
2384
|
+
}
|
2385
|
+
}
|
2386
|
+
|
2387
|
+
/**
|
2388
|
+
* Generates a unique id. If `prefix` is passed, the id will be appended to it.
|
2389
|
+
*
|
2390
|
+
* @static
|
2391
|
+
* @memberOf _
|
2392
|
+
* @category Utilities
|
2393
|
+
* @param {String} [prefix] The value to prefix the id with.
|
2394
|
+
* @returns {Number|String} Returns a numeric id if no prefix is passed, else
|
2395
|
+
* a string id may be returned.
|
2396
|
+
* @example
|
2397
|
+
*
|
2398
|
+
* _.uniqueId('contact_');
|
2399
|
+
* // => 'contact_104'
|
2400
|
+
*/
|
2401
|
+
function uniqueId(prefix) {
|
2402
|
+
var id = idCounter++;
|
2403
|
+
return prefix ? prefix + id : id;
|
2404
|
+
}
|
2405
|
+
|
2406
|
+
/*--------------------------------------------------------------------------*/
|
2407
|
+
|
2408
|
+
/**
|
2409
|
+
* A JavaScript micro-templating method, similar to John Resig's implementation.
|
2410
|
+
* Lo-Dash templating handles arbitrary delimiters, preserves whitespace, and
|
2411
|
+
* correctly escapes quotes within interpolated code.
|
2412
|
+
*
|
2413
|
+
* @static
|
2414
|
+
* @memberOf _
|
2415
|
+
* @category Utilities
|
2416
|
+
* @param {String} text The template text.
|
2417
|
+
* @param {Obect} data The data object used to populate the text.
|
2418
|
+
* @param {Object} options The options object.
|
2419
|
+
* @returns {Function|String} Returns a compiled function when no `data` object
|
2420
|
+
* is given, else it returns the interpolated text.
|
2421
|
+
* @example
|
2422
|
+
*
|
2423
|
+
* // using compiled template
|
2424
|
+
* var compiled = _.template('hello: <%= name %>');
|
2425
|
+
* compiled({ 'name': 'moe' });
|
2426
|
+
* // => 'hello: moe'
|
2427
|
+
*
|
2428
|
+
* var list = '% _.forEach(people, function(name) { %> <li><%= name %></li> <% }); %>';
|
2429
|
+
* _.template(list, { 'people': ['moe', 'curly', 'larry'] });
|
2430
|
+
* // => '<li>moe</li><li>curly</li><li>larry</li>'
|
2431
|
+
*
|
2432
|
+
* var template = _.template('<b><%- value %></b>');
|
2433
|
+
* template({ 'value': '<script>' });
|
2434
|
+
* // => '<b><script></b>'
|
2435
|
+
*
|
2436
|
+
* // using `print`
|
2437
|
+
* var compiled = _.template('<% print("Hello " + epithet); %>');
|
2438
|
+
* compiled({ 'epithet': 'stooge' });
|
2439
|
+
* // => 'Hello stooge.'
|
2440
|
+
*
|
2441
|
+
* // using custom template settings
|
2442
|
+
* _.templateSettings = {
|
2443
|
+
* 'interpolate': /\{\{(.+?)\}\}/g
|
2444
|
+
* };
|
2445
|
+
*
|
2446
|
+
* var template = _.template('Hello {{ name }}!');
|
2447
|
+
* template({ 'name': 'Mustache' });
|
2448
|
+
* // => 'Hello Mustache!'
|
2449
|
+
*
|
2450
|
+
*
|
2451
|
+
* // using the `variable` option
|
2452
|
+
* _.template('<%= data.hasWith %>', { 'hasWith': 'no' }, { 'variable': 'data' });
|
2453
|
+
* // => 'no'
|
2454
|
+
*
|
2455
|
+
* // using the `source` property
|
2456
|
+
* <script>
|
2457
|
+
* JST.project = <%= _.template(jstText).source %>;
|
2458
|
+
* </script>
|
2459
|
+
*/
|
2460
|
+
function template(text, data, options) {
|
2461
|
+
options = defaults(options || {}, lodash.templateSettings);
|
2462
|
+
|
2463
|
+
// Compile the template source, taking care to escape characters that
|
2464
|
+
// cannot be included in string literals and then unescape them in code
|
2465
|
+
// blocks.
|
2466
|
+
var source = "__p+='" + text
|
2467
|
+
.replace(reEscaper, function(match) {
|
2468
|
+
return '\\' + escapes[match];
|
2469
|
+
})
|
2470
|
+
.replace(options.escape || reNoMatch, function(match, code) {
|
2471
|
+
return "'+\n((__t=(" + unescape(code) + "))==null?'':_.escape(__t))+\n'";
|
2472
|
+
})
|
2473
|
+
.replace(options.interpolate || reNoMatch, function(match, code) {
|
2474
|
+
return "'+\n((__t=(" + unescape(code) + "))==null?'':__t)+\n'";
|
2475
|
+
})
|
2476
|
+
.replace(options.evaluate || reNoMatch, function(match, code) {
|
2477
|
+
return "';\n" + unescape(code) + ";\n__p+='";
|
2478
|
+
}) + "';\n";
|
2479
|
+
|
2480
|
+
// if a variable is not specified, place data values in local scope
|
2481
|
+
if (!options.variable) {
|
2482
|
+
source = 'with(object||{}){\n' + source + '\n}\n';
|
2483
|
+
}
|
2484
|
+
|
2485
|
+
source = 'var __t,__j=Array.prototype.join,__p="";' +
|
2486
|
+
'function print(){__p+=__j.call(arguments,"")}\n' +
|
2487
|
+
source + 'return __p';
|
2488
|
+
|
2489
|
+
var render = Function(options.variable || 'object', '_', source);
|
2490
|
+
if (data) {
|
2491
|
+
return render(data, lodash);
|
2492
|
+
}
|
2493
|
+
|
2494
|
+
var template = function(data) {
|
2495
|
+
return render.call(this, data, lodash);
|
2496
|
+
};
|
2497
|
+
|
2498
|
+
// provide the compiled function source as a convenience for build time precompilation
|
2499
|
+
template.source = 'function(' + (options.variable || 'object') + '){\n' + source + '\n}';
|
2500
|
+
|
2501
|
+
return template;
|
2502
|
+
}
|
2503
|
+
|
2504
|
+
/*--------------------------------------------------------------------------*/
|
2505
|
+
|
2506
|
+
/**
|
2507
|
+
* Wraps the value in a `lodash` chainable object.
|
2508
|
+
*
|
2509
|
+
* @static
|
2510
|
+
* @memberOf _
|
2511
|
+
* @category Chaining
|
2512
|
+
* @param {Mixed} value The value to wrap.
|
2513
|
+
* @returns {Object} Returns the `lodash` chainable object.
|
2514
|
+
* @example
|
2515
|
+
*
|
2516
|
+
* var stooges = [
|
2517
|
+
* { 'name': 'moe', 'age': 40 },
|
2518
|
+
* { 'name': 'larry', 'age': 50 },
|
2519
|
+
* { 'name': 'curly', 'age': 60 }
|
2520
|
+
* ];
|
2521
|
+
*
|
2522
|
+
* var youngest = _.chain(stooges)
|
2523
|
+
* .sortBy(function(stooge) { return stooge.age; })
|
2524
|
+
* .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })
|
2525
|
+
* .first()
|
2526
|
+
* .value();
|
2527
|
+
* // => 'moe is 40'
|
2528
|
+
*/
|
2529
|
+
function chain(value) {
|
2530
|
+
return new Lodash(value).chain();
|
2531
|
+
}
|
2532
|
+
|
2533
|
+
/**
|
2534
|
+
* Extracts the value from a wrapped chainable object.
|
2535
|
+
*
|
2536
|
+
* @name chain
|
2537
|
+
* @memberOf _
|
2538
|
+
* @category Chaining
|
2539
|
+
* @returns {Mixed} Returns the wrapped object.
|
2540
|
+
* @example
|
2541
|
+
*
|
2542
|
+
* _([1, 2, 3]).value();
|
2543
|
+
* // => [1, 2, 3]
|
2544
|
+
*/
|
2545
|
+
function chainWrapper() {
|
2546
|
+
this._chain = true;
|
2547
|
+
return this;
|
2548
|
+
}
|
2549
|
+
|
2550
|
+
/**
|
2551
|
+
* Extracts the value from a wrapped chainable object.
|
2552
|
+
*
|
2553
|
+
* @memberOf _
|
2554
|
+
* @category Chaining
|
2555
|
+
* @returns {Mixed} Returns the wrapped object.
|
2556
|
+
* @example
|
2557
|
+
*
|
2558
|
+
* _([1, 2, 3]).value();
|
2559
|
+
* // => [1, 2, 3]
|
2560
|
+
*/
|
2561
|
+
function value() {
|
2562
|
+
return this._wrapped;
|
2563
|
+
}
|
2564
|
+
|
2565
|
+
/*--------------------------------------------------------------------------*/
|
2566
|
+
|
2567
|
+
extend(lodash, {
|
2568
|
+
|
2569
|
+
/**
|
2570
|
+
* The semantic version number.
|
2571
|
+
*
|
2572
|
+
* @static
|
2573
|
+
* @memberOf _
|
2574
|
+
* @type String
|
2575
|
+
*/
|
2576
|
+
'VERSION': '0.1.0',
|
2577
|
+
|
2578
|
+
/**
|
2579
|
+
* By default, Lo-Dash uses ERB-style template delimiters, change the
|
2580
|
+
* following template settings to use alternative delimiters.
|
2581
|
+
*
|
2582
|
+
* @static
|
2583
|
+
* @memberOf _
|
2584
|
+
* @type Object
|
2585
|
+
*/
|
2586
|
+
'templateSettings': {
|
2587
|
+
|
2588
|
+
/**
|
2589
|
+
* Used to detect `data` property values to be HTML-escaped.
|
2590
|
+
*
|
2591
|
+
* @static
|
2592
|
+
* @memberOf _.templateSettings
|
2593
|
+
* @type RegExp
|
2594
|
+
*/
|
2595
|
+
'escape': /<%-([\s\S]+?)%>/g,
|
2596
|
+
|
2597
|
+
/**
|
2598
|
+
* Used to detect code to be evaluated.
|
2599
|
+
*
|
2600
|
+
* @static
|
2601
|
+
* @memberOf _.templateSettings
|
2602
|
+
* @type RegExp
|
2603
|
+
*/
|
2604
|
+
'evaluate': /<%([\s\S]+?)%>/g,
|
2605
|
+
|
2606
|
+
/**
|
2607
|
+
* Used to detect `data` property values to inject.
|
2608
|
+
*
|
2609
|
+
* @static
|
2610
|
+
* @memberOf _.templateSettings
|
2611
|
+
* @type RegExp
|
2612
|
+
*/
|
2613
|
+
'interpolate': /<%=([\s\S]+?)%>/g
|
2614
|
+
},
|
2615
|
+
|
2616
|
+
// assign static methods
|
2617
|
+
'after': after,
|
2618
|
+
'bind': bind,
|
2619
|
+
'bindAll': bindAll,
|
2620
|
+
'chain': chain,
|
2621
|
+
'clone': clone,
|
2622
|
+
'compact': compact,
|
2623
|
+
'compose': compose,
|
2624
|
+
'contains': contains,
|
2625
|
+
'debounce': debounce,
|
2626
|
+
'defaults': defaults,
|
2627
|
+
'defer': defer,
|
2628
|
+
'delay': delay,
|
2629
|
+
'difference': difference,
|
2630
|
+
'escape': escape,
|
2631
|
+
'every': every,
|
2632
|
+
'extend': extend,
|
2633
|
+
'filter': filter,
|
2634
|
+
'find': find,
|
2635
|
+
'first': first,
|
2636
|
+
'flatten': flatten,
|
2637
|
+
'forEach': forEach,
|
2638
|
+
'functions': functions,
|
2639
|
+
'groupBy': groupBy,
|
2640
|
+
'has': has,
|
2641
|
+
'identity': identity,
|
2642
|
+
'indexOf': indexOf,
|
2643
|
+
'initial': initial,
|
2644
|
+
'intersection': intersection,
|
2645
|
+
'invoke': invoke,
|
2646
|
+
'isArguments': isArguments,
|
2647
|
+
'isArray': isArray,
|
2648
|
+
'isBoolean': isBoolean,
|
2649
|
+
'isDate': isDate,
|
2650
|
+
'isElement': isElement,
|
2651
|
+
'isEmpty': isEmpty,
|
2652
|
+
'isEqual': isEqual,
|
2653
|
+
'isFinite': isFinite,
|
2654
|
+
'isFunction': isFunction,
|
2655
|
+
'isNaN': isNaN,
|
2656
|
+
'isNull': isNull,
|
2657
|
+
'isNumber': isNumber,
|
2658
|
+
'isObject': isObject,
|
2659
|
+
'isRegExp': isRegExp,
|
2660
|
+
'isString': isString,
|
2661
|
+
'isUndefined': isUndefined,
|
2662
|
+
'keys': keys,
|
2663
|
+
'last': last,
|
2664
|
+
'lastIndexOf': lastIndexOf,
|
2665
|
+
'map': map,
|
2666
|
+
'max': max,
|
2667
|
+
'memoize': memoize,
|
2668
|
+
'min': min,
|
2669
|
+
'mixin': mixin,
|
2670
|
+
'noConflict': noConflict,
|
2671
|
+
'once': once,
|
2672
|
+
'pick': pick,
|
2673
|
+
'pluck': pluck,
|
2674
|
+
'range': range,
|
2675
|
+
'reduce': reduce,
|
2676
|
+
'reduceRight': reduceRight,
|
2677
|
+
'reject': reject,
|
2678
|
+
'rest': rest,
|
2679
|
+
'result': result,
|
2680
|
+
'shuffle': shuffle,
|
2681
|
+
'size': size,
|
2682
|
+
'some': some,
|
2683
|
+
'sortBy': sortBy,
|
2684
|
+
'sortedIndex': sortedIndex,
|
2685
|
+
'tap': tap,
|
2686
|
+
'template': template,
|
2687
|
+
'throttle': throttle,
|
2688
|
+
'times': times,
|
2689
|
+
'toArray': toArray,
|
2690
|
+
'union': union,
|
2691
|
+
'uniq': uniq,
|
2692
|
+
'uniqueId': uniqueId,
|
2693
|
+
'values': values,
|
2694
|
+
'without': without,
|
2695
|
+
'wrap': wrap,
|
2696
|
+
'zip': zip,
|
2697
|
+
|
2698
|
+
// assign aliases
|
2699
|
+
'all': every,
|
2700
|
+
'any': some,
|
2701
|
+
'collect': map,
|
2702
|
+
'detect': find,
|
2703
|
+
'each': forEach,
|
2704
|
+
'foldl': reduce,
|
2705
|
+
'foldr': reduceRight,
|
2706
|
+
'head': first,
|
2707
|
+
'include': contains,
|
2708
|
+
'inject': reduce,
|
2709
|
+
'intersect': intersection,
|
2710
|
+
'methods': functions,
|
2711
|
+
'select': filter,
|
2712
|
+
'tail': rest,
|
2713
|
+
'take': first,
|
2714
|
+
'unique': uniq
|
2715
|
+
});
|
2716
|
+
|
2717
|
+
/*--------------------------------------------------------------------------*/
|
2718
|
+
|
2719
|
+
// assign private `Lodash` constructor's prototype
|
2720
|
+
Lodash.prototype = lodash.prototype;
|
2721
|
+
|
2722
|
+
// add all of the static functions to `Lodash.prototype`
|
2723
|
+
mixin(lodash);
|
2724
|
+
|
2725
|
+
// add all mutator Array functions to the wrapper.
|
2726
|
+
forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
|
2727
|
+
var func = ArrayProto[methodName];
|
2728
|
+
|
2729
|
+
lodash.prototype[methodName] = function() {
|
2730
|
+
var value = this._wrapped;
|
2731
|
+
func.apply(value, arguments);
|
2732
|
+
|
2733
|
+
// IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()`
|
2734
|
+
// functions that fail to remove the last element, `object[0]`, of
|
2735
|
+
// array-like-objects even though the `length` property is set to `0`.
|
2736
|
+
// The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
|
2737
|
+
// is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
|
2738
|
+
if (value.length === 0) {
|
2739
|
+
delete value[0];
|
2740
|
+
}
|
2741
|
+
return this._chain ? new Lodash(value).chain() : value;
|
2742
|
+
};
|
2743
|
+
});
|
2744
|
+
|
2745
|
+
// add all accessor Array functions to the wrapper.
|
2746
|
+
forEach(['concat', 'join', 'slice'], function(methodName) {
|
2747
|
+
var func = ArrayProto[methodName];
|
2748
|
+
Lodash.prototype[methodName] = function() {
|
2749
|
+
var result = func.apply(this._wrapped, arguments);
|
2750
|
+
return this._chain ? new Lodash(result).chain() : result;
|
2751
|
+
};
|
2752
|
+
});
|
2753
|
+
|
2754
|
+
// add `chain` and `value` after calling to `mixin()` to avoid getting wrapped
|
2755
|
+
extend(Lodash.prototype, {
|
2756
|
+
'chain': chainWrapper,
|
2757
|
+
'value': value
|
2758
|
+
});
|
2759
|
+
|
2760
|
+
/*--------------------------------------------------------------------------*/
|
2761
|
+
|
2762
|
+
// expose Lo-Dash
|
2763
|
+
if (freeExports) {
|
2764
|
+
// in Node.js or RingoJS v0.8.0+
|
2765
|
+
if (typeof module == 'object' && module && module.exports == freeExports) {
|
2766
|
+
(module.exports = lodash)._ = lodash;
|
2767
|
+
}
|
2768
|
+
// in Narwhal or RingoJS v0.7.0-
|
2769
|
+
else {
|
2770
|
+
freeExports._ = lodash;
|
2771
|
+
}
|
2772
|
+
} else {
|
2773
|
+
// in a browser or Rhino
|
2774
|
+
window._ = lodash;
|
2775
|
+
|
2776
|
+
// Expose Lo-Dash as an AMD module, but only for AMD loaders that understand
|
2777
|
+
// the issues with loading multiple versions of Lo-Dash in a page that all
|
2778
|
+
// might call `define()`. The loader will indicate they have special
|
2779
|
+
// allowances for multiple Lo-Dash versions by specifying
|
2780
|
+
// `define.amd.lodash=true`. Register as a named module, since Lo-Dash can
|
2781
|
+
// be concatenated with other files that may use `define()`, but not use a
|
2782
|
+
// proper concatenation script that understands anonymous AMD modules.
|
2783
|
+
// Lowercase `lodash` is used because AMD module names are derived from
|
2784
|
+
// file names, and Lo-Dash is normally delivered in a lowercase file name.
|
2785
|
+
// Do this after assigning Lo-Dash the global so that if an AMD module wants
|
2786
|
+
// to call `noConflict()` to hide this version of Lo-Dash, it will work.
|
2787
|
+
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd && define.amd.lodash) {
|
2788
|
+
define('lodash', function() {
|
2789
|
+
return lodash;
|
2790
|
+
});
|
2791
|
+
}
|
2792
|
+
}
|
2793
|
+
}(this));
|