sugar-rails 1.3.6 → 1.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. data/lib/sugar/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/precompiled/development/array.js +15 -7
  3. data/vendor/assets/javascripts/precompiled/development/core.js +4 -0
  4. data/vendor/assets/javascripts/precompiled/development/date.js +46 -12
  5. data/vendor/assets/javascripts/precompiled/development/date_ranges.js +13 -0
  6. data/vendor/assets/javascripts/precompiled/development/es5.js +0 -1
  7. data/vendor/assets/javascripts/precompiled/development/inflections.js +3 -2
  8. data/vendor/assets/javascripts/precompiled/development/object.js +75 -5
  9. data/vendor/assets/javascripts/precompiled/development/string.js +52 -40
  10. data/vendor/assets/javascripts/precompiled/minified/array.js +18 -17
  11. data/vendor/assets/javascripts/precompiled/minified/core.js +7 -7
  12. data/vendor/assets/javascripts/precompiled/minified/date.js +40 -40
  13. data/vendor/assets/javascripts/precompiled/minified/date_ranges.js +3 -2
  14. data/vendor/assets/javascripts/precompiled/minified/es5.js +6 -6
  15. data/vendor/assets/javascripts/precompiled/minified/function.js +3 -3
  16. data/vendor/assets/javascripts/precompiled/minified/inflections.js +7 -7
  17. data/vendor/assets/javascripts/precompiled/minified/language.js +8 -8
  18. data/vendor/assets/javascripts/precompiled/minified/number.js +5 -5
  19. data/vendor/assets/javascripts/precompiled/minified/object.js +5 -5
  20. data/vendor/assets/javascripts/precompiled/minified/regexp.js +2 -2
  21. data/vendor/assets/javascripts/precompiled/minified/string.js +11 -11
  22. data/vendor/assets/javascripts/sugar-development.js +209 -68
  23. data/vendor/assets/javascripts/sugar-full.js +116 -114
  24. data/vendor/assets/javascripts/sugar.js +101 -99
  25. metadata +4 -4
@@ -1,6 +1,6 @@
1
1
  module Sugar
2
2
  module Rails
3
- VERSION = "1.3.6"
4
- SUGARJS_VERSION = "1.3.6"
3
+ VERSION = "1.3.7"
4
+ SUGARJS_VERSION = "1.3.7"
5
5
  end
6
6
  end
@@ -195,8 +195,11 @@
195
195
  min = which === 'min',
196
196
  isArray = Array.isArray(obj);
197
197
  iterateOverObject(obj, function(key) {
198
- var el = obj[key];
199
- var test = transformArgument(el, map, obj, isArray ? [el, parseInt(key), obj] : []);
198
+ var el = obj[key],
199
+ test = transformArgument(el, map, obj, isArray ? [el, parseInt(key), obj] : []);
200
+ if(isUndefined(test)) {
201
+ throw new TypeError('Cannot compare with undefined');
202
+ }
200
203
  if(test === edge) {
201
204
  result.push(el);
202
205
  } else if(isUndefined(edge) || (max && test > edge) || (min && test < edge)) {
@@ -322,7 +325,7 @@
322
325
  if(tmp.length > 0) {
323
326
  a = tmp;
324
327
  }
325
- } catch(e) {}
328
+ } catch(e) {};
326
329
  }
327
330
  result = result.concat(a);
328
331
  });
