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.
@@ -1,5 +1,5 @@
1
1
  module Underscore
2
2
  module Source
3
- VERSION = "0.5.7"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  end
@@ -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 _ = root._ = function(obj) { return new wrapper(obj); };
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
- // Create quick reference variables for speed access to core prototypes.
34
- var slice = Array.prototype.slice,
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.5.7';
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
- _.each = function(obj, iterator, context) {
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 (_.isArray(obj) || _.isArguments(obj)) {
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 keys = _.keys(obj), l = keys.length;
56
- for (var i=0; i<l; i++) iterator.call(context, obj[keys[i]], keys[i], obj);
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. Use JavaScript
65
- // 1.6's version of map, if possible.
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 (obj && _.isFunction(obj.map)) return obj.map(iterator, context);
86
+ if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
68
87
  var results = [];
69
- _.each(obj, function(value, index, list) {
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. Also known as
76
- // inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.
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 (obj && _.isFunction(obj.reduce)) return obj.reduce(_.bind(iterator, context), memo);
79
- _.each(obj, function(value, index, list) {
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 version of reduceRight, if available.
105
+ // Delegates to JavaScript 1.8's native reduceRight if available.
87
106
  _.reduceRight = function(obj, memo, iterator, context) {
88
- if (obj && _.isFunction(obj.reduceRight)) return obj.reduceRight(_.bind(iterator, context), memo);
107
+ if (nativeReduceRight && obj.reduceRight === nativeReduceRight) return obj.reduceRight(_.bind(iterator, context), memo);
89
108
  var reversed = _.clone(_.toArray(obj)).reverse();
90
- _.each(reversed, function(value, index) {
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
- _.each(obj, function(value, index, list) {
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. Use JavaScript 1.6's
109
- // filter(), if it exists.
110
- _.select = function(obj, iterator, context) {
111
- if (obj && _.isFunction(obj.filter)) return obj.filter(iterator, context);
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
- _.each(obj, function(value, index, list) {
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
- _.each(obj, function(value, index, list) {
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. Delegate to
129
- // JavaScript 1.6's every(), if it is present.
130
- _.all = function(obj, iterator, context) {
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 (obj && _.isFunction(obj.every)) return obj.every(iterator, context);
148
+ if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
133
149
  var result = true;
134
- _.each(obj, function(value, index, list) {
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. Use
141
- // JavaScript 1.6's some(), if it exists.
142
- _.any = function(obj, iterator, context) {
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 (obj && _.isFunction(obj.some)) return obj.some(iterator, context);
160
+ if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
145
161
  var result = false;
146
- _.each(obj, function(value, index, list) {
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 (_.isArray(obj)) return _.indexOf(obj, target) != -1;
170
+ if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
156
171
  var found = false;
157
- _.each(obj, function(value) {
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
- _.each(obj, function(value, index, list) {
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
- _.each(obj, function(value, index, list) {
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 _.select(array, function(value){ return !!value; });
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 _.select(array, function(value){ return !_.include(values, value); });
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 _.select(_.uniq(array), function(item) {
293
- return _.all(rest, function(other) {
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
- // Provide JavaScript 1.6's lastIndexOf, delegating to the native function,
319
- // if possible.
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 || root, args.concat(_.toArray(arguments)));
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
- _.each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
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
- _.keys = function(obj) {
403
- if(_.isArray(obj)) return _.range(0, obj.length);
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 in Underscore.
431
+ // Return a sorted list of the function names available on the object.
415
432
  _.functions = function(obj) {
416
- return _.select(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
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
- return _.keys(obj).length == 0;
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
- _.isArray = function(obj) {
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(new RegExp("'(?=[^"+c.end[0]+"]*"+c.end+")","g"),"\t")
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
- _.forEach = _.each;
626
+ _.each = _.forEach;
592
627
  _.foldl = _.inject = _.reduce;
593
628
  _.foldr = _.reduceRight;
594
- _.filter = _.select;
595
- _.every = _.all;
596
- _.some = _.any;
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
- // Add all of the Underscore functions to the wrapper object.
609
- _.each(_.functions(_), function(name) {
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(method.apply(_, args), this._chain);
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
- _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
620
- var method = Array.prototype[name];
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
- _.each(['concat', 'join', 'slice'], function(name) {
629
- var method = Array.prototype[name];
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
  };
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: underscore-source
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.5.7
5
+ version: 0.6.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Daniel X. Moore