underscore_extensions 0.2.4 → 0.2.5

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 042a27db5ef9ba1099d77038c102c139bf890af3
4
+ data.tar.gz: 2ca5ba4ca74be59e61601da701ed50601617d51c
5
+ SHA512:
6
+ metadata.gz: 15f82e7a81c84d4055931acda7030c7acdfbf2c08dc2f518741ccbb5c68111867d8cf0c141272bee39e1b3a8616c562335bdd286c539deee67786ca29af6fd3b
7
+ data.tar.gz: 8af5584e0d09de5325fad62fb69e6c0f8d9a224ba2da7c48f6a697b16c14c24d9a7995dc1f3d0a48d0ba6806ec085d3686dcd3722a336c3d051aa7361170720a
@@ -0,0 +1 @@
1
+ underscore_extensions
@@ -0,0 +1 @@
1
+ 2.0.0
@@ -1,8 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.8.7
4
- - 1.9.2
5
3
  - 1.9.3
4
+ - 2.0.0
6
5
  before_script:
7
6
  - "export DISPLAY=:99.0"
8
7
  - "sh -e /etc/init.d/xvfb start"
@@ -1,5 +1,5 @@
1
1
  module UnderscoreExtensions
2
- VERSION = '0.2.4'
3
- UNDERSCORE_VERSION = '1.4.4'
2
+ VERSION = '0.2.5'
3
+ UNDERSCORE_VERSION = '1.5.2'
4
4
  UNDERSCORE_STRING_VERSION = '2.3.0'
5
5
  end
@@ -1,15 +1,14 @@
1
- // Underscore.js 1.4.4
2
- // ===================
1
+ // Underscore.js 1.5.2
2
+ // http://underscorejs.org
3
+ // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4
+ // Underscore may be freely distributed under the MIT license.
3
5
 