@@ -468,7 +471,7 @@
468
471
  /***
469
472
  * @method clone()
470
473
  * @returns Array
471
- * @short Clones the array.
474
+ * @short Makes a shallow clone of the array.
472
475
  * @example
473
476
  *
474
477
  * [1,2,3].clone() -> [1,2,3]
@@ -1187,9 +1190,14 @@
1187
1190
 
1188
1191
  });
1189
1192
 
1193
+ var EnumerableFindingMethods = 'any,all,none,count,find,findAll,isEmpty'.split(',');
1194
+ var EnumerableMappingMethods = 'sum,average,min,max,least,most'.split(',');
1195
+ var EnumerableOtherMethods = 'map,reduce,size'.split(',');
1196
+ var EnumerableMethods = EnumerableFindingMethods.concat(EnumerableMappingMethods).concat(EnumerableOtherMethods);
1197
+
1190
1198
  buildEnhancements();
1191
1199
  buildAlphanumericSort();
1192
- buildEnumerableMethods('any,all,none,count,find,findAll,isEmpty');
1193
- buildEnumerableMethods('sum,average,min,max,least,most', true);
1194
- buildObjectInstanceMethods('map,reduce,size', Hash);
1200
+ buildEnumerableMethods(EnumerableFindingMethods);
1201
+ buildEnumerableMethods(EnumerableMappingMethods, true);
1202
+ buildObjectInstanceMethods(EnumerableOtherMethods, Hash);
1195
1203
 
@@ -120,6 +120,10 @@
120
120
  return result;
121
121
  }
122
122
 
123
+ function flattenedArgs(obj, fn, from) {
124
+ multiArgs(array.prototype.concat.apply([], array.prototype.slice.call(obj, from || 0)), fn);
125
+ }
126
+
123
127
  function checkCallback(fn) {
124
128
  if(!fn || !fn.call) {
125
129
  throw new TypeError('Callback is not callable');
@@ -151,7 +151,8 @@
151
151
  }
152
152
  }
153
153
  return days * 24 * 60 * 60 * 1000;
154
- }
154
+ },
155
+ error: 0.919
155
156
  },
156
157
  {
157
158
  unit: 'week',
@@ -586,9 +587,11 @@
586
587
  d.utc(forceUTC);
587
588
 
588
589
  if(isDate(f)) {
589
- d = new date(f.getTime());
590
+ // If the source here is already a date object, then the operation
591
+ // is the same as cloning the date, which preserves the UTC flag.
592
+ d.utc(f.isUTC()).setTime(f.getTime());
590
593
  } else if(isNumber(f)) {
591
- d = new date(f);
594
+ d.setTime(f);
592
595
  } else if(isObject(f)) {
593
596
  d.set(f, true);
594
597
  set = f;
@@ -749,6 +752,11 @@
749
752
  // The Date constructor does something tricky like checking the number
750
753
  // of arguments so simply passing in undefined won't work.
751
754
  d = f ? new date(f) : new date();
755
+ if(forceUTC) {
756
+ // Falling back to system date here which cannot be parsed as UTC,
757
+ // so if we're forcing UTC then simply add the offset.
758
+ d.addMinutes(d.getTimezoneOffset());
759
+ }
752
760
  } else if(relative) {
753
761
  d.advance(set);
754
762
  } else {
@@ -779,9 +787,13 @@
779
787
  if(after) {
780
788
  after();
781
789
  }
782
-
790
+ // A date created by parsing a string presumes that the format *itself* is UTC, but
791
+ // not that the date, once created, should be manipulated as such. In other words,
792
+ // if you are creating a date object from a server time "2012-11-15T12:00:00Z",
793
+ // in the majority of cases you are using it to create a date that will, after creation,
794
+ // be manipulated as local, so reset the utc flag here.
795
+ d.utc(false);
783
796
  }
784
- d.utc(false);
785
797
  return {
786
798
  date: d,
787
799
  set: set
@@ -1283,11 +1295,33 @@
1283
1295
  extendSimilar(date, true, false, DateUnits, function(methods, u, i) {
1284
1296
  var unit = u.unit, caps = simpleCapitalize(unit), multiplier = u.multiplier(), since, until;
1285
1297
  u.addMethod = 'add' + caps + 's';
1298
+ // "since/until now" only count "past" an integer, i.e. "2 days ago" is
1299
+ // anything between 2 - 2.999 days. The default margin of error is 0.999,
1300
+ // but "months" have an inherently larger margin, as the number of days
1301
+ // in a given month may be significantly less than the number of days in
1302
+ // the average month, so for example "30 days" before March 15 may in fact
1303
+ // be 1 month ago. Years also have a margin of error due to leap years,
1304
+ // but this is roughly 0.999 anyway (365 / 365.25). Other units do not
1305
+ // technically need the error margin applied to them but this accounts
1306
+ // for discrepancies like (15).hoursAgo() which technically creates the
1307
+ // current date first, then creates a date 15 hours before and compares
1308
+ // them, the discrepancy between the creation of the 2 dates means that
1309
+ // they may actually be 15.0001 hours apart. Milliseconds don't have
1310
+ // fractions, so they won't be subject to this error margin.
1311
+ function applyErrorMargin(ms) {
1312
+ var num = ms / multiplier,
1313
+ fraction = num % 1,
1314
+ error = u.error || 0.999;
1315
+ if(fraction && math.abs(fraction % 1) > error) {
1316
+ num = round(num);
1317
+ }
1318
+ return parseInt(num);
1319
+ }
1286
1320
  since = function(f, localeCode) {
1287
- return round((this.getTime() - date.create(f, localeCode).getTime()) / multiplier);
1321
+ return applyErrorMargin(this.getTime() - date.create(f, localeCode).getTime());
1288
1322
  };
1289
1323
  until = function(f, localeCode) {
1290
- return round((date.create(f, localeCode).getTime() - this.getTime()) / multiplier);
1324
+ return applyErrorMargin(date.create(f, localeCode).getTime() - this.getTime());
1291
1325
  };
1292
1326
  methods[unit+'sAgo'] = until;
1293
1327
  methods[unit+'sUntil'] = until;
@@ -1676,7 +1710,7 @@
1676
1710
  *
1677
1711
  ***/
