underscore-source 0.5.7 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/underscore-source/version.rb +1 -1
- data/vendor/assets/javascripts/underscore.js +131 -89
- metadata +1 -1
@@ -7,7 +7,6 @@
|
|
7
7
|
// http://documentcloud.github.com/underscore
|
8
8
|
|
9
9
|
(function() {
|
10
|
-
|
11
10
|
// ------------------------- Baseline setup ---------------------------------
|
12
11
|
|
13
12
|
// Establish the root object, "window" in the browser, or "global" on the server.
|
@@ -16,44 +15,64 @@
|
|
16
15
|
// Save the previous value of the "_" variable.
|
17
16
|
var previousUnderscore = root._;
|
18
17
|
|
19
|
-
// If Underscore is called as a function, it returns a wrapped object that
|
20
|
-
// can be used OO-style. This wrapper holds altered versions of all the
|
21
|
-
// underscore functions. Wrapped objects may be chained.
|
22
|
-
var wrapper = function(obj) { this._wrapped = obj; };
|
23
|
-
|
24
18
|
// Establish the object that gets thrown to break out of a loop iteration.
|
25
19
|
var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__';
|
26
20
|
|
21
|
+
// Quick regexp-escaping function, because JS doesn't have RegExp.escape().
|
22
|
+
var escapeRegExp = function(s) { return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); };
|
23
|
+
|
24
|
+
// Save bytes in the minified (but not gzipped) version:
|
25
|
+
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
|
26
|
+
|
27
|
+
// Create quick reference variables for speed access to core prototypes.
|
28
|
+
var slice = ArrayProto.slice,
|
29
|
+
unshift = ArrayProto.unshift,
|
30
|
+
toString = ObjProto.toString,
|
31
|
+
hasOwnProperty = ObjProto.hasOwnProperty,
|
32
|
+
propertyIsEnumerable = ObjProto.propertyIsEnumerable;
|
33
|
+
|
34
|
+
// All ECMA5 native implementations we hope to use are declared here.
|
35
|
+
var
|
36
|
+
nativeForEach = ArrayProto.forEach,
|
37
|
+
nativeMap = ArrayProto.map,
|
38
|
+
nativeReduce = ArrayProto.reduce,
|
39
|
+
nativeReduceRight = ArrayProto.reduceRight,
|
40
|
+
nativeFilter = ArrayProto.filter,
|
41
|
+
nativeEvery = ArrayProto.every,
|
42
|
+
nativeSome = ArrayProto.some,
|
43
|
+
nativeIndexOf = ArrayProto.indexOf,
|
44
|
+
nativeLastIndexOf = ArrayProto.lastIndexOf,
|
45
|
+
nativeIsArray = Array.isArray,
|
46
|
+
nativeKeys = Object.keys;
|
47
|
+
|
27
48
|
// Create a safe reference to the Underscore object for reference below.
|
28
|
-
var _ =
|
49
|
+
var _ = function(obj) { return new wrapper(obj); };
|
29
50
|
|
30
51
|
// Export the Underscore object for CommonJS.
|
31
52
|
if (typeof exports !== 'undefined') exports._ = _;
|
32
53
|
|
33
|
-
//
|
34
|
-
|
35
|
-
unshift = Array.prototype.unshift,
|
36
|
-
toString = Object.prototype.toString,
|
37
|
-
hasOwnProperty = Object.prototype.hasOwnProperty,
|
38
|
-
propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
|
54
|
+
// Export underscore to global scope.
|
55
|
+
root._ = _;
|
39
56
|
|
40
57
|
// Current version.
|
41
|
-
_.VERSION = '0.
|
58
|
+
_.VERSION = '0.6.0';
|
42
59
|
|
43
60
|
// ------------------------ Collection Functions: ---------------------------
|
44
61
|
|
45
62
|
// The cornerstone, an each implementation.
|
46
63
|
// Handles objects implementing forEach, arrays, and raw objects.
|
47
|
-
|
64
|
+
// Delegates to JavaScript 1.6's native forEach if available.
|
65
|
+
var each = _.forEach = function(obj, iterator, context) {
|
48
66
|
var index = 0;
|
49
67
|
try {
|
50
|
-
if (obj.forEach) {
|
68
|
+
if (nativeForEach && obj.forEach === nativeForEach) {
|
51
69
|
obj.forEach(iterator, context);
|
52
|
-
} else if (_.
|
53
|
-
for (var i=0, l=obj.length; i<l; i++) iterator.call(context, obj[i], i, obj);
|
70
|
+
} else if (_.isNumber(obj.length)) {
|
71
|
+
for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj);
|
54
72
|
} else {
|
55
|
-
var
|
56
|
-
|
73
|
+
for (var key in obj) {
|
74
|
+
if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj);
|
75
|
+
}
|
57
76
|
}
|
58
77
|
} catch(e) {
|
59
78
|
if (e != breaker) throw e;
|
@@ -61,42 +80,39 @@
|
|
61
80
|
return obj;
|
62
81
|
};
|
63
82
|
|
64
|
-
// Return the results of applying the iterator to each element.
|
65
|
-
// 1.6's
|
83
|
+
// Return the results of applying the iterator to each element.
|
84
|
+
// Delegates to JavaScript 1.6's native map if available.
|
66
85
|
_.map = function(obj, iterator, context) {
|
67
|
-
if (
|
86
|
+
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
68
87
|
var results = [];
|
69
|
-
|
88
|
+
each(obj, function(value, index, list) {
|
70
89
|
results.push(iterator.call(context, value, index, list));
|
71
90
|
});
|
72
91
|
return results;
|
73
92
|
};
|
74
93
|
|
75
|
-
// Reduce builds up a single result from a list of values
|
76
|
-
//
|
94
|
+
// Reduce builds up a single result from a list of values, aka inject, or foldl.
|
95
|
+
// Delegates to JavaScript 1.8's native reduce if available.
|
77
96
|
_.reduce = function(obj, memo, iterator, context) {
|
78
|
-
if (
|
79
|
-
|
97
|
+
if (nativeReduce && obj.reduce === nativeReduce) return obj.reduce(_.bind(iterator, context), memo);
|
98
|
+
each(obj, function(value, index, list) {
|
80
99
|
memo = iterator.call(context, memo, value, index, list);
|
81
100
|
});
|
82
101
|
return memo;
|
83
102
|
};
|
84
103
|
|
85
104
|
// The right-associative version of reduce, also known as foldr. Uses
|
86
|
-
// JavaScript 1.8's
|
105
|
+
// Delegates to JavaScript 1.8's native reduceRight if available.
|
87
106
|
_.reduceRight = function(obj, memo, iterator, context) {
|
88
|
-
if (
|
107
|
+
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) return obj.reduceRight(_.bind(iterator, context), memo);
|
89
108
|
var reversed = _.clone(_.toArray(obj)).reverse();
|
90
|
-
_.
|
91
|
-
memo = iterator.call(context, memo, value, index, obj);
|
92
|
-
});
|
93
|
-
return memo;
|
109
|
+
return _.reduce(reversed, memo, iterator, context);
|
94
110
|
};
|
95
111
|
|
96
112
|
// Return the first value which passes a truth test.
|
97
113
|
_.detect = function(obj, iterator, context) {
|
98
114
|
var result;
|
99
|
-
|
115
|
+
each(obj, function(value, index, list) {
|
100
116
|
if (iterator.call(context, value, index, list)) {
|
101
117
|
result = value;
|
102
118
|
_.breakLoop();
|
@@ -105,12 +121,12 @@
|
|
105
121
|
return result;
|
106
122
|
};
|
107
123
|
|
108
|
-
// Return all the elements that pass a truth test.
|
109
|
-
// filter
|
110
|
-
_.
|
111
|
-
if (
|
124
|
+
// Return all the elements that pass a truth test.
|
125
|
+
// Delegates to JavaScript 1.6's native filter if available.
|
126
|
+
_.filter = function(obj, iterator, context) {
|
127
|
+
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
112
128
|
var results = [];
|
113
|
-
|
129
|
+
each(obj, function(value, index, list) {
|
114
130
|
iterator.call(context, value, index, list) && results.push(value);
|
115
131
|
});
|
116
132
|
return results;
|
@@ -119,42 +135,41 @@
|
|
119
135
|
// Return all the elements for which a truth test fails.
|
120
136
|
_.reject = function(obj, iterator, context) {
|
121
137
|
var results = [];
|
122
|
-
|
138
|
+
each(obj, function(value, index, list) {
|
123
139
|
!iterator.call(context, value, index, list) && results.push(value);
|
124
140
|
});
|
125
141
|
return results;
|
126
142
|
};
|
127
143
|
|
128
|
-
// Determine whether all of the elements match a truth test.
|
129
|
-
// JavaScript 1.6's every
|
130
|
-
_.
|
144
|
+
// Determine whether all of the elements match a truth test.
|
145
|
+
// Delegates to JavaScript 1.6's native every if available.
|
146
|
+
_.every = function(obj, iterator, context) {
|
131
147
|
iterator = iterator || _.identity;
|
132
|
-
if (
|
148
|
+
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
133
149
|
var result = true;
|
134
|
-
|
150
|
+
each(obj, function(value, index, list) {
|
135
151
|
if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
|
136
152
|
});
|
137
153
|
return result;
|
138
154
|
};
|
139
155
|
|
140
|
-
// Determine if at least one element in the object matches a truth test.
|
141
|
-
// JavaScript 1.6's some
|
142
|
-
_.
|
156
|
+
// Determine if at least one element in the object matches a truth test.
|
157
|
+
// Delegates to JavaScript 1.6's native some if available.
|
158
|
+
_.some = function(obj, iterator, context) {
|
143
159
|
iterator = iterator || _.identity;
|
144
|
-
if (
|
160
|
+
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
145
161
|
var result = false;
|
146
|
-
|
162
|
+
each(obj, function(value, index, list) {
|
147
163
|
if (result = iterator.call(context, value, index, list)) _.breakLoop();
|
148
164
|
});
|
149
165
|
return result;
|
150
166
|
};
|
151
167
|
|
152
|
-
// Determine if a given value is included in the array or object
|
153
|
-
// based on '==='.
|
168
|
+
// Determine if a given value is included in the array or object using '==='.
|
154
169
|
_.include = function(obj, target) {
|
155
|
-
if (
|
170
|
+
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
156
171
|
var found = false;
|
157
|
-
|
172
|
+
each(obj, function(value) {
|
158
173
|
if (found = value === target) _.breakLoop();
|
159
174
|
});
|
160
175
|
return found;
|
@@ -177,7 +192,7 @@
|
|
177
192
|
_.max = function(obj, iterator, context) {
|
178
193
|
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
|
179
194
|
var result = {computed : -Infinity};
|
180
|
-
|
195
|
+
each(obj, function(value, index, list) {
|
181
196
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
182
197
|
computed >= result.computed && (result = {value : value, computed : computed});
|
183
198
|
});
|
@@ -188,7 +203,7 @@
|
|
188
203
|
_.min = function(obj, iterator, context) {
|
189
204
|
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
|
190
205
|
var result = {computed : Infinity};
|
191
|
-
|
206
|
+
each(obj, function(value, index, list) {
|
192
207
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
193
208
|
computed < result.computed && (result = {value : value, computed : computed});
|
194
209
|
});
|
@@ -258,7 +273,7 @@
|
|
258
273
|
|
259
274
|
// Trim out all falsy values from an array.
|
260
275
|
_.compact = function(array) {
|
261
|
-
return _.
|
276
|
+
return _.filter(array, function(value){ return !!value; });
|
262
277
|
};
|
263
278
|
|
264
279
|
// Return a completely flattened version of an array.
|
@@ -273,7 +288,7 @@
|
|
273
288
|
// Return a version of the array that does not contain the specified value(s).
|
274
289
|
_.without = function(array) {
|
275
290
|
var values = _.rest(arguments);
|
276
|
-
return _.
|
291
|
+
return _.filter(array, function(value){ return !_.include(values, value); });
|
277
292
|
};
|
278
293
|
|
279
294
|
// Produce a duplicate-free version of the array. If the array has already
|
@@ -289,8 +304,8 @@
|
|
289
304
|
// passed-in arrays.
|
290
305
|
_.intersect = function(array) {
|
291
306
|
var rest = _.rest(arguments);
|
292
|
-
return _.
|
293
|
-
return _.
|
307
|
+
return _.filter(_.uniq(array), function(item) {
|
308
|
+
return _.every(rest, function(other) {
|
294
309
|
return _.indexOf(other, item) >= 0;
|
295
310
|
});
|
296
311
|
});
|
@@ -302,23 +317,24 @@
|
|
302
317
|
var args = _.toArray(arguments);
|
303
318
|
var length = _.max(_.pluck(args, 'length'));
|
304
319
|
var results = new Array(length);
|
305
|
-
for (var i=0; i<length; i++) results[i] = _.pluck(args, String(i));
|
320
|
+
for (var i = 0; i < length; i++) results[i] = _.pluck(args, String(i));
|
306
321
|
return results;
|
307
322
|
};
|
308
323
|
|
309
324
|
// If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
|
310
325
|
// we need this function. Return the position of the first occurence of an
|
311
326
|
// item in an array, or -1 if the item is not included in the array.
|
327
|
+
// Delegates to JavaScript 1.8's native indexOf if available.
|
312
328
|
_.indexOf = function(array, item) {
|
313
|
-
if (array.indexOf) return array.indexOf(item);
|
314
|
-
for (var i=0, l=array.length; i<l; i++) if (array[i] === item) return i;
|
329
|
+
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
330
|
+
for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
|
315
331
|
return -1;
|
316
332
|
};
|
317
333
|
|
318
|
-
|
319
|
-
// if
|
334
|
+
|
335
|
+
// Delegates to JavaScript 1.6's native lastIndexOf if available.
|
320
336
|
_.lastIndexOf = function(array, item) {
|
321
|
-
if (array.lastIndexOf) return array.lastIndexOf(item);
|
337
|
+
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
|
322
338
|
var i = array.length;
|
323
339
|
while (i--) if (array[i] === item) return i;
|
324
340
|
return -1;
|
@@ -347,7 +363,7 @@
|
|
347
363
|
_.bind = function(func, obj) {
|
348
364
|
var args = _.rest(arguments, 2);
|
349
365
|
return function() {
|
350
|
-
return func.apply(obj ||
|
366
|
+
return func.apply(obj || {}, args.concat(_.toArray(arguments)));
|
351
367
|
};
|
352
368
|
};
|
353
369
|
|
@@ -356,7 +372,7 @@
|
|
356
372
|
_.bindAll = function(obj) {
|
357
373
|
var funcs = _.rest(arguments);
|
358
374
|
if (funcs.length == 0) funcs = _.functions(obj);
|
359
|
-
|
375
|
+
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
360
376
|
return obj;
|
361
377
|
};
|
362
378
|
|
@@ -399,8 +415,9 @@
|
|
399
415
|
// ------------------------- Object Functions: ------------------------------
|
400
416
|
|
401
417
|
// Retrieve the names of an object's properties.
|
402
|
-
|
403
|
-
|
418
|
+
// Delegates to ECMA5's native Object.keys
|
419
|
+
_.keys = nativeKeys || function(obj) {
|
420
|
+
if (_.isArray(obj)) return _.range(0, obj.length);
|
404
421
|
var keys = [];
|
405
422
|
for (var key in obj) if (hasOwnProperty.call(obj, key)) keys.push(key);
|
406
423
|
return keys;
|
@@ -411,9 +428,9 @@
|
|
411
428
|
return _.map(obj, _.identity);
|
412
429
|
};
|
413
430
|
|
414
|
-
// Return a sorted list of the function names available
|
431
|
+
// Return a sorted list of the function names available on the object.
|
415
432
|
_.functions = function(obj) {
|
416
|
-
return _.
|
433
|
+
return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
|
417
434
|
};
|
418
435
|
|
419
436
|
// Extend a given object with all of the properties in a source object.
|
@@ -473,7 +490,9 @@
|
|
473
490
|
|
474
491
|
// Is a given array or object empty?
|
475
492
|
_.isEmpty = function(obj) {
|
476
|
-
|
493
|
+
if (_.isArray(obj)) return obj.length === 0;
|
494
|
+
for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
|
495
|
+
return true;
|
477
496
|
};
|
478
497
|
|
479
498
|
// Is a given value a DOM element?
|
@@ -482,7 +501,8 @@
|
|
482
501
|
};
|
483
502
|
|
484
503
|
// Is a given value an array?
|
485
|
-
|
504
|
+
// Delegates to ECMA5's native Array.isArray
|
505
|
+
_.isArray = nativeIsArray || function(obj) {
|
486
506
|
return !!(obj && obj.concat && obj.unshift);
|
487
507
|
};
|
488
508
|
|
@@ -546,11 +566,24 @@
|
|
546
566
|
return value;
|
547
567
|
};
|
548
568
|
|
569
|
+
// Run a function n times.
|
570
|
+
_.times = function (n, iterator, context) {
|
571
|
+
for (var i = 0; i < n; i++) iterator.call(context, i);
|
572
|
+
};
|
573
|
+
|
549
574
|
// Break out of the middle of an iteration.
|
550
575
|
_.breakLoop = function() {
|
551
576
|
throw breaker;
|
552
577
|
};
|
553
578
|
|
579
|
+
// Add your own custom functions to the Underscore object, ensuring that
|
580
|
+
// they're correctly added to the OOP wrapper as well.
|
581
|
+
_.mixin = function(obj) {
|
582
|
+
each(_.functions(obj), function(name){
|
583
|
+
addToWrapper(name, _[name] = obj[name]);
|
584
|
+
});
|
585
|
+
};
|
586
|
+
|
554
587
|
// Generate a unique integer id (unique within the entire client session).
|
555
588
|
// Useful for temporary DOM ids.
|
556
589
|
var idCounter = 0;
|
@@ -570,13 +603,15 @@
|
|
570
603
|
// JavaScript templating a-la ERB, pilfered from John Resig's
|
571
604
|
// "Secrets of the JavaScript Ninja", page 83.
|
572
605
|
// Single-quote fix from Rick Strahl's version.
|
606
|
+
// With alterations for arbitrary delimiters.
|
573
607
|
_.template = function(str, data) {
|
574
608
|
var c = _.templateSettings;
|
609
|
+
var endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g");
|
575
610
|
var fn = new Function('obj',
|
576
611
|
'var p=[],print=function(){p.push.apply(p,arguments);};' +
|
577
612
|
'with(obj){p.push(\'' +
|
578
613
|
str.replace(/[\r\t\n]/g, " ")
|
579
|
-
.replace(
|
614
|
+
.replace(endMatch,"\t")
|
580
615
|
.split("'").join("\\'")
|
581
616
|
.split("\t").join("'")
|
582
617
|
.replace(c.interpolate, "',$1,'")
|
@@ -588,36 +623,43 @@
|
|
588
623
|
|
589
624
|
// ------------------------------- Aliases ----------------------------------
|
590
625
|
|
591
|
-
_.
|
626
|
+
_.each = _.forEach;
|
592
627
|
_.foldl = _.inject = _.reduce;
|
593
628
|
_.foldr = _.reduceRight;
|
594
|
-
_.
|
595
|
-
_.
|
596
|
-
_.
|
629
|
+
_.select = _.filter;
|
630
|
+
_.all = _.every;
|
631
|
+
_.any = _.some;
|
597
632
|
_.head = _.first;
|
598
633
|
_.tail = _.rest;
|
599
634
|
_.methods = _.functions;
|
600
635
|
|
601
636
|
// ------------------------ Setup the OOP Wrapper: --------------------------
|
602
637
|
|
638
|
+
// If Underscore is called as a function, it returns a wrapped object that
|
639
|
+
// can be used OO-style. This wrapper holds altered versions of all the
|
640
|
+
// underscore functions. Wrapped objects may be chained.
|
641
|
+
var wrapper = function(obj) { this._wrapped = obj; };
|
642
|
+
|
603
643
|
// Helper function to continue chaining intermediate results.
|
604
644
|
var result = function(obj, chain) {
|
605
645
|
return chain ? _(obj).chain() : obj;
|
606
646
|
};
|
607
647
|
|
608
|
-
//
|
609
|
-
|
610
|
-
var method = _[name];
|
648
|
+
// A method to easily add functions to the OOP wrapper.
|
649
|
+
var addToWrapper = function(name, func) {
|
611
650
|
wrapper.prototype[name] = function() {
|
612
651
|
var args = _.toArray(arguments);
|
613
652
|
unshift.call(args, this._wrapped);
|
614
|
-
return result(
|
653
|
+
return result(func.apply(_, args), this._chain);
|
615
654
|
};
|
616
|
-
}
|
655
|
+
};
|
656
|
+
|
657
|
+
// Add all of the Underscore functions to the wrapper object.
|
658
|
+
_.mixin(_);
|
617
659
|
|
618
660
|
// Add all mutator Array functions to the wrapper.
|
619
|
-
|
620
|
-
var method =
|
661
|
+
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
662
|
+
var method = ArrayProto[name];
|
621
663
|
wrapper.prototype[name] = function() {
|
622
664
|
method.apply(this._wrapped, arguments);
|
623
665
|
return result(this._wrapped, this._chain);
|
@@ -625,8 +667,8 @@
|
|
625
667
|
});
|
626
668
|
|
627
669
|
// Add all accessor Array functions to the wrapper.
|
628
|
-
|
629
|
-
var method =
|
670
|
+
each(['concat', 'join', 'slice'], function(name) {
|
671
|
+
var method = ArrayProto[name];
|
630
672
|
wrapper.prototype[name] = function() {
|
631
673
|
return result(method.apply(this._wrapped, arguments), this._chain);
|
632
674
|
};
|