4
- // > http://underscorejs.org
5
- // > (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
6
- // > Underscore may be freely distributed under the MIT license.
7
-
8
- // Baseline setup
9
- // --------------
10
6
  (function() {
11
7
 
12
- // Establish the root object, `window` in the browser, or `global` on the server.
8
+ // Baseline setup
9
+ // --------------
10
+
11
+ // Establish the root object, `window` in the browser, or `exports` on the server.
13
12
  var root = this;
14
13
 
15
14
  // Save the previous value of the `_` variable.
@@ -22,27 +21,28 @@
22
21
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
23
22
 
24
23
  // Create quick reference variables for speed access to core prototypes.
25
- var push = ArrayProto.push,
26
- slice = ArrayProto.slice,
27
- concat = ArrayProto.concat,
28
- toString = ObjProto.toString,
29
- hasOwnProperty = ObjProto.hasOwnProperty;
24
+ var
25
+ push = ArrayProto.push,
26
+ slice = ArrayProto.slice,
27
+ concat = ArrayProto.concat,
28
+ toString = ObjProto.toString,
29
+ hasOwnProperty = ObjProto.hasOwnProperty;
30
30
 
31
31
  // All **ECMAScript 5** native function implementations that we hope to use
32
32
  // are declared here.
33
33
  var
34
- nativeForEach = ArrayProto.forEach,
35
- nativeMap = ArrayProto.map,
36
- nativeReduce = ArrayProto.reduce,
37
- nativeReduceRight = ArrayProto.reduceRight,
38
- nativeFilter = ArrayProto.filter,
39
- nativeEvery = ArrayProto.every,
40
- nativeSome = ArrayProto.some,
41
- nativeIndexOf = ArrayProto.indexOf,
42
- nativeLastIndexOf = ArrayProto.lastIndexOf,
43
- nativeIsArray = Array.isArray,
44
- nativeKeys = Object.keys,
45
- nativeBind = FuncProto.bind;
34
+ nativeForEach = ArrayProto.forEach,
35
+ nativeMap = ArrayProto.map,
36
+ nativeReduce = ArrayProto.reduce,
37
+ nativeReduceRight = ArrayProto.reduceRight,
38
+ nativeFilter = ArrayProto.filter,
39
+ nativeEvery = ArrayProto.every,
40
+ nativeSome = ArrayProto.some,
41
+ nativeIndexOf = ArrayProto.indexOf,
42
+ nativeLastIndexOf = ArrayProto.lastIndexOf,
43
+ nativeIsArray = Array.isArray,
44
+ nativeKeys = Object.keys,
45
+ nativeBind = FuncProto.bind;
46
46
 
47
47
  // Create a safe reference to the Underscore object for use below.
48
48
  var _ = function(obj) {
@@ -65,7 +65,7 @@
65
65
  }
66
66
 
67
67
  // Current version.
68
- _.VERSION = '1.4.4';
68
+ _.VERSION = '1.5.2';
69
69
 
70
70
  // Collection Functions
71
71
  // --------------------
@@ -78,14 +78,13 @@
78
78
  if (nativeForEach && obj.forEach === nativeForEach) {
79
79
  obj.forEach(iterator, context);
80
80
  } else if (obj.length === +obj.length) {
81
- for (var i = 0, l = obj.length; i < l; i++) {
81
+ for (var i = 0, length = obj.length; i < length; i++) {
82
82
  if (iterator.call(context, obj[i], i, obj) === breaker) return;
83
83
  }
84
84
  } else {
85
- for (var key in obj) {
86
- if (_.has(obj, key)) {
87
- if (iterator.call(context, obj[key], key, obj) === breaker) return;
88
- }
85
+ var keys = _.keys(obj);
86
+ for (var i = 0, length = keys.length; i < length; i++) {
87
+ if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
89
88
  }
90
89
  }
91
90
  };
@@ -97,7 +96,7 @@
97
96
  if (obj == null) return results;
98
97
  if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
99
98
  each(obj, function(value, index, list) {
100
- results[results.length] = iterator.call(context, value, index, list);
99
+ results.push(iterator.call(context, value, index, list));
101
100
  });
102
101
  return results;
103
102
  };
@@ -172,7 +171,7 @@
172
171
  if (obj == null) return results;
173
172
  if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
174
173
  each(obj, function(value, index, list) {
175
- if (iterator.call(context, value, index, list)) results[results.length] = value;
174
+ if (iterator.call(context, value, index, list)) results.push(value);
176
175
  });
177
176
  return results;
178
177
  };
@@ -239,7 +238,7 @@
239
238
  // Convenience version of a common use case of `filter`: selecting only objects
240
239
  // containing specific `key:value` pairs.
241
240
  _.where = function(obj, attrs, first) {
242
- if (_.isEmpty(attrs)) return first ? null : [];
241
+ if (_.isEmpty(attrs)) return first ? void 0 : [];
243
242
  return _[first ? 'find' : 'filter'](obj, function(value) {
244
243
  for (var key in attrs) {
245
244
  if (attrs[key] !== value[key]) return false;
@@ -256,7 +255,7 @@
256
255
 
257
256
  // Return the maximum element or (element-based computation).
258
257
  // Can't optimize arrays of integers longer than 65,535 elements.
259
- // See: https://bugs.webkit.org/show_bug.cgi?id=80797
258
+ // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
260
259
  _.max = function(obj, iterator, context) {
261
260
  if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
262
261
  return Math.max.apply(Math, obj);
@@ -265,7 +264,7 @@
265
264
  var result = {computed : -Infinity, value: -Infinity};
266
265
  each(obj, function(value, index, list) {
267
266
  var computed = iterator ? iterator.call(context, value, index, list) : value;
268
- computed >= result.computed && (result = {value : value, computed : computed});
267
+ computed > result.computed && (result = {value : value, computed : computed});
269
268
  });
270
269
  return result.value;
271
270
  };
@@ -284,7 +283,8 @@
284
283
  return result.value;
285
284
  };
286
285
 
287
- // Shuffle an array.
286
+ // Shuffle an array, using the modern version of the
287
+ // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
288
288
  _.shuffle = function(obj) {
289
289
  var rand;
290
290
  var index = 0;
@@ -297,6 +297,16 @@
297
297
  return shuffled;
298
298
  };
299
299
 
300
+ // Sample **n** random values from an array.
301
+ // If **n** is not specified, returns a single random element from the array.
302
+ // The internal `guard` argument allows it to work with `map`.
303
+ _.sample = function(obj, n, guard) {
304
+ if (arguments.length < 2 || guard) {
305
+ return obj[_.random(obj.length - 1)];
306
+ }
307
+ return _.shuffle(obj).slice(0, Math.max(0, n));
308
+ };
309
+
300
310
  // An internal function to generate lookup iterators.
301
311
  var lookupIterator = function(value) {
302
312
  return _.isFunction(value) ? value : function(obj){ return obj[value]; };
@@ -307,49 +317,52 @@
307
317
  var iterator = lookupIterator(value);
308
318
  return _.pluck(_.map(obj, function(value, index, list) {
309
319
  return {
310
- value : value,
311
- index : index,
312
- criteria : iterator.call(context, value, index, list)
320
+ value: value,
321
+ index: index,
322
+ criteria: iterator.call(context, value, index, list)
313
323
  };
314
324
  }).sort(function(left, right) {
315
- var a = left.criteria;
316
- var b = right.criteria;
317
- if (a !== b) {
318
- if (a > b || a === void 0) return 1;
319
- if (a < b || b === void 0) return -1;
320
- }
321
- return left.index < right.index ? -1 : 1;
322
- }), 'value');
325
+ var a = left.criteria;
326
+ var b = right.criteria;
327
+ if (a !== b) {
328
+ if (a > b || a === void 0) return 1;
329
+ if (a < b || b === void 0) return -1;
330
+ }
331
+ return left.index - right.index;
332
+ }), 'value');
323
333
  };
324
334
 
325
335
  // An internal function used for aggregate "group by" operations.
326
- var group = function(obj, value, context, behavior) {
327
- var result = {};
328
- var iterator = lookupIterator(value || _.identity);
329
- each(obj, function(value, index) {
330
- var key = iterator.call(context, value, index, obj);
331
- behavior(result, key, value);
332
- });
333
- return result;
336
+ var group = function(behavior) {
337
+ return function(obj, value, context) {
338
+ var result = {};
339
+ var iterator = value == null ? _.identity : lookupIterator(value);
340
+ each(obj, function(value, index) {
341
+ var key = iterator.call(context, value, index, obj);
342
+ behavior(result, key, value);
343
+ });
344
+ return result;
345
+ };
334
346
  };
335
347
 
336
348
  // Groups the object's values by a criterion. Pass either a string attribute
337
349
  // to group by, or a function that returns the criterion.
338
- _.groupBy = function(obj, value, context) {
339
- return group(obj, value, context, function(result, key, value) {
340
- (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
341
- });
342
- };
350
+ _.groupBy = group(function(result, key, value) {
351
+ (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
352
+ });
353
+
354
+ // Indexes the object's values by a criterion, similar to `groupBy`, but for
355
+ // when you know that your index values will be unique.
356
+ _.indexBy = group(function(result, key, value) {
357
+ result[key] = value;
358
+ });
343
359
 
344
360
  // Counts instances of an object that group by a certain criterion. Pass
345
361
  // either a string attribute to count by, or a function that returns the
346
362
  // criterion.
347
- _.countBy = function(obj, value, context) {
348
- return group(obj, value, context, function(result, key) {
349
- if (!_.has(result, key)) result[key] = 0;
350
- result[key]++;
351
- });
352
- };
363
+ _.countBy = group(function(result, key) {
364
+ _.has(result, key) ? result[key]++ : result[key] = 1;
365
+ });
353
366
 
354
367
  // Use a comparator function to figure out the smallest index at which
355
368
  // an object should be inserted so as to maintain order. Uses binary search.
@@ -364,7 +377,7 @@
364
377
  return low;
365
378
  };
366
379
 
367
- // Safely convert anything iterable into a real, live array.
380
+ // Safely create a real, live array from anything iterable.
368
381
  _.toArray = function(obj) {
369
382
  if (!obj) return [];
370
383
  if (_.isArray(obj)) return slice.call(obj);
@@ -386,7 +399,7 @@
386
399
  // allows it to work with `_.map`.
387
400
  _.first = _.head = _.take = function(array, n, guard) {
388
401
  if (array == null) return void 0;
389
- return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
402
+ return (n == null) || guard ? array[0] : slice.call(array, 0, n);
390
403
  };
391
404
 
392
405
  // Returns everything but the last entry of the array. Especially useful on
@@ -401,10 +414,10 @@
401
414
  // values in the array. The **guard** check allows it to work with `_.map`.
402
415
  _.last = function(array, n, guard) {
403
416
  if (array == null) return void 0;
404
- if ((n != null) && !guard) {
405
- return slice.call(array, Math.max(array.length - n, 0));
406
- } else {
417
+ if ((n == null) || guard) {
407
418
  return array[array.length - 1];
419
+ } else {
420
+ return slice.call(array, Math.max(array.length - n, 0));
408
421
  }
409
422
  };
410
423
 
@@ -423,8 +436,11 @@
423
436
 
424
437
  // Internal implementation of a recursive `flatten` function.
425
438
  var flatten = function(input, shallow, output) {
439
+ if (shallow && _.every(input, _.isArray)) {
440
+ return concat.apply(output, input);
441
+ }
426
442
  each(input, function(value) {
427
- if (_.isArray(value)) {
443
+ if (_.isArray(value) || _.isArguments(value)) {
428
444
  shallow ? push.apply(output, value) : flatten(value, shallow, output);
429
445
  } else {
430
446
  output.push(value);
@@ -433,7 +449,7 @@
433
449
  return output;
434
450
  };
435
451
 
436
- // Return a completely flattened version of an array.
452
+ // Flatten out an array, either recursively (by default), or just one level.
437
453
  _.flatten = function(array, shallow) {
438
454
  return flatten(array, shallow, []);
439
455
  };
@@ -467,7 +483,7 @@
467
483
  // Produce an array that contains the union: each distinct element from all of
468
484
  // the passed-in arrays.
469
485
  _.union = function() {
470
- return _.uniq(concat.apply(ArrayProto, arguments));
486
+ return _.uniq(_.flatten(arguments, true));
471
487
  };
472
488
 
473
489
  // Produce an array that contains every item shared between all the
@@ -491,11 +507,10 @@
491
507
  // Zip together multiple lists into a single array -- elements that share
492
508
  // an index go together.
493
509
  _.zip = function() {
494
- var args = slice.call(arguments);
495
- var length = _.max(_.pluck(args, 'length'));
510
+ var length = _.max(_.pluck(arguments, "length").concat(0));
496
511
  var results = new Array(length);
497
512
  for (var i = 0; i < length; i++) {
498
- results[i] = _.pluck(args, "" + i);
513
+ results[i] = _.pluck(arguments, '' + i);
499
514
  }
500
515
  return results;
501
516
  };
@@ -506,7 +521,7 @@
506
521
  _.object = function(list, values) {
507
522
  if (list == null) return {};
508
523
  var result = {};
509
- for (var i = 0, l = list.length; i < l; i++) {
524
+ for (var i = 0, length = list.length; i < length; i++) {
510
525
  if (values) {
511
526
  result[list[i]] = values[i];
512
527
  } else {
@@ -524,17 +539,17 @@
524
539
  // for **isSorted** to use binary search.
525
540
  _.indexOf = function(array, item, isSorted) {
526
541
  if (array == null) return -1;
527
- var i = 0, l = array.length;
542
+ var i = 0, length = array.length;
528
543
  if (isSorted) {
529
544
  if (typeof isSorted == 'number') {
530
- i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
545
+ i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
531
546
  } else {
532
547
  i = _.sortedIndex(array, item);
533
548
  return array[i] === item ? i : -1;
534
549
  }
535
550
  }
536
551
  if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
537
- for (; i < l; i++) if (array[i] === item) return i;
552
+ for (; i < length; i++) if (array[i] === item) return i;
538
553
  return -1;
539
554
  };
540
555
 
@@ -560,11 +575,11 @@
560
575
  }
561
576
  step = arguments[2] || 1;
562
577
 
563
- var len = Math.max(Math.ceil((stop - start) / step), 0);
578
+ var length = Math.max(Math.ceil((stop - start) / step), 0);
564
579
  var idx = 0;
565
- var range = new Array(len);
580
+ var range = new Array(length);
566
581
 
567
- while(idx < len) {
582
+ while(idx < length) {
568
583
  range[idx++] = start;
569
584
  start += step;
570
585
  }
@@ -575,14 +590,25 @@
575
590
  // Function (ahem) Functions
576
591
  // ------------------
577
592
 
593
+ // Reusable constructor function for prototype setting.
594
+ var ctor = function(){};
595
+
578
596
  // Create a function bound to a given object (assigning `this`, and arguments,
579
597
  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
580
598
  // available.
581
599
  _.bind = function(func, context) {
582
- if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
583
- var args = slice.call(arguments, 2);
584
- return function() {
585
- return func.apply(context, args.concat(slice.call(arguments)));
600
+ var args, bound;
601
+ if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
602
+ if (!_.isFunction(func)) throw new TypeError;
603
+ args = slice.call(arguments, 2);
604
+ return bound = function() {
605
+ if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
606
+ ctor.prototype = func.prototype;
607
+ var self = new ctor;
608
+ ctor.prototype = null;
609
+ var result = func.apply(self, args.concat(slice.call(arguments)));
610
+ if (Object(result) === result) return result;
611
+ return self;
586
612
  };
587
613
  };
588
614
 
@@ -599,7 +625,7 @@
599
625
  // all callbacks defined on an object belong to it.
600
626
  _.bindAll = function(obj) {
601
627
  var funcs = slice.call(arguments, 1);
602
- if (funcs.length === 0) funcs = _.functions(obj);
628
+ if (funcs.length === 0) throw new Error("bindAll must be passed function names");
603
629
  each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
604
630
  return obj;
605
631
  };
@@ -628,17 +654,23 @@
628
654
  };
629
655
 
630
656
  // Returns a function, that, when invoked, will only be triggered at most once
631
- // during a given window of time.
632
- _.throttle = function(func, wait) {
633
- var context, args, timeout, result;
657
+ // during a given window of time. Normally, the throttled function will run
658
+ // as much as it can, without ever going more than once per `wait` duration;
659
+ // but if you'd like to disable the execution on the leading edge, pass
660
+ // `{leading: false}`. To disable execution on the trailing edge, ditto.
661
+ _.throttle = function(func, wait, options) {
662
+ var context, args, result;
663
+ var timeout = null;
634
664
  var previous = 0;
665
+ options || (options = {});
635
666
  var later = function() {
636
- previous = new Date;
667
+ previous = options.leading === false ? 0 : new Date;
637
668
  timeout = null;
638
669
  result = func.apply(context, args);
639
670
  };
640
671
  return function() {
641
672
  var now = new Date;
673
+ if (!previous && options.leading === false) previous = now;
642
674
  var remaining = wait - (now - previous);
643
675
  context = this;
644
676
  args = arguments;
@@ -647,7 +679,7 @@
647
679
  timeout = null;
648
680
  previous = now;
649
681
  result = func.apply(context, args);
650
- } else if (!timeout) {
682
+ } else if (!timeout && options.trailing !== false) {
651
683
  timeout = setTimeout(later, remaining);
652
684
  }
653
685
  return result;
@@ -659,16 +691,24 @@
659
691
  // N milliseconds. If `immediate` is passed, trigger the function on the
660
692
  // leading edge, instead of the trailing.
661
693
  _.debounce = function(func, wait, immediate) {
662
- var timeout, result;
694
+ var timeout, args, context, timestamp, result;
663
695
  return function() {
664
- var context = this, args = arguments;
696
+ context = this;
697
+ args = arguments;
698
+ timestamp = new Date();
665
699
  var later = function() {
666
- timeout = null;
667
- if (!immediate) result = func.apply(context, args);
700
+ var last = (new Date()) - timestamp;
701
+ if (last < wait) {
702
+ timeout = setTimeout(later, wait - last);
703
+ } else {
704
+ timeout = null;
705
+ if (!immediate) result = func.apply(context, args);
706
+ }
668
707
  };
669
708
  var callNow = immediate && !timeout;
670
- clearTimeout(timeout);
671
- timeout = setTimeout(later, wait);
709
+ if (!timeout) {
710
+ timeout = setTimeout(later, wait);
711
+ }
672
712
  if (callNow) result = func.apply(context, args);
673
713
  return result;
674
714
  };
@@ -713,7 +753,6 @@
713
753
 
714
754
  // Returns a function that will only be executed after being called N times.
715
755
  _.after = function(times, func) {
716
- if (times <= 0) return func();
717
756
  return function() {
718
757
  if (--times < 1) {
719
758
  return func.apply(this, arguments);
@@ -729,28 +768,39 @@
729
768
  _.keys = nativeKeys || function(obj) {
730
769
  if (obj !== Object(obj)) throw new TypeError('Invalid object');
731
770
  var keys = [];
732
- for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
771
+ for (var key in obj) if (_.has(obj, key)) keys.push(key);
733
772
  return keys;
734
773
  };
735
774
 
736
775
  // Retrieve the values of an object's properties.
737
776
  _.values = function(obj) {
738
- var values = [];
739
- for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
777
+ var keys = _.keys(obj);
778
+ var length = keys.length;
779
+ var values = new Array(length);
780
+ for (var i = 0; i < length; i++) {
781
+ values[i] = obj[keys[i]];
782
+ }
740
783
  return values;
741
784
  };
742
785
 
743
786
  // Convert an object into a list of `[key, value]` pairs.
744
787
  _.pairs = function(obj) {
745
- var pairs = [];
746
- for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
788
+ var keys = _.keys(obj);
789
+ var length = keys.length;
790
+ var pairs = new Array(length);
791
+ for (var i = 0; i < length; i++) {
792
+ pairs[i] = [keys[i], obj[keys[i]]];
793
+ }
747
794
  return pairs;
748
795
  };
749
796
 
750
797
  // Invert the keys and values of an object. The values must be serializable.
751
798
  _.invert = function(obj) {
752
799
  var result = {};
753
- for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
800
+ var keys = _.keys(obj);
801
+ for (var i = 0, length = keys.length; i < length; i++) {
802
+ result[obj[keys[i]]] = keys[i];
803
+ }
754
804
  return result;
755
805
  };
756
806
 
@@ -786,7 +836,7 @@
786
836
  return copy;
787
837
  };
788
838
 
789
- // Return a copy of the object without the blacklisted properties.
839
+ // Return a copy of the object without the blacklisted properties.
790
840
  _.omit = function(obj) {
791
841
  var copy = {};
792
842
  var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
@@ -801,7 +851,7 @@
801
851
  each(slice.call(arguments, 1), function(source) {
802
852
  if (source) {
803
853
  for (var prop in source) {
804
- if (obj[prop] == null) obj[prop] = source[prop];
854
+ if (obj[prop] === void 0) obj[prop] = source[prop];
805
855
  }
806
856
  }
807
857
  });
@@ -825,7 +875,7 @@
825
875
  // Internal recursive comparison function for `isEqual`.
826
876
  var eq = function(a, b, aStack, bStack) {
827
877
  // Identical objects are equal. `0 === -0`, but they aren't identical.
828
- // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
878
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
829
879
  if (a === b) return a !== 0 || 1 / a == 1 / b;
830
880
  // A strict comparison is necessary because `null == undefined`.
831
881
  if (a == null || b == null) return a === b;
@@ -854,9 +904,9 @@
854
904
  // RegExps are compared by their source patterns and flags.
855
905
  case '[object RegExp]':
856
906
  return a.source == b.source &&
857
- a.global == b.global &&
858
- a.multiline == b.multiline &&
859
- a.ignoreCase == b.ignoreCase;
907
+ a.global == b.global &&
908
+ a.multiline == b.multiline &&
909
+ a.ignoreCase == b.ignoreCase;
860
910
  }
861
911
  if (typeof a != 'object' || typeof b != 'object') return false;
862
912
  // Assume equality for cyclic structures. The algorithm for detecting cyclic
@@ -867,6 +917,13 @@
867
917
  // unique nested structures.
868
918
  if (aStack[length] == a) return bStack[length] == b;
869
919
  }
920
+ // Objects with different constructors are not equivalent, but `Object`s
921
+ // from different frames are.
922
+ var aCtor = a.constructor, bCtor = b.constructor;
923
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
924
+ _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
925
+ return false;
926
+ }
870
927
  // Add the first object to the stack of traversed objects.
871
928
  aStack.push(a);
872
929
  bStack.push(b);
@@ -883,13 +940,6 @@
883
940
  }
884
941
  }
885
942
  } else {
886
- // Objects with different constructors are not equivalent, but `Object`s
887
- // from different frames are.
888
- var aCtor = a.constructor, bCtor = b.constructor;
889
- if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
890
- _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
891
- return false;
892
- }
893
943
  // Deep compare objects.
894
944
  for (var key in a) {
895
945
  if (_.has(a, key)) {
@@ -1013,7 +1063,7 @@
1013
1063
 
1014
1064
  // Run a function **n** times.
1015
1065
  _.times = function(n, iterator, context) {
1016
- var accum = Array(n);
1066
+ var accum = Array(Math.max(0, n));
1017
1067
  for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
1018
1068
  return accum;
1019
1069
  };
@@ -1034,8 +1084,7 @@
1034
1084
  '<': '&lt;',
1035
1085
  '>': '&gt;',
1036
1086
  '"': '&quot;',
1037
- "'": '&#x27;',
1038
- '/': '&#x2F;'
1087
+ "'": '&#x27;'
1039
1088
  }
1040
1089
  };
1041
1090
  entityMap.unescape = _.invert(entityMap.escape);
@@ -1056,17 +1105,17 @@
1056
1105
  };
1057
1106
  });
1058
1107
 
1059
- // If the value of the named property is a function then invoke it;
1060
- // otherwise, return it.
1108
+ // If the value of the named `property` is a function then invoke it with the
1109
+ // `object` as context; otherwise, return it.
1061
1110
  _.result = function(object, property) {
1062
- if (object == null) return null;
1111
+ if (object == null) return void 0;
1063
1112
  var value = object[property];
1064
1113
  return _.isFunction(value) ? value.call(object) : value;
1065
1114
  };
1066
1115
 
1067
1116
  // Add your own custom functions to the Underscore object.
1068
1117
  _.mixin = function(obj) {
1069
- each(_.functions(obj), function(name){
1118
+ each(_.functions(obj), function(name) {
1070
1119
  var func = _[name] = obj[name];
1071
1120
  _.prototype[name] = function() {
1072
1121
  var args = [this._wrapped];
@@ -1130,7 +1179,7 @@
1130
1179
  var source = "__p+='";
1131
1180
  text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1132
1181
  source += text.slice(index, offset)
1133
- .replace(escaper, function(match) { return '\\' + escapes[match]; });
1182
+ .replace(escaper, function(match) { return '\\' + escapes[match]; });
1134
1183
 
1135
1184
  if (escape) {
1136
1185
  source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
@@ -1150,8 +1199,8 @@
1150
1199
  if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
1151
1200
 
1152
1201
  source = "var __t,__p='',__j=Array.prototype.join," +
1153
- "print=function(){__p+=__j.call(arguments,'');};\n" +
1154
- source + "return __p;\n";
1202
+ "print=function(){__p+=__j.call(arguments,'');};\n" +
1203
+ source + "return __p;\n";
1155
1204
 
1156
1205
  try {
1157
1206
  render = new Function(settings.variable || 'obj', '_', source);
@@ -1224,4 +1273,4 @@
1224
1273
 
1225
1274
  });
1226
1275
 
1227
- }).call(this);
1276
+ }).call(this);
@@ -494,7 +494,7 @@
494
494
  slugify: function(str) {
495
495
  if (str == null) return '';
496
496
 
497
- var from = "ąà áäâãåæćęèéëêìíïîłńòóöôõøùúüûñçżź",
497
+ var from = "ąàáäâãåæćęèéëêìíïîłńòóöôõøùúüûñçżź",
498
498
  to = "aaaaaaaaceeeeeiiiilnoooooouuuunczz",
499
499
  regex = new RegExp(defaultToWhiteSpace(from), 'g');
500
500
 
@@ -597,4 +597,4 @@
597
597
  root._.string = root._.str = _s;
598
598
  }
599
599
 
600
- }(this, String);
600
+ }(this, String);
metadata CHANGED
@@ -1,94 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: underscore_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
5
- prerelease:
4
+ version: 0.2.5
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ryan Dy
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-03-29 00:00:00.000000000 Z
11
+ date: 2014-01-23 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: fuubar
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: jasmine
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: 1.3.2
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: 1.3.2
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: jshint_on_rails
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: thin
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rails
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '3.1'
86
76
  type: :runtime
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '3.1'
94
83
  description: Adds extensions to the underscore javascript library. It adds the javascript
@@ -101,7 +90,8 @@ extensions: []
101
90
  extra_rdoc_files: []
102
91
  files:
103
92
  - .gitignore
104
- - .rvmrc
93
+ - .ruby-gemset
94
+ - .ruby-version
105
95
  - .travis.yml
106
96
  - Gemfile
107
97
  - README.markdown
@@ -119,33 +109,26 @@ files:
119
109
  - vendor/assets/javascripts/underscore.string.js
120
110
  homepage: http://github.com/rdy/underscore_extensions
121
111
  licenses: []
112
+ metadata: {}
122
113
  post_install_message:
123
114
  rdoc_options: []
124
115
  require_paths:
125
116
  - lib
126
117
  required_ruby_version: !ruby/object:Gem::Requirement
127
- none: false
128
118
  requirements:
129
- - - ! '>='
119
+ - - '>='
130
120
  - !ruby/object:Gem::Version
131
121
  version: '0'
132
- segments:
133
- - 0
134
- hash: 1293456751333068915
135
122
  required_rubygems_version: !ruby/object:Gem::Requirement
136
- none: false
137
123
  requirements:
138
- - - ! '>='
124
+ - - '>='
139
125
  - !ruby/object:Gem::Version
140
126
  version: '0'
141
- segments:
142
- - 0
143
- hash: 1293456751333068915
144
127
  requirements: []
145
128
  rubyforge_project: underscore_extensions
146
- rubygems_version: 1.8.24
129
+ rubygems_version: 2.2.1
147
130
  signing_key:
148
- specification_version: 3
131
+ specification_version: 4
149
132
  summary: Extensions to underscore javascript library as a rails engine
150
133
  test_files:
151
134
  - spec/javascripts/support/jasmine.yml
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm 1.9.3@underscore_extensions --create