1678
1712
  'utc': function(set) {
1679
- this._utc = set === true || arguments.length === 0;
1713
+ defineProperty(this, '_utc', set === true || arguments.length === 0);
1680
1714
  return this;
1681
1715
  },
1682
1716
 
@@ -1684,11 +1718,11 @@
1684
1718
  * @method isUTC()
1685
1719
  * @returns Boolean
1686
1720
  * @short Returns true if the date has no timezone offset.
1687
- * @extra This will also return true for a date that has had %toUTC% called on it. This is intended to help approximate shifting timezones which is not possible in client-side Javascript. Note that the native method %getTimezoneOffset% will always report the same thing, even if %isUTC% becomes true.
1721
+ * @extra This will also return true for utc-based dates (dates that have the %utc% method set true). Note that even if the utc flag is set, %getTimezoneOffset% will always report the same thing as Javascript always reports that based on the environment's locale.
1688
1722
  * @example
1689
1723
  *
1690
- * new Date().isUTC() -> true or false?
1691
- * new Date().toUTC().isUTC() -> true
1724
+ * new Date().isUTC() -> true or false?
1725
+ * new Date().utc(true).isUTC() -> true
1692
1726
  *
1693
1727
  ***/
1694
1728
  'isUTC': function() {
@@ -1940,7 +1974,7 @@
1940
1974
  ***/
1941
1975
  'clone': function() {
1942
1976
  var d = new date(this.getTime());
1943
- d._utc = this._utc;
1977
+ d.utc(this.isUTC());
1944
1978
  return d;
1945
1979
  }
1946
1980
 
@@ -144,6 +144,19 @@
144
144
  this.start > range.start ? this.start : range.start,
145
145
  this.end < range.end ? this.end : range.end
146
146
  );
147
+ },
148
+
149
+ /***
150
+ * @method clone()
151
+ * @returns DateRange
152
+ * @short Clones the DateRange.
153
+ * @example
154
+ *
155
+ * Date.range('2003-01', '2005-01').intersect(Date.range('2004-01', '2006-01')) -> Jan 1, 2004..Jan 1, 2005
156
+ *
157
+ ***/
158
+ 'clone': function(range) {
159
+ return new DateRange(this.start, this.end);
147
160
  }
148
161
 
