underscore-source 0.5.7 → 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.
@@ -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