sugar-rails 1.3.7 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/README.md +3 -50
  5. data/{vendor → app}/assets/javascripts/sugar-development.js +1914 -1225
  6. data/app/assets/javascripts/sugar-full.js +200 -0
  7. data/app/assets/javascripts/sugar.js +132 -0
  8. data/copy_release.sh +4 -7
  9. data/lib/sugar/rails/version.rb +2 -2
  10. metadata +16 -58
  11. data/.rvmrc +0 -1
  12. data/lib/generators/sugar/build/build_generator.rb +0 -107
  13. data/lib/generators/sugar/install/install_generator.rb +0 -35
  14. data/vendor/assets/javascripts/precompiled/development/array.js +0 -1203
  15. data/vendor/assets/javascripts/precompiled/development/core.js +0 -365
  16. data/vendor/assets/javascripts/precompiled/development/date.js +0 -2267
  17. data/vendor/assets/javascripts/precompiled/development/date_locales.js +0 -1179
  18. data/vendor/assets/javascripts/precompiled/development/date_ranges.js +0 -208
  19. data/vendor/assets/javascripts/precompiled/development/es5.js +0 -474
  20. data/vendor/assets/javascripts/precompiled/development/function.js +0 -224
  21. data/vendor/assets/javascripts/precompiled/development/inflections.js +0 -410
  22. data/vendor/assets/javascripts/precompiled/development/language.js +0 -383
  23. data/vendor/assets/javascripts/precompiled/development/number.js +0 -428
  24. data/vendor/assets/javascripts/precompiled/development/object.js +0 -419
  25. data/vendor/assets/javascripts/precompiled/development/regexp.js +0 -92
  26. data/vendor/assets/javascripts/precompiled/development/string.js +0 -894
  27. data/vendor/assets/javascripts/precompiled/minified/array.js +0 -18
  28. data/vendor/assets/javascripts/precompiled/minified/core.js +0 -9
  29. data/vendor/assets/javascripts/precompiled/minified/date.js +0 -44
  30. data/vendor/assets/javascripts/precompiled/minified/date_locales.js +0 -49
  31. data/vendor/assets/javascripts/precompiled/minified/date_ranges.js +0 -4
  32. data/vendor/assets/javascripts/precompiled/minified/es5.js +0 -8
  33. data/vendor/assets/javascripts/precompiled/minified/function.js +0 -4
  34. data/vendor/assets/javascripts/precompiled/minified/inflections.js +0 -11
  35. data/vendor/assets/javascripts/precompiled/minified/language.js +0 -19
  36. data/vendor/assets/javascripts/precompiled/minified/number.js +0 -5
  37. data/vendor/assets/javascripts/precompiled/minified/object.js +0 -6
  38. data/vendor/assets/javascripts/precompiled/minified/regexp.js +0 -2
  39. data/vendor/assets/javascripts/precompiled/minified/string.js +0 -12
  40. data/vendor/assets/javascripts/precompiled/readme.txt +0 -3
  41. data/vendor/assets/javascripts/sugar-full.js +0 -199
  42. data/vendor/assets/javascripts/sugar.js +0 -120
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm use 1.9.3@sugar-rails --create
@@ -1,107 +0,0 @@
1
- require "rails"
2
-
3
- module Sugar
4
- module Generators
5
- class BuildGenerator < ::Rails::Generators::Base
6
- source_root File.expand_path("../../../../../vendor/assets", __FILE__)
7
- argument :packages, :type => :array, :default => []
8
- class_option :minify, :type => :boolean, :default => false
9
-
10
- desc "Creates a custom Sugar build."
11
- def build
12
- return unless valid_rails_version?
13
-
14
- if packages.present?
15
- build_packages
16
- else
17
- display_help
18
- end
19
- end
20
-
21
-
22
- private
23
-
24
- def get_package_content(packages)
25
- type = options.minify? ? "minified" : "development"
26
- base_path = "javascripts/precompiled/#{type}"
27
-
28
- packages.each do |name|
29
- filename = find_in_source_paths "#{base_path}/#{name}.js"
30
- yield name, File.read(filename)
31
- end
32
- end
33
-
34
- def build_packages
35
- output = ""
36
- destination = "vendor/assets/javascripts/sugar-custom.js"
37
-
38
- say_status "", ""
39
- say_status "build", "Custom Sugar packages: #{packages.join(", ")}", :green
40
-
41
- remove_file destination
42
- packages.unshift("core") # add 'core' package to the top of the bulid
43
- get_package_content(packages) { |name, content| output << content }
44
- create_file destination, "(function() { #{output} })();"
45
-
46
- say_status "", ""
47
- say_status "success", "Add `//= require sugar-custom` to your app/assets/javascripts/application.js", :green
48
- say_status "", ""
49
- end
50
-
51
- def valid_rails_version?
52
- valid = ::Rails.version >= "3.1" && ::Rails.application.config.assets.enabled
53
-
54
- unless valid
55
- say_status "", ""
56
- say_status "error", "You are using Rails below version 3.1 or the Asset Pipeline is not enabled.", :red
57
- say_status "", "This generator requires Rails 3.1+ and the Asset Pipeline."
58
- say_status "", ""
59
- say_status "", "Please ensure that you are running a supported version of Rails."
60
- say_status "", "Yoy may need to enable the Asset Pipeline by setting `config.assets.enabled = true` in your `config/application.rb` file."
61
- end
62
-
63
- valid
64
- end
65
-
66
- def display_help
67
- default_packages = [
68
- :es5, :object, :array, :number, :regexp, :function, :date,
69
- :date_ranges, :date_locales, :string, :inflections, :language
70
- ]
71
-
72
- say_status "", ""
73
- say_status "[USAGE]", "rails g sugar:build package1 package2 ... [options]", :yellow
74
- say_status "", ""
75
- say_status "", "This script creates a custom Sugar build."
76
- say_status "", "You can include the following packages:"
77
- say_status "", ""
78
-
79
-
80
- get_package_content(default_packages) do |name, content|
81
- description = if name == :date_locales
82
- "Locale definitions: fr, it, es, pt, de, ru, pl, sv, ja, ko, zh-CN, zh-TW"
83
- else
84
- content[/@description (.+)$/, 1]
85
- end
86
-
87
- say_status "", "#{name.to_s.ljust(15)} #{description}"
88
- end
89
-
90
- say_status "", ""
91
- say_status "", "Dependencies must be met for your build to work properly:"
92
- say_status "", ""
93
- say_status "", "date < date_locales"
94
- say_status "", "date < date_ranges"
95
- say_status "", "string < inflections"
96
- say_status "", "string < language"
97
- say_status "", ""
98
- say_status "", "Note that all packages require proper ES5 support, however this package"
99
- say_status "", "can be omitted if you are only targeting modern browsers (ie. not < IE9)."
100
- say_status "", ""
101
- say_status "", "Also note that the core package is required and included by default."
102
- say_status "", "Custom builds can also be created at http://sugarjs.com/customize"
103
- say_status "", ""
104
- end
105
- end
106
- end
107
- end
@@ -1,35 +0,0 @@
1
- require "rails"
2
-
3
- # Supply generator for Rails 3.0.x or if asset pipeline is not enabled
4
- if ::Rails.version < "3.1" || !::Rails.application.config.assets.enabled
5
- module Sugar
6
- module Generators
7
- class InstallGenerator < ::Rails::Generators::Base
8
- desc "This generator installs Sugar #{Sugar::Rails::SUGARJS_VERSION}"
9
- source_root File.expand_path("../../../../../vendor/assets", __FILE__)
10
-
11
- def copy_javascript
12
- say_status("copying", "Sugar", :green)
13
- copy_file "javascripts/sugar.js", "public/javascripts/sugar.js"
14
- end
15
- end
16
- end
17
- end
18
- else
19
- module Sugar
20
- module Generators
21
- class InstallGenerator < ::Rails::Generators::Base
22
- desc "Just show instructions so people will know what to do when mistakenly using generator for Rails 3.1 apps"
23
-
24
- def do_nothing
25
- say_status("deprecated", "You are using Rails 3.1 with the asset pipeline enabled, so this generator is not needed.")
26
- say_status("", "The necessary files are already in your asset pipeline.")
27
- say_status("", "Just add `//= require sugar` to your app/assets/javascripts/application.js")
28
- say_status("", "If you upgraded your app from Rails 3.0 and still have sugar.js in your public assets folders, be sure to remove them.")
29
- say_status("", "If you do not want the asset pipeline enabled, you may turn it off in application.rb and re-run this generator.")
30
- # ok, nothing
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,1203 +0,0 @@
1
-
2
-
3
- /***
4
- * @package Array
5
- * @dependency core
6
- * @description Array manipulation and traversal, "fuzzy matching" against elements, alphanumeric sorting and collation, enumerable methods on Object.
7
- *
8
- ***/
9
-
10
-
11
- function multiMatch(el, match, scope, params) {
12
- var result = true;
13
- if(el === match) {
14
- // Match strictly equal values up front.
15
- return true;
16
- } else if(isRegExp(match) && isString(el)) {
17
- // Match against a regexp
18
- return regexp(match).test(el);
19
- } else if(isFunction(match)) {
20
- // Match against a filtering function
21
- return match.apply(scope, params);
22
- } else if(isObject(match) && isObjectPrimitive(el)) {
23
- // Match against a hash or array.
24
- iterateOverObject(match, function(key, value) {
25
- if(!multiMatch(el[key], match[key], scope, [el[key], el])) {
26
- result = false;
27
- }
28
- });
29
- return result;
30
- } else {
31
- return isEqual(el, match);
32
- }
33
- }
34
-
35
- function transformArgument(el, map, context, mapArgs) {
36
- if(isUndefined(map)) {
37
- return el;
38
- } else if(isFunction(map)) {
39
- return map.apply(context, mapArgs || []);
40
- } else if(isFunction(el[map])) {
41
- return el[map].call(el);
42
- } else {
43
- return el[map];
44
- }
45
- }
46
-
47
- // Basic array internal methods
48
-
49
- function arrayEach(arr, fn, startIndex, loop) {
50
- var length, index, i;
51
- if(startIndex < 0) startIndex = arr.length + startIndex;
52
- i = isNaN(startIndex) ? 0 : startIndex;
53
- length = loop === true ? arr.length + i : arr.length;
54
- while(i < length) {
55
- index = i % arr.length;
56
- if(!(index in arr)) {
57
- return iterateOverSparseArray(arr, fn, i, loop);
58
- } else if(fn.call(arr, arr[index], index, arr) === false) {
59
- break;
60
- }
61
- i++;
62
- }
63
- }
64
-
65
- function iterateOverSparseArray(arr, fn, fromIndex, loop) {
66
- var indexes = [], i;
67
- for(i in arr) {
68
- if(isArrayIndex(arr, i) && i >= fromIndex) {
69
- indexes.push(parseInt(i));
70
- }
71
- }
72
- indexes.sort().each(function(index) {
73
- return fn.call(arr, arr[index], index, arr);
74
- });
75
- return arr;
76
- }
77
-
78
- function isArrayIndex(arr, i) {
79
- return i in arr && toUInt32(i) == i && i != 0xffffffff;
80
- }
81
-
82
- function toUInt32(i) {
83
- return i >>> 0;
84
- }
85
-
86
- function arrayFind(arr, f, startIndex, loop, returnIndex) {
87
- var result, index;
88
- arrayEach(arr, function(el, i, arr) {
89
- if(multiMatch(el, f, arr, [el, i, arr])) {
90
- result = el;
91
- index = i;
92
- return false;
93
- }
94
- }, startIndex, loop);
95
- return returnIndex ? index : result;
96
- }
97
-
98
- function arrayUnique(arr, map) {
99
- var result = [], o = {}, transformed;
100
- arrayEach(arr, function(el, i) {
101
- transformed = map ? transformArgument(el, map, arr, [el, i, arr]) : el;
102
- if(!checkForElementInHashAndSet(o, transformed)) {
103
- result.push(el);
104
- }
105
- })
106
- return result;
107
- }
108
-
109
- function arrayIntersect(arr1, arr2, subtract) {
110
- var result = [], o = {};
111
- arr2.each(function(el) {
112
- checkForElementInHashAndSet(o, el);
113
- });
114
- arr1.each(function(el) {
115
- var stringified = stringify(el),
116
- isReference = !objectIsMatchedByValue(el);
117
- // Add the result to the array if:
118
- // 1. We're subtracting intersections or it doesn't already exist in the result and
119
- // 2. It exists in the compared array and we're adding, or it doesn't exist and we're removing.
120
- if(elementExistsInHash(o, stringified, el, isReference) != subtract) {
121
- discardElementFromHash(o, stringified, el, isReference);
122
- result.push(el);
123
- }
124
- });
125
- return result;
126
- }
127
-
128
- function arrayFlatten(arr, level, current) {
129
- level = level || Infinity;
130
- current = current || 0;
131
- var result = [];
132
- arrayEach(arr, function(el) {
133
- if(isArray(el) && current < level) {
134
- result = result.concat(arrayFlatten(el, level, current + 1));
135
- } else {
136
- result.push(el);
137
- }
138
- });
139
- return result;
140
- }
141
-
142
- function flatArguments(args) {
143
- var result = [];
144
- multiArgs(args, function(arg) {
145
- result = result.concat(arg);
146
- });
147
- return result;
148
- }
149
-
150
- function elementExistsInHash(hash, key, element, isReference) {
151
- var exists = key in hash;
152
- if(isReference) {
153
- if(!hash[key]) {
154
- hash[key] = [];
155
- }
156
- exists = hash[key].indexOf(element) !== -1;
157
- }
158
- return exists;
159
- }
160
-
161
- function checkForElementInHashAndSet(hash, element) {
162
- var stringified = stringify(element),
163
- isReference = !objectIsMatchedByValue(element),
164
- exists = elementExistsInHash(hash, stringified, element, isReference);
165
- if(isReference) {
166
- hash[stringified].push(element);
167
- } else {
168
- hash[stringified] = element;
169
- }
170
- return exists;
171
- }
172
-
173
- function discardElementFromHash(hash, key, element, isReference) {
174
- var arr, i = 0;
175
- if(isReference) {
176
- arr = hash[key];
177
- while(i < arr.length) {
178
- if(arr[i] === element) {
179
- arr.splice(i, 1);
180
- } else {
181
- i += 1;
182
- }
183
- }
184
- } else {
185
- delete hash[key];
186
- }
187
- }
188
-
189
- // Support methods
190
-
191
- function getMinOrMax(obj, map, which, all) {
192
- var edge,
193
- result = [],
194
- max = which === 'max',
195
- min = which === 'min',
196
- isArray = Array.isArray(obj);
197
- iterateOverObject(obj, function(key) {
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
- }
203
- if(test === edge) {
204
- result.push(el);
205
- } else if(isUndefined(edge) || (max && test > edge) || (min && test < edge)) {
206
- result = [el];
207
- edge = test;
208
- }
209
- });
210
- if(!isArray) result = arrayFlatten(result, 1);
211
- return all ? result : result[0];
212
- }
213
-
214
-
215
- // Alphanumeric collation helpers
216
-
217
- function collateStrings(a, b) {
218
- var aValue, bValue, aChar, bChar, aEquiv, bEquiv, index = 0, tiebreaker = 0;
219
- a = getCollationReadyString(a);
220
- b = getCollationReadyString(b);
221
- do {
222
- aChar = getCollationCharacter(a, index);
223
- bChar = getCollationCharacter(b, index);
224
- aValue = getCollationValue(aChar);
225
- bValue = getCollationValue(bChar);
226
- if(aValue === -1 || bValue === -1) {
227
- aValue = a.charCodeAt(index) || null;
228
- bValue = b.charCodeAt(index) || null;
229
- }
230
- aEquiv = aChar !== a.charAt(index);
231
- bEquiv = bChar !== b.charAt(index);
232
- if(aEquiv !== bEquiv && tiebreaker === 0) {
233
- tiebreaker = aEquiv - bEquiv;
234
- }
235
- index += 1;
236
- } while(aValue != null && bValue != null && aValue === bValue);
237
- if(aValue === bValue) return tiebreaker;
238
- return aValue < bValue ? -1 : 1;
239
- }
240
-
241
- function getCollationReadyString(str) {
242
- if(array[AlphanumericSortIgnoreCase]) {
243
- str = str.toLowerCase();
244
- }
245
- return str.replace(array[AlphanumericSortIgnore], '');
246
- }
247
-
248
- function getCollationCharacter(str, index) {
249
- var chr = str.charAt(index), eq = array[AlphanumericSortEquivalents] || {};
250
- return eq[chr] || chr;
251
- }
252
-
253
- function getCollationValue(chr) {
254
- var order = array[AlphanumericSortOrder];
255
- if(!chr) {
256
- return null;
257
- } else {
258
- return order.indexOf(chr);
259
- }
260
- }
261
-
262
- var AlphanumericSortOrder = 'AlphanumericSortOrder';
263
- var AlphanumericSortIgnore = 'AlphanumericSortIgnore';
264
- var AlphanumericSortIgnoreCase = 'AlphanumericSortIgnoreCase';
265
- var AlphanumericSortEquivalents = 'AlphanumericSortEquivalents';
266
-
267
-
268
-
269
- function buildEnhancements() {
270
- var callbackCheck = function() { var a = arguments; return a.length > 0 && !isFunction(a[0]); };
271
- extendSimilar(array, true, callbackCheck, 'map,every,all,some,any,none,filter', function(methods, name) {
272
- methods[name] = function(f) {
273
- return this[name](function(el, index) {
274
- if(name === 'map') {
275
- return transformArgument(el, f, this, [el, index, this]);
276
- } else {
277
- return multiMatch(el, f, this, [el, index, this]);
278
- }
279
- });
280
- }
281
- });
282
- }
283
-
284
- function buildAlphanumericSort() {
285
- var order = 'AÁÀÂÃĄBCĆČÇDĎÐEÉÈĚÊËĘFGĞHıIÍÌİÎÏJKLŁMNŃŇÑOÓÒÔPQRŘSŚŠŞTŤUÚÙŮÛÜVWXYÝZŹŻŽÞÆŒØÕÅÄÖ';
286
- var equiv = 'AÁÀÂÃÄ,CÇ,EÉÈÊË,IÍÌİÎÏ,OÓÒÔÕÖ,Sß,UÚÙÛÜ';
287
- array[AlphanumericSortOrder] = order.split('').map(function(str) {
288
- return str + str.toLowerCase();
289
- }).join('');
290
- var equivalents = {};
291
- arrayEach(equiv.split(','), function(set) {
292
- var equivalent = set.charAt(0);
293
- arrayEach(set.slice(1).split(''), function(chr) {
294
- equivalents[chr] = equivalent;
295
- equivalents[chr.toLowerCase()] = equivalent.toLowerCase();
296
- });
297
- });
298
- array[AlphanumericSortIgnoreCase] = true;
299
- array[AlphanumericSortEquivalents] = equivalents;
300
- }
301
-
302
- extend(array, false, false, {
303
-
304
- /***
305
- *
306
- * @method Array.create(<obj1>, <obj2>, ...)
307
- * @returns Array
308
- * @short Alternate array constructor.
309
- * @extra This method will create a single array by calling %concat% on all arguments passed. In addition to ensuring that an unknown variable is in a single, flat array (the standard constructor will create nested arrays, this one will not), it is also a useful shorthand to convert a function's arguments object into a standard array.
310
- * @example
311
- *
312
- * Array.create('one', true, 3) -> ['one', true, 3]
313
- * Array.create(['one', true, 3]) -> ['one', true, 3]
314
- + Array.create(function(n) {
315
- * return arguments;
316
- * }('howdy', 'doody'));
317
- *
318
- ***/
319
- 'create': function() {
320
- var result = [], tmp;
321
- multiArgs(arguments, function(a) {
322
- if(isObjectPrimitive(a)) {
323
- try {
324
- tmp = array.prototype.slice.call(a, 0);
325
- if(tmp.length > 0) {
326
- a = tmp;
327
- }
328
- } catch(e) {};
329
- }
330
- result = result.concat(a);
331
- });
332
- return result;
333
- }
334
-
335
- });
336
-
337
- extend(array, true, false, {
338
-
339
- /***
340
- * @method find(<f>, [index] = 0, [loop] = false)
341
- * @returns Mixed
342
- * @short Returns the first element that matches <f>.
343
- * @extra <f> will match a string, number, array, object, or alternately test against a function or regex. Starts at [index], and will continue once from index = 0 if [loop] is true. This method implements @array_matching.
344
- * @example
345
- *
346
- + [{a:1,b:2},{a:1,b:3},{a:1,b:4}].find(function(n) {
347
- * return n['a'] == 1;
348
- * }); -> {a:1,b:3}
349
- * ['cuba','japan','canada'].find(/^c/, 2) -> 'canada'
350
- *
351
- ***/
352
- 'find': function(f, index, loop) {
353
- return arrayFind(this, f, index, loop);
354
- },
355
-
356
- /***
357
- * @method findAll(<f>, [index] = 0, [loop] = false)
358
- * @returns Array
359
- * @short Returns all elements that match <f>.
360
- * @extra <f> will match a string, number, array, object, or alternately test against a function or regex. Starts at [index], and will continue once from index = 0 if [loop] is true. This method implements @array_matching.
361
- * @example
362
- *
363
- + [{a:1,b:2},{a:1,b:3},{a:2,b:4}].findAll(function(n) {
364
- * return n['a'] == 1;
365
- * }); -> [{a:1,b:3},{a:1,b:4}]
366
- * ['cuba','japan','canada'].findAll(/^c/) -> 'cuba','canada'
367
- * ['cuba','japan','canada'].findAll(/^c/, 2) -> 'canada'
368
- *
369
- ***/
370
- 'findAll': function(f, index, loop) {
371
- var result = [];
372
- arrayEach(this, function(el, i, arr) {
373
- if(multiMatch(el, f, arr, [el, i, arr])) {
374
- result.push(el);
375
- }
376
- }, index, loop);
377
- return result;
378
- },
379
-
380
- /***
381
- * @method findIndex(<f>, [startIndex] = 0, [loop] = false)
382
- * @returns Number
383
- * @short Returns the index of the first element that matches <f> or -1 if not found.
384
- * @extra This method has a few notable differences to native %indexOf%. Although <f> will similarly match a primitive such as a string or number, it will also match deep objects and arrays that are not equal by reference (%===%). Additionally, if a function is passed it will be run as a matching function (similar to the behavior of %Array#filter%) rather than attempting to find that function itself by reference in the array. Starts at [index], and will continue once from index = 0 if [loop] is true. This method implements @array_matching.
385
- * @example
386
- *
387
- + [1,2,3,4].findIndex(3); -> 2
388
- + [1,2,3,4].findIndex(function(n) {
389
- * return n % 2 == 0;
390
- * }); -> 1
391
- + ['one','two','three'].findIndex(/th/); -> 2
392
- *
393
- ***/
394
- 'findIndex': function(f, startIndex, loop) {
395
- var index = arrayFind(this, f, startIndex, loop, true);
396
- return isUndefined(index) ? -1 : index;
397
- },
398
-
399
- /***
400
- * @method count(<f>)
401
- * @returns Number
402
- * @short Counts all elements in the array that match <f>.
403
- * @extra <f> will match a string, number, array, object, or alternately test against a function or regex. This method implements @array_matching.
404
- * @example
405
- *
406
- * [1,2,3,1].count(1) -> 2
407
- * ['a','b','c'].count(/b/) -> 1
408
- + [{a:1},{b:2}].count(function(n) {
409
- * return n['a'] > 1;
410
- * }); -> 0
411
- *
412
- ***/
413
- 'count': function(f) {
414
- if(isUndefined(f)) return this.length;
415
- return this.findAll(f).length;
416
- },
417
-
418
- /***
419
- * @method removeAt(<start>, [end])
420
- * @returns Array
421
- * @short Removes element at <start>. If [end] is specified, removes the range between <start> and [end]. This method will change the array! If you don't intend the array to be changed use %clone% first.
422
- * @example
423
- *
424
- * ['a','b','c'].removeAt(0) -> ['b','c']
425
- * [1,2,3,4].removeAt(1, 3) -> [1]
426
- *
427
- ***/
428
- 'removeAt': function(start, end) {
429
- if(isUndefined(start)) return this;
430
- if(isUndefined(end)) end = start;
431
- for(var i = 0; i <= (end - start); i++) {
432
- this.splice(start, 1);
433
- }
434
- return this;
435
- },
436
-
437
- /***
438
- * @method include(<el>, [index])
439
- * @returns Array
440
- * @short Adds <el> to the array.
441
- * @extra This is a non-destructive alias for %add%. It will not change the original array.
442
- * @example
443
- *
444
- * [1,2,3,4].include(5) -> [1,2,3,4,5]
445
- * [1,2,3,4].include(8, 1) -> [1,8,2,3,4]
446
- * [1,2,3,4].include([5,6,7]) -> [1,2,3,4,5,6,7]
447
- *
448
- ***/
449
- 'include': function(el, index) {
450
- return this.clone().add(el, index);
451
- },
452
-
453
- /***
454
- * @method exclude([f1], [f2], ...)
455
- * @returns Array
456
- * @short Removes any element in the array that matches [f1], [f2], etc.
457
- * @extra This is a non-destructive alias for %remove%. It will not change the original array. This method implements @array_matching.
458
- * @example
459
- *
460
- * [1,2,3].exclude(3) -> [1,2]
461
- * ['a','b','c'].exclude(/b/) -> ['a','c']
462
- + [{a:1},{b:2}].exclude(function(n) {
463
- * return n['a'] == 1;
464
- * }); -> [{b:2}]
465
- *
466
- ***/
467
- 'exclude': function() {
468
- return array.prototype.remove.apply(this.clone(), arguments);
469
- },
470
-
471
- /***
472
- * @method clone()
473
- * @returns Array
474
- * @short Makes a shallow clone of the array.
475
- * @example
476
- *
477
- * [1,2,3].clone() -> [1,2,3]
478
- *
479
- ***/
480
- 'clone': function() {
481
- return simpleMerge([], this);
482
- },
483
-
484
- /***
485
- * @method unique([map] = null)
486
- * @returns Array
487
- * @short Removes all duplicate elements in the array.
488
- * @extra [map] may be a function mapping the value to be uniqued on or a string acting as a shortcut. This is most commonly used when you have a key that ensures the object's uniqueness, and don't need to check all fields. This method will also correctly operate on arrays of objects.
489
- * @example
490
- *
491
- * [1,2,2,3].unique() -> [1,2,3]
492
- * [{foo:'bar'},{foo:'bar'}].unique() -> [{foo:'bar'}]
493
- + [{foo:'bar'},{foo:'bar'}].unique(function(obj){
494
- * return obj.foo;
495
- * }); -> [{foo:'bar'}]
496
- * [{foo:'bar'},{foo:'bar'}].unique('foo') -> [{foo:'bar'}]
497
- *
498
- ***/
499
- 'unique': function(map) {
500
- return arrayUnique(this, map);
501
- },
502
-
503
- /***
504
- * @method flatten([limit] = Infinity)
505
- * @returns Array
506
- * @short Returns a flattened, one-dimensional copy of the array.
507
- * @extra You can optionally specify a [limit], which will only flatten that depth.
508
- * @example
509
- *
510
- * [[1], 2, [3]].flatten() -> [1,2,3]
511
- * [['a'],[],'b','c'].flatten() -> ['a','b','c']
512
- *
513
- ***/
514
- 'flatten': function(limit) {
515
- return arrayFlatten(this, limit);
516
- },
517
-
518
- /***
519
- * @method union([a1], [a2], ...)
520
- * @returns Array
521
- * @short Returns an array containing all elements in all arrays with duplicates removed.
522
- * @extra This method will also correctly operate on arrays of objects.
523
- * @example
524
- *
525
- * [1,3,5].union([5,7,9]) -> [1,3,5,7,9]
526
- * ['a','b'].union(['b','c']) -> ['a','b','c']
527
- *
528
- ***/
529
- 'union': function() {
530
- return arrayUnique(this.concat(flatArguments(arguments)));
531
- },
532
-
533
- /***
534
- * @method intersect([a1], [a2], ...)
535
- * @returns Array
536
- * @short Returns an array containing the elements all arrays have in common.
537
- * @extra This method will also correctly operate on arrays of objects.
538
- * @example
539
- *
540
- * [1,3,5].intersect([5,7,9]) -> [5]
541
- * ['a','b'].intersect('b','c') -> ['b']
542
- *
543
- ***/
544
- 'intersect': function() {
545
- return arrayIntersect(this, flatArguments(arguments), false);
546
- },
547
-
548
- /***
549
- * @method subtract([a1], [a2], ...)
550
- * @returns Array
551
- * @short Subtracts from the array all elements in [a1], [a2], etc.
552
- * @extra This method will also correctly operate on arrays of objects.
553
- * @example
554
- *
555
- * [1,3,5].subtract([5,7,9]) -> [1,3]
556
- * [1,3,5].subtract([3],[5]) -> [1]
557
- * ['a','b'].subtract('b','c') -> ['a']
558
- *
559
- ***/
560
- 'subtract': function(a) {
561
- return arrayIntersect(this, flatArguments(arguments), true);
562
- },
563
-
564
- /***
565
- * @method at(<index>, [loop] = true)
566
- * @returns Mixed
567
- * @short Gets the element(s) at a given index.
568
- * @extra When [loop] is true, overshooting the end of the array (or the beginning) will begin counting from the other end. As an alternate syntax, passing multiple indexes will get the elements at those indexes.
569
- * @example
570
- *
571
- * [1,2,3].at(0) -> 1
572
- * [1,2,3].at(2) -> 3
573
- * [1,2,3].at(4) -> 2
574
- * [1,2,3].at(4, false) -> null
575
- * [1,2,3].at(-1) -> 3
576
- * [1,2,3].at(0,1) -> [1,2]
577
- *
578
- ***/
579
- 'at': function() {
580
- return entryAtIndex(this, arguments);
581
- },
582
-
583
- /***
584
- * @method first([num] = 1)
585
- * @returns Mixed
586
- * @short Returns the first element(s) in the array.
587
- * @extra When <num> is passed, returns the first <num> elements in the array.
588
- * @example
589
- *
590
- * [1,2,3].first() -> 1
591
- * [1,2,3].first(2) -> [1,2]
592
- *
593
- ***/
594
- 'first': function(num) {
595
- if(isUndefined(num)) return this[0];
596
- if(num < 0) num = 0;
597
- return this.slice(0, num);
598
- },
599
-
600
- /***
601
- * @method last([num] = 1)
602
- * @returns Mixed
603
- * @short Returns the last element(s) in the array.
604
- * @extra When <num> is passed, returns the last <num> elements in the array.
605
- * @example
606
- *
607
- * [1,2,3].last() -> 3
608
- * [1,2,3].last(2) -> [2,3]
609
- *
610
- ***/
611
- 'last': function(num) {
612
- if(isUndefined(num)) return this[this.length - 1];
613
- var start = this.length - num < 0 ? 0 : this.length - num;
614
- return this.slice(start);
615
- },
616
-
617
- /***
618
- * @method from(<index>)
619
- * @returns Array
620
- * @short Returns a slice of the array from <index>.
621
- * @example
622
- *
623
- * [1,2,3].from(1) -> [2,3]
624
- * [1,2,3].from(2) -> [3]
625
- *
626
- ***/
627
- 'from': function(num) {
628
- return this.slice(num);
629
- },
630
-
631
- /***
632
- * @method to(<index>)
633
- * @returns Array
634
- * @short Returns a slice of the array up to <index>.
635
- * @example
636
- *
637
- * [1,2,3].to(1) -> [1]
638
- * [1,2,3].to(2) -> [1,2]
639
- *
640
- ***/
641
- 'to': function(num) {
642
- if(isUndefined(num)) num = this.length;
643
- return this.slice(0, num);
644
- },
645
-
646
- /***
647
- * @method min([map], [all] = false)
648
- * @returns Mixed
649
- * @short Returns the element in the array with the lowest value.
650
- * @extra [map] may be a function mapping the value to be checked or a string acting as a shortcut. If [all] is true, will return all min values in an array.
651
- * @example
652
- *
653
- * [1,2,3].min() -> 1
654
- * ['fee','fo','fum'].min('length') -> 'fo'
655
- * ['fee','fo','fum'].min('length', true) -> ['fo']
656
- + ['fee','fo','fum'].min(function(n) {
657
- * return n.length;
658
- * }); -> ['fo']
659
- + [{a:3,a:2}].min(function(n) {
660
- * return n['a'];
661
- * }); -> [{a:2}]
662
- *
663
- ***/
664
- 'min': function(map, all) {
665
- return getMinOrMax(this, map, 'min', all);
666
- },
667
-
668
- /***
669
- * @method max([map], [all] = false)
670
- * @returns Mixed
671
- * @short Returns the element in the array with the greatest value.
672
- * @extra [map] may be a function mapping the value to be checked or a string acting as a shortcut. If [all] is true, will return all max values in an array.
673
- * @example
674
- *
675
- * [1,2,3].max() -> 3
676
- * ['fee','fo','fum'].max('length') -> 'fee'
677
- * ['fee','fo','fum'].max('length', true) -> ['fee']
678
- + [{a:3,a:2}].max(function(n) {
679
- * return n['a'];
680
- * }); -> {a:3}
681
- *
682
- ***/
683
- 'max': function(map, all) {
684
- return getMinOrMax(this, map, 'max', all);
685
- },
686
-
687
- /***
688
- * @method least([map])
689
- * @returns Array
690
- * @short Returns the elements in the array with the least commonly occuring value.
691
- * @extra [map] may be a function mapping the value to be checked or a string acting as a shortcut.
692
- * @example
693
- *
694
- * [3,2,2].least() -> [3]
695
- * ['fe','fo','fum'].least('length') -> ['fum']
696
- + [{age:35,name:'ken'},{age:12,name:'bob'},{age:12,name:'ted'}].least(function(n) {
697
- * return n.age;
698
- * }); -> [{age:35,name:'ken'}]
699
- *
700
- ***/
701
- 'least': function(map, all) {
702
- return getMinOrMax(this.groupBy.apply(this, [map]), 'length', 'min', all);
703
- },
704
-
705
- /***
706
- * @method most([map])
707
- * @returns Array
708
- * @short Returns the elements in the array with the most commonly occuring value.
709
- * @extra [map] may be a function mapping the value to be checked or a string acting as a shortcut.
710
- * @example
711
- *
712
- * [3,2,2].most() -> [2]
713
- * ['fe','fo','fum'].most('length') -> ['fe','fo']
714
- + [{age:35,name:'ken'},{age:12,name:'bob'},{age:12,name:'ted'}].most(function(n) {
715
- * return n.age;
716
- * }); -> [{age:12,name:'bob'},{age:12,name:'ted'}]
717
- *
718
- ***/
719
- 'most': function(map, all) {
720
- return getMinOrMax(this.groupBy.apply(this, [map]), 'length', 'max', all);
721
- },
722
-
723
- /***
724
- * @method sum([map])
725
- * @returns Number
726
- * @short Sums all values in the array.
727
- * @extra [map] may be a function mapping the value to be summed or a string acting as a shortcut.
728
- * @example
729
- *
730
- * [1,2,2].sum() -> 5
731
- + [{age:35},{age:12},{age:12}].sum(function(n) {
732
- * return n.age;
733
- * }); -> 59
734
- * [{age:35},{age:12},{age:12}].sum('age') -> 59
735
- *
736
- ***/
737
- 'sum': function(map) {
738
- var arr = map ? this.map(map) : this;
739
- return arr.length > 0 ? arr.reduce(function(a,b) { return a + b; }) : 0;
740
- },
741
-
742
- /***
743
- * @method average([map])
744
- * @returns Number
745
- * @short Averages all values in the array.
746
- * @extra [map] may be a function mapping the value to be averaged or a string acting as a shortcut.
747
- * @example
748
- *
749
- * [1,2,3].average() -> 2
750
- + [{age:35},{age:11},{age:11}].average(function(n) {
751
- * return n.age;
752
- * }); -> 19
753
- * [{age:35},{age:11},{age:11}].average('age') -> 19
754
- *
755
- ***/
756
- 'average': function(map) {
757
- var arr = map ? this.map(map) : this;
758
- return arr.length > 0 ? arr.sum() / arr.length : 0;
759
- },
760
-
761
- /***
762
- * @method inGroups(<num>, [padding])
763
- * @returns Array
764
- * @short Groups the array into <num> arrays.
765
- * @extra [padding] specifies a value with which to pad the last array so that they are all equal length.
766
- * @example
767
- *
768
- * [1,2,3,4,5,6,7].inGroups(3) -> [ [1,2,3], [4,5,6], [7] ]
769
- * [1,2,3,4,5,6,7].inGroups(3, 'none') -> [ [1,2,3], [4,5,6], [7,'none','none'] ]
770
- *
771
- ***/
772
- 'inGroups': function(num, padding) {
773
- var pad = arguments.length > 1;
774
- var arr = this;
775
- var result = [];
776
- var divisor = ceil(this.length / num);
777
- getRange(0, num - 1, function(i) {
778
- var index = i * divisor;
779
- var group = arr.slice(index, index + divisor);
780
- if(pad && group.length < divisor) {
781
- getRange(1, divisor - group.length, function() {
782
- group = group.add(padding);
783
- });
784
- }
785
- result.push(group);
786
- });
787
- return result;
788
- },
789
-
790
- /***
791
- * @method inGroupsOf(<num>, [padding] = null)
792
- * @returns Array
793
- * @short Groups the array into arrays of <num> elements each.
794
- * @extra [padding] specifies a value with which to pad the last array so that they are all equal length.
795
- * @example
796
- *
797
- * [1,2,3,4,5,6,7].inGroupsOf(4) -> [ [1,2,3,4], [5,6,7] ]
798
- * [1,2,3,4,5,6,7].inGroupsOf(4, 'none') -> [ [1,2,3,4], [5,6,7,'none'] ]
799
- *
800
- ***/
801
- 'inGroupsOf': function(num, padding) {
802
- var result = [], len = this.length, arr = this, group;
803
- if(len === 0 || num === 0) return arr;
804
- if(isUndefined(num)) num = 1;
805
- if(isUndefined(padding)) padding = null;
806
- getRange(0, ceil(len / num) - 1, function(i) {
807
- group = arr.slice(num * i, num * i + num);
808
- while(group.length < num) {
809
- group.push(padding);
810
- }
811
- result.push(group);
812
- });
813
- return result;
814
- },
815
-
816
- /***
817
- * @method isEmpty()
818
- * @returns Boolean
819
- * @short Returns true if the array is empty.
820
- * @extra This is true if the array has a length of zero, or contains only %undefined%, %null%, or %NaN%.
821
- * @example
822
- *
823
- * [].isEmpty() -> true
824
- * [null,undefined].isEmpty() -> true
825
- *
826
- ***/
827
- 'isEmpty': function() {
828
- return this.compact().length == 0;
829
- },
830
-
831
- /***
832
- * @method sortBy(<map>, [desc] = false)
833
- * @returns Array
834
- * @short Sorts the array by <map>.
835
- * @extra <map> may be a function, a string acting as a shortcut, or blank (direct comparison of array values). [desc] will sort the array in descending order. When the field being sorted on is a string, the resulting order will be determined by an internal collation algorithm that is optimized for major Western languages, but can be customized. For more information see @array_sorting.
836
- * @example
837
- *
838
- * ['world','a','new'].sortBy('length') -> ['a','new','world']
839
- * ['world','a','new'].sortBy('length', true) -> ['world','new','a']
840
- + [{age:72},{age:13},{age:18}].sortBy(function(n) {
841
- * return n.age;
842
- * }); -> [{age:13},{age:18},{age:72}]
843
- *
844
- ***/
845
- 'sortBy': function(map, desc) {
846
- var arr = this.clone();
847
- arr.sort(function(a, b) {
848
- var aProperty, bProperty, comp;
849
- aProperty = transformArgument(a, map, arr, [a]);
850
- bProperty = transformArgument(b, map, arr, [b]);
851
- if(isString(aProperty) && isString(bProperty)) {
852
- comp = collateStrings(aProperty, bProperty);
853
- } else if(aProperty < bProperty) {
854
- comp = -1;
855
- } else if(aProperty > bProperty) {
856
- comp = 1;
857
- } else {
858
- comp = 0;
859
- }
860
- return comp * (desc ? -1 : 1);
861
- });
862
- return arr;
863
- },
864
-
865
- /***
866
- * @method randomize()
867
- * @returns Array
868
- * @short Returns a copy of the array with the elements randomized.
869
- * @extra Uses Fisher-Yates algorithm.
870
- * @example
871
- *
872
- * [1,2,3,4].randomize() -> [?,?,?,?]
873
- *
874
- ***/
875
- 'randomize': function() {
876
- var a = this.concat();
877
- for(var j, x, i = a.length; i; j = parseInt(math.random() * i), x = a[--i], a[i] = a[j], a[j] = x) {};
878
- return a;
879
- },
880
-
881
- /***
882
- * @method zip([arr1], [arr2], ...)
883
- * @returns Array
884
- * @short Merges multiple arrays together.
885
- * @extra This method "zips up" smaller arrays into one large whose elements are "all elements at index 0", "all elements at index 1", etc. Useful when you have associated data that is split over separated arrays. If the arrays passed have more elements than the original array, they will be discarded. If they have fewer elements, the missing elements will filled with %null%.
886
- * @example
887
- *
888
- * [1,2,3].zip([4,5,6]) -> [[1,2], [3,4], [5,6]]
889
- * ['Martin','John'].zip(['Luther','F.'], ['King','Kennedy']) -> [['Martin','Luther','King'], ['John','F.','Kennedy']]
890
- *
891
- ***/
892
- 'zip': function() {
893
- var args = multiArgs(arguments);
894
- return this.map(function(el, i) {
895
- return [el].concat(args.map(function(k) {
896
- return (i in k) ? k[i] : null;
897
- }));
898
- });
899
- },
900
-
901
- /***
902
- * @method sample([num])
903
- * @returns Mixed
904
- * @short Returns a random element from the array.
905
- * @extra If [num] is passed, will return [num] samples from the array.
906
- * @example
907
- *
908
- * [1,2,3,4,5].sample() -> // Random element
909
- * [1,2,3,4,5].sample(3) -> // Array of 3 random elements
910
- *
911
- ***/
912
- 'sample': function(num) {
913
- var arr = this.randomize();
914
- return arguments.length > 0 ? arr.slice(0, num) : arr[0];
915
- },
916
-
917
- /***
918
- * @method each(<fn>, [index] = 0, [loop] = false)
919
- * @returns Array
920
- * @short Runs <fn> against each element in the array. Enhanced version of %Array#forEach%.
921
- * @extra Parameters passed to <fn> are identical to %forEach%, ie. the first parameter is the current element, second parameter is the current index, and third parameter is the array itself. If <fn> returns %false% at any time it will break out of the loop. Once %each% finishes, it will return the array. If [index] is passed, <fn> will begin at that index and work its way to the end. If [loop] is true, it will then start over from the beginning of the array and continue until it reaches [index] - 1.
922
- * @example
923
- *
924
- * [1,2,3,4].each(function(n) {
925
- * // Called 4 times: 1, 2, 3, 4
926
- * });
927
- * [1,2,3,4].each(function(n) {
928
- * // Called 4 times: 3, 4, 1, 2
929
- * }, 2, true);
930
- *
931
- ***/
932
- 'each': function(fn, index, loop) {
933
- arrayEach(this, fn, index, loop);
934
- return this;
935
- },
936
-
937
- /***
938
- * @method add(<el>, [index])
939
- * @returns Array
940
- * @short Adds <el> to the array.
941
- * @extra If [index] is specified, it will add at [index], otherwise adds to the end of the array. %add% behaves like %concat% in that if <el> is an array it will be joined, not inserted. This method will change the array! Use %include% for a non-destructive alias. Also, %insert% is provided as an alias that reads better when using an index.
942
- * @example
943
- *
944
- * [1,2,3,4].add(5) -> [1,2,3,4,5]
945
- * [1,2,3,4].add([5,6,7]) -> [1,2,3,4,5,6,7]
946
- * [1,2,3,4].insert(8, 1) -> [1,8,2,3,4]
947
- *
948
- ***/
949
- 'add': function(el, index) {
950
- if(!isNumber(number(index)) || isNaN(index)) index = this.length;
951
- array.prototype.splice.apply(this, [index, 0].concat(el));
952
- return this;
953
- },
954
-
955
- /***
956
- * @method remove([f1], [f2], ...)
957
- * @returns Array
958
- * @short Removes any element in the array that matches [f1], [f2], etc.
959
- * @extra Will match a string, number, array, object, or alternately test against a function or regex. This method will change the array! Use %exclude% for a non-destructive alias. This method implements @array_matching.
960
- * @example
961
- *
962
- * [1,2,3].remove(3) -> [1,2]
963
- * ['a','b','c'].remove(/b/) -> ['a','c']
964
- + [{a:1},{b:2}].remove(function(n) {
965
- * return n['a'] == 1;
966
- * }); -> [{b:2}]
967
- *
968
- ***/
969
- 'remove': function() {
970
- var i, arr = this;
971
- multiArgs(arguments, function(f) {
972
- i = 0;
973
- while(i < arr.length) {
974
- if(multiMatch(arr[i], f, arr, [arr[i], i, arr])) {
975
- arr.splice(i, 1);
976
- } else {
977
- i++;
978
- }
979
- }
980
- });
981
- return arr;
982
- },
983
-
984
- /***
985
- * @method compact([all] = false)
986
- * @returns Array
987
- * @short Removes all instances of %undefined%, %null%, and %NaN% from the array.
988
- * @extra If [all] is %true%, all "falsy" elements will be removed. This includes empty strings, 0, and false.
989
- * @example
990
- *
991
- * [1,null,2,undefined,3].compact() -> [1,2,3]
992
- * [1,'',2,false,3].compact() -> [1,'',2,false,3]
993
- * [1,'',2,false,3].compact(true) -> [1,2,3]
994
- *
995
- ***/
996
- 'compact': function(all) {
997
- var result = [];
998
- arrayEach(this, function(el, i) {
999
- if(isArray(el)) {
1000
- result.push(el.compact());
1001
- } else if(all && el) {
1002
- result.push(el);
1003
- } else if(!all && el != null && el.valueOf() === el.valueOf()) {
1004
- result.push(el);
1005
- }
1006
- });
1007
- return result;
1008
- },
1009
-
1010
- /***
1011
- * @method groupBy(<map>, [fn])
1012
- * @returns Object
1013
- * @short Groups the array by <map>.
1014
- * @extra Will return an object with keys equal to the grouped values. <map> may be a mapping function, or a string acting as a shortcut. Optionally calls [fn] for each group.
1015
- * @example
1016
- *
1017
- * ['fee','fi','fum'].groupBy('length') -> { 2: ['fi'], 3: ['fee','fum'] }
1018
- + [{age:35,name:'ken'},{age:15,name:'bob'}].groupBy(function(n) {
1019
- * return n.age;
1020
- * }); -> { 35: [{age:35,name:'ken'}], 15: [{age:15,name:'bob'}] }
1021
- *
1022
- ***/
1023
- 'groupBy': function(map, fn) {
1024
- var arr = this, result = {}, key;
1025
- arrayEach(arr, function(el, index) {
1026
- key = transformArgument(el, map, arr, [el, index, arr]);
1027
- if(!result[key]) result[key] = [];
1028
- result[key].push(el);
1029
- });
1030
- if(fn) {
1031
- iterateOverObject(result, fn);
1032
- }
1033
- return result;
1034
- },
1035
-
1036
- /***
1037
- * @method none(<f>)
1038
- * @returns Boolean
1039
- * @short Returns true if none of the elements in the array match <f>.
1040
- * @extra <f> will match a string, number, array, object, or alternately test against a function or regex. This method implements @array_matching.
1041
- * @example
1042
- *
1043
- * [1,2,3].none(5) -> true
1044
- * ['a','b','c'].none(/b/) -> false
1045
- + [{a:1},{b:2}].none(function(n) {
1046
- * return n['a'] > 1;
1047
- * }); -> true
1048
- *
1049
- ***/
1050
- 'none': function() {
1051
- return !this.any.apply(this, arguments);
1052
- }
1053
-
1054
-
1055
- });
1056
-
1057
- // Aliases
1058
- extend(array, true, false, {
1059
-
1060
- /***
1061
- * @method all()
1062
- * @alias every
1063
- *
1064
- ***/
1065
- 'all': array.prototype.every,
1066
-
1067
- /*** @method any()
1068
- * @alias some
1069
- *
1070
- ***/
1071
- 'any': array.prototype.some,
1072
-
1073
- /***
1074
- * @method insert()
1075
- * @alias add
1076
- *
1077
- ***/
1078
- 'insert': array.prototype.add
1079
-
1080
- });
1081
-
1082
-
1083
- /***
1084
- * Object module
1085
- * Enumerable methods on objects
1086
- *
1087
- ***/
1088
-
1089
- function keysWithCoercion(obj) {
1090
- if(obj && obj.valueOf) {
1091
- obj = obj.valueOf();
1092
- }
1093
- return object.keys(obj);
1094
- }
1095
-
1096
- /***
1097
- * @method [enumerable](<obj>)
1098
- * @returns Boolean
1099
- * @short Enumerable methods in the Array package are also available to the Object class. They will perform their normal operations for every property in <obj>.
1100
- * @extra In cases where a callback is used, instead of %element, index%, the callback will instead be passed %key, value%. Enumerable methods are also available to extended objects as instance methods.
1101
- *
1102
- * @set
1103
- * each
1104
- * map
1105
- * any
1106
- * all
1107
- * none
1108
- * count
1109
- * find
1110
- * findAll
1111
- * reduce
1112
- * isEmpty
1113
- * sum
1114
- * average
1115
- * min
1116
- * max
1117
- * least
1118
- * most
1119
- *
1120
- * @example
1121
- *
1122
- * Object.any({foo:'bar'}, 'bar') -> true
1123
- * Object.extended({foo:'bar'}).any('bar') -> true
1124
- * Object.isEmpty({}) -> true
1125
- + Object.map({ fred: { age: 52 } }, 'age'); -> { fred: 52 }
1126
- *
1127
- ***/
1128
-
1129
- function buildEnumerableMethods(names, mapping) {
1130
- extendSimilar(object, false, false, names, function(methods, name) {
1131
- methods[name] = function(obj, arg1, arg2) {
1132
- var result;
1133
- var x = keysWithCoercion(obj);
1134
- result = array.prototype[name].call(x, function(key) {
1135
- if(mapping) {
1136
- return transformArgument(obj[key], arg1, obj, [key, obj[key], obj]);
1137
- } else {
1138
- return multiMatch(obj[key], arg1, obj, [key, obj[key], obj]);
1139
- }
1140
- }, arg2);
1141
- if(isArray(result)) {
1142
- // The method has returned an array of keys so use this array
1143
- // to build up the resulting object in the form we want it in.
1144
- result = result.reduce(function(o, key, i) {
1145
- o[key] = obj[key];
1146
- return o;
1147
- }, {});
1148
- }
1149
- return result;
1150
- };
1151
- });
1152
- buildObjectInstanceMethods(names, Hash);
1153
- }
1154
-
1155
- extend(object, false, false, {
1156
-
1157
- 'map': function(obj, map) {
1158
- return keysWithCoercion(obj).reduce(function(result, key) {
1159
- result[key] = transformArgument(obj[key], map, obj, [key, obj[key], obj]);
1160
- return result;
1161
- }, {});
1162
- },
1163
-
1164
- 'reduce': function(obj) {
1165
- var values = keysWithCoercion(obj).map(function(key) {
1166
- return obj[key];
1167
- });
1168
- return values.reduce.apply(values, multiArgs(arguments).slice(1));
1169
- },
1170
-
1171
- 'each': function(obj, fn) {
1172
- checkCallback(fn);
1173
- iterateOverObject(obj, fn);
1174
- return obj;
1175
- },
1176
-
1177
- /***
1178
- * @method size(<obj>)
1179
- * @returns Number
1180
- * @short Returns the number of properties in <obj>.
1181
- * @extra %size% is available as an instance method on extended objects.
1182
- * @example
1183
- *
1184
- * Object.size({ foo: 'bar' }) -> 1
1185
- *
1186
- ***/
1187
- 'size': function (obj) {
1188
- return keysWithCoercion(obj).length;
1189
- }
1190
-
1191
- });
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
-
1198
- buildEnhancements();
1199
- buildAlphanumericSort();
1200
- buildEnumerableMethods(EnumerableFindingMethods);
1201
- buildEnumerableMethods(EnumerableMappingMethods, true);
1202
- buildObjectInstanceMethods(EnumerableOtherMethods, Hash);
1203
-