149
162
  });
@@ -93,7 +93,6 @@
93
93
 
94
94
 
95
95
 
96
-
97
96
  extend(array, false, false, {
98
97
 
99
98
  /***
@@ -345,10 +345,11 @@
345
345
  *
346
346
  ***/
347
347
  'humanize': function() {
348
- var str = runReplacements(this, humans);
348
+ var str = runReplacements(this, humans), acronym;
349
349
  str = str.replace(/_id$/g, '');
350
350
  str = str.replace(/(_)?([a-z\d]*)/gi, function(match, _, word){
351
- return (_ ? ' ' : '') + (acronyms[word] || word.toLowerCase());
351
+ acronym = hasOwnProperty(acronyms, word) ? acronyms[word] : null;
352
+ return (_ ? ' ' : '') + (acronym || word.toLowerCase());
352
353
  });
353
354
  return capitalize(str);
354
355
  },
@@ -9,7 +9,7 @@
9
9
  ***/
10
10
 
11
11
  var ObjectTypeMethods = 'isObject,isNaN'.split(',');
12
- var ObjectHashMethods = 'keys,values,each,merge,clone,equal,watch,tap,has'.split(',');
12
+ var ObjectHashMethods = 'keys,values,select,reject,each,merge,clone,equal,watch,tap,has'.split(',');
13
13
 
14
14
  function setParamsObject(obj, param, value, deep) {
15
15
  var reg = /^(.+?)(\[.*\])$/, paramIsArray, match, allKeys, key;
@@ -19,7 +19,7 @@
19
19
  allKeys.forEach(function(k) {
20
20
  paramIsArray = !k || k.match(/^\d+$/);
21
21
  if(!key && isArray(obj)) key = obj.length;
22
- if(!obj[key]) {
22
+ if(!hasOwnProperty(obj, key)) {
23
23
  obj[key] = paramIsArray ? [] : {};
24
24
  }
25
25
  obj = obj[key];
@@ -38,6 +38,32 @@
38
38
  }
39
39
  }
40
40
 
41
+ function matchKey(key, match) {
42
+ if(isRegExp(match)) {
43
+ return match.test(key);
44
+ } else if(isObjectPrimitive(match)) {
45
+ return hasOwnProperty(match, key);
46
+ } else {
47
+ return key === string(match);
48
+ }
49
+ }
50
+
51
+ function selectFromObject(obj, args, select) {
52
+ var result = {}, match;
53
+ iterateOverObject(obj, function(key, value) {
54
+ match = false;
55
+ flattenedArgs(args, function(arg) {
56
+ if(matchKey(key, arg)) {
57
+ match = true;
58
+ }
59
+ }, 1);
60
+ if(match === select) {
61
+ result[key] = value;
62
+ }
63
+ });
64
+ return result;
65
+ }
66
+
41
67
 
42
68
  /***
43
69
  * @method Object.is[Type](<obj>)
@@ -77,7 +103,11 @@
77
103
  function buildObjectExtend() {
78
104
  extend(object, false, function(){ return arguments.length === 0; }, {
79
105
  'extend': function() {
80
- buildObjectInstanceMethods(ObjectTypeMethods.concat(ObjectHashMethods), object);
106
+ var methods = ObjectTypeMethods.concat(ObjectHashMethods)
107
+ if(typeof EnumerableMethods !== 'undefined') {
108
+ methods = methods.concat(EnumerableMethods);
109
+ }
110
+ buildObjectInstanceMethods(methods, object);
81
111
  }
82
112
  });
83
113
  }
@@ -271,9 +301,13 @@
271
301
  *
272
302
  ***/
273
303
  'clone': function(obj, deep) {
304
+ var target;
274
305
  if(!isObjectPrimitive(obj)) return obj;
275
- if(array.isArray(obj)) return obj.concat();
276
- var target = obj instanceof Hash ? new Hash() : {};
306
+ if (obj instanceof Hash) {
307
+ target = new Hash;
308
+ } else {
309
+ target = new obj.constructor;
310
+ }
277
311
  return object.merge(target, obj, deep);
278
312
  },
279
313
 
@@ -338,6 +372,42 @@
338
372
  ***/
339
373
  'has': function (obj, key) {
340
374
  return hasOwnProperty(obj, key);
375
+ },
376
+
377
+ /***
378
+ * @method select(<obj>, <find>, ...)
379
+ * @returns Object
380
+ * @short Builds a new object containing the values specified in <find>.
381
+ * @extra When <find> is a string, that single key will be selected. It can also be a regex, selecting any key that matches, or an object which will match if the key also exists in that object, effectively doing an "intersect" operation on that object. Multiple selections may also be passed as an array or directly as enumerated arguments. %select% is available as an instance method on extended objects.
382
+ * @example
383
+ *
384
+ * Object.select({a:1,b:2}, 'a') -> {a:1}
385
+ * Object.select({a:1,b:2}, /[a-z]/) -> {a:1,ba:2}
386
+ * Object.select({a:1,b:2}, {a:1}) -> {a:1}
387
+ * Object.select({a:1,b:2}, 'a', 'b') -> {a:1,b:2}
388
+ * Object.select({a:1,b:2}, ['a', 'b']) -> {a:1,b:2}
389
+ *
390
+ ***/
391
+ 'select': function (obj) {
392
+ return selectFromObject(obj, arguments, true);
393
+ },
394
+
395
+ /***
396
+ * @method reject(<obj>, <find>, ...)
397
+ * @returns Object
398
+ * @short Builds a new object containing all values except those specified in <find>.
399
+ * @extra When <find> is a string, that single key will be rejected. It can also be a regex, rejecting any key that matches, or an object which will match if the key also exists in that object, effectively "subtracting" that object. Multiple selections may also be passed as an array or directly as enumerated arguments. %reject% is available as an instance method on extended objects.
400
+ * @example
401
+ *
402
+ * Object.reject({a:1,b:2}, 'a') -> {b:2}
403
+ * Object.reject({a:1,b:2}, /[a-z]/) -> {}
404
+ * Object.reject({a:1,b:2}, {a:1}) -> {b:2}
405
+ * Object.reject({a:1,b:2}, 'a', 'b') -> {}
406
+ * Object.reject({a:1,b:2}, ['a', 'b']) -> {}
407
+ *
408
+ ***/
409
+ 'reject': function (obj) {
410
+ return selectFromObject(obj, arguments, false);
341
411
  }
342
412
 
343
413
  });
@@ -92,6 +92,56 @@
92
92
  }
93
93
  }
94
94
 
95
+
96
+ extend(string, true, function(reg) { return isRegExp(reg) || arguments.length > 2; }, {
97
+
98
+ /***
99
+ * @method startsWith(<find>, [pos] = 0, [case] = true)
100
+ * @returns Boolean
101
+ * @short Returns true if the string starts with <find>.
102
+ * @extra <find> may be either a string or regex. Search begins at [pos], which defaults to the entire string. Case sensitive if [case] is true.
103
+ * @example
104
+ *
105
+ * 'hello'.startsWith('hell') -> true
106
+ * 'hello'.startsWith(/[a-h]/) -> true
107
+ * 'hello'.startsWith('HELL') -> false
108
+ * 'hello'.startsWith('ell', 1) -> true
109
+ * 'hello'.startsWith('HELL', 0, false) -> true
110
+ *
111
+ ***/
112
+ 'startsWith': function(reg, pos, c) {
113
+ var str = this, source;
114
+ if(pos) str = str.slice(pos);
115
+ if(isUndefined(c)) c = true;
116
+ source = isRegExp(reg) ? reg.source.replace('^', '') : escapeRegExp(reg);
117
+ return regexp('^' + source, c ? '' : 'i').test(str);
118
+ },
119
+
120
+ /***
121
+ * @method endsWith(<find>, [pos] = length, [case] = true)
122
+ * @returns Boolean
123
+ * @short Returns true if the string ends with <find>.
124
+ * @extra <find> may be either a string or regex. Search ends at [pos], which defaults to the entire string. Case sensitive if [case] is true.
125
+ * @example
126
+ *
127
+ * 'jumpy'.endsWith('py') -> true
128
+ * 'jumpy'.endsWith(/[q-z]/) -> true
129
+ * 'jumpy'.endsWith('MPY') -> false
130
+ * 'jumpy'.endsWith('mp', 4) -> false
131
+ * 'jumpy'.endsWith('MPY', 5, false) -> true
132
+ *
133
+ ***/
134
+ 'endsWith': function(reg, pos, c) {
135
+ var str = this, source;
136
+ if(isDefined(pos)) str = str.slice(0, pos);
137
+ if(isUndefined(c)) c = true;
138
+ source = isRegExp(reg) ? reg.source.replace('$', '') : escapeRegExp(reg);
139
+ return regexp(source + '$', c ? '' : 'i').test(str);
140
+ }
141
+
142
+ });
143
+
144
+
95
145
  extend(string, true, false, {
96
146
 
97
147
  /***
@@ -354,44 +404,6 @@
354
404
  return paragraphs;
355
405
  },
356
406
 
357
- /***
358
- * @method startsWith(<find>, [case] = true)
359
- * @returns Boolean
360
- * @short Returns true if the string starts with <find>.
361
- * @extra <find> may be either a string or regex. Case sensitive if [case] is true.
362
- * @example
363
- *
364
- * 'hello'.startsWith('hell') -> true
365
- * 'hello'.startsWith(/[a-h]/) -> true
366
- * 'hello'.startsWith('HELL') -> false
367
- * 'hello'.startsWith('HELL', false) -> true
368
- *
369
- ***/
370
- 'startsWith': function(reg, c) {
371
- if(isUndefined(c)) c = true;
372
- var source = isRegExp(reg) ? reg.source.replace('^', '') : escapeRegExp(reg);
373
- return regexp('^' + source, c ? '' : 'i').test(this);
374
- },
375
-
376
- /***
377
- * @method endsWith(<find>, [case] = true)
378
- * @returns Boolean
379
- * @short Returns true if the string ends with <find>.
380
- * @extra <find> may be either a string or regex. Case sensitive if [case] is true.
381
- * @example
382
- *
383
- * 'jumpy'.endsWith('py') -> true
384
- * 'jumpy'.endsWith(/[q-z]/) -> true
385
- * 'jumpy'.endsWith('MPY') -> false
386
- * 'jumpy'.endsWith('MPY', false) -> true
387
- *
388
- ***/
389
- 'endsWith': function(reg, c) {
390
- if(isUndefined(c)) c = true;
391
- var source = isRegExp(reg) ? reg.source.replace('$', '') : escapeRegExp(reg);
392
- return regexp(source + '$', c ? '' : 'i').test(this);
393
- },
394
-
395
407
  /***
396
408
  * @method isBlank()
397
409
  * @returns Boolean
@@ -617,7 +629,7 @@
617
629
  ***/
618
630
  'stripTags': function() {
619
631
  var str = this, args = arguments.length > 0 ? arguments : [''];
620
- multiArgs(args, function(tag) {
632
+ flattenedArgs(args, function(tag) {
621
633
  str = str.replace(regexp('<\/?' + escapeRegExp(tag) + '[^<>]*>', 'gi'), '');
622
634
  });
623
635
  return str;
@@ -636,7 +648,7 @@
636
648
  ***/
637
649
  'removeTags': function() {
638
650
  var str = this, args = arguments.length > 0 ? arguments : ['\\S+'];
639
- multiArgs(args, function(t) {
651
+ flattenedArgs(args, function(t) {
640
652
  var reg = regexp('<(' + t + ')[^<>]*(?:\\/>|>.*?<\\/\\1>)', 'gi');
641
653
  str = str.replace(reg, '');
642
654
  });