activesupport 4.0.13 → 4.2.11.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (166) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +406 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -2
  5. data/lib/active_support/backtrace_cleaner.rb +8 -8
  6. data/lib/active_support/benchmarkable.rb +0 -10
  7. data/lib/active_support/cache/file_store.rb +32 -22
  8. data/lib/active_support/cache/mem_cache_store.rb +5 -7
  9. data/lib/active_support/cache/memory_store.rb +1 -0
  10. data/lib/active_support/cache/strategy/local_cache.rb +11 -30
  11. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  12. data/lib/active_support/cache.rb +75 -41
  13. data/lib/active_support/callbacks.rb +482 -261
  14. data/lib/active_support/concern.rb +23 -7
  15. data/lib/active_support/configurable.rb +1 -1
  16. data/lib/active_support/core_ext/array/access.rb +11 -1
  17. data/lib/active_support/core_ext/array/conversions.rb +2 -17
  18. data/lib/active_support/core_ext/array/grouping.rb +29 -12
  19. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -2
  20. data/lib/active_support/core_ext/array.rb +0 -1
  21. data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -15
  22. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +16 -0
  23. data/lib/active_support/core_ext/class/attribute.rb +1 -2
  24. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -170
  25. data/lib/active_support/core_ext/class/delegating_attributes.rb +13 -8
  26. data/lib/active_support/core_ext/class/subclasses.rb +0 -2
  27. data/lib/active_support/core_ext/class.rb +0 -1
  28. data/lib/active_support/core_ext/date/calculations.rb +10 -0
  29. data/lib/active_support/core_ext/date/conversions.rb +9 -1
  30. data/lib/active_support/core_ext/date/zones.rb +2 -33
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -11
  32. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  33. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  34. data/lib/active_support/core_ext/date_time/calculations.rb +45 -22
  35. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  36. data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
  37. data/lib/active_support/core_ext/date_time/zones.rb +3 -21
  38. data/lib/active_support/core_ext/date_time.rb +1 -0
  39. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  40. data/lib/active_support/core_ext/enumerable.rb +17 -1
  41. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  42. data/lib/active_support/core_ext/hash/compact.rb +24 -0
  43. data/lib/active_support/core_ext/hash/conversions.rb +9 -8
  44. data/lib/active_support/core_ext/hash/except.rb +8 -2
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -0
  46. data/lib/active_support/core_ext/hash/keys.rb +25 -19
  47. data/lib/active_support/core_ext/hash/slice.rb +8 -2
  48. data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
  49. data/lib/active_support/core_ext/hash.rb +2 -1
  50. data/lib/active_support/core_ext/integer/time.rb +0 -15
  51. data/lib/active_support/core_ext/kernel/concern.rb +10 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  53. data/lib/active_support/core_ext/kernel/reporting.rb +13 -2
  54. data/lib/active_support/core_ext/kernel.rb +3 -2
  55. data/lib/active_support/core_ext/load_error.rb +4 -1
  56. data/lib/active_support/core_ext/marshal.rb +8 -5
  57. data/lib/active_support/core_ext/module/aliasing.rb +2 -2
  58. data/lib/active_support/core_ext/module/attr_internal.rb +2 -1
  59. data/lib/active_support/core_ext/module/attribute_accessors.rb +160 -14
  60. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  61. data/lib/active_support/core_ext/module/delegation.rb +53 -25
  62. data/lib/active_support/core_ext/module/deprecation.rb +0 -2
  63. data/lib/active_support/core_ext/module/introspection.rb +0 -16
  64. data/lib/active_support/core_ext/module/method_transplanting.rb +13 -0
  65. data/lib/active_support/core_ext/module.rb +1 -0
  66. data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
  67. data/lib/active_support/core_ext/numeric/time.rb +4 -29
  68. data/lib/active_support/core_ext/object/blank.rb +44 -18
  69. data/lib/active_support/core_ext/object/deep_dup.rb +6 -6
  70. data/lib/active_support/core_ext/object/duplicable.rb +72 -33
  71. data/lib/active_support/core_ext/object/inclusion.rb +16 -15
  72. data/lib/active_support/core_ext/object/itself.rb +15 -0
  73. data/lib/active_support/core_ext/object/json.rb +197 -0
  74. data/lib/active_support/core_ext/object/to_query.rb +14 -6
  75. data/lib/active_support/core_ext/object/try.rb +36 -14
  76. data/lib/active_support/core_ext/object/with_options.rb +30 -3
  77. data/lib/active_support/core_ext/object.rb +2 -1
  78. data/lib/active_support/core_ext/string/access.rb +35 -35
  79. data/lib/active_support/core_ext/string/conversions.rb +10 -9
  80. data/lib/active_support/core_ext/string/exclude.rb +3 -3
  81. data/lib/active_support/core_ext/string/filters.rb +51 -3
  82. data/lib/active_support/core_ext/string/inflections.rb +15 -10
  83. data/lib/active_support/core_ext/string/output_safety.rb +97 -33
  84. data/lib/active_support/core_ext/string/zones.rb +1 -0
  85. data/lib/active_support/core_ext/thread.rb +12 -5
  86. data/lib/active_support/core_ext/time/calculations.rb +47 -68
  87. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  88. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  89. data/lib/active_support/core_ext/time/zones.rb +2 -20
  90. data/lib/active_support/core_ext/time.rb +1 -0
  91. data/lib/active_support/core_ext.rb +0 -1
  92. data/lib/active_support/dependencies/autoload.rb +1 -1
  93. data/lib/active_support/dependencies.rb +64 -25
  94. data/lib/active_support/deprecation/behaviors.rb +4 -4
  95. data/lib/active_support/deprecation.rb +4 -4
  96. data/lib/active_support/duration.rb +55 -11
  97. data/lib/active_support/file_update_checker.rb +1 -1
  98. data/lib/active_support/gem_version.rb +15 -0
  99. data/lib/active_support/hash_with_indifferent_access.rb +39 -11
  100. data/lib/active_support/i18n.rb +4 -4
  101. data/lib/active_support/i18n_railtie.rb +1 -7
  102. data/lib/active_support/inflections.rb +6 -1
  103. data/lib/active_support/inflector/inflections.rb +19 -19
  104. data/lib/active_support/inflector/methods.rb +66 -25
  105. data/lib/active_support/json/decoding.rb +15 -22
  106. data/lib/active_support/json/encoding.rb +125 -286
  107. data/lib/active_support/key_generator.rb +8 -10
  108. data/lib/active_support/lazy_load_hooks.rb +1 -1
  109. data/lib/active_support/log_subscriber/test_helper.rb +1 -1
  110. data/lib/active_support/logger.rb +51 -1
  111. data/lib/active_support/logger_silence.rb +7 -4
  112. data/lib/active_support/logger_thread_safe_level.rb +32 -0
  113. data/lib/active_support/message_encryptor.rb +14 -6
  114. data/lib/active_support/message_verifier.rb +16 -12
  115. data/lib/active_support/multibyte/chars.rb +2 -3
  116. data/lib/active_support/multibyte/unicode.rb +46 -58
  117. data/lib/active_support/notifications/fanout.rb +12 -7
  118. data/lib/active_support/notifications/instrumenter.rb +2 -1
  119. data/lib/active_support/notifications.rb +11 -6
  120. data/lib/active_support/number_helper/number_converter.rb +182 -0
  121. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  122. data/lib/active_support/number_helper/number_to_delimited_converter.rb +23 -0
  123. data/lib/active_support/number_helper/number_to_human_converter.rb +66 -0
  124. data/lib/active_support/number_helper/number_to_human_size_converter.rb +58 -0
  125. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  126. data/lib/active_support/number_helper/number_to_phone_converter.rb +49 -0
  127. data/lib/active_support/number_helper/number_to_rounded_converter.rb +87 -0
  128. data/lib/active_support/number_helper.rb +32 -324
  129. data/lib/active_support/ordered_options.rb +8 -0
  130. data/lib/active_support/per_thread_registry.rb +13 -10
  131. data/lib/active_support/security_utils.rb +27 -0
  132. data/lib/active_support/subscriber.rb +35 -3
  133. data/lib/active_support/test_case.rb +52 -19
  134. data/lib/active_support/testing/assertions.rb +1 -31
  135. data/lib/active_support/testing/autorun.rb +2 -2
  136. data/lib/active_support/testing/constant_lookup.rb +1 -5
  137. data/lib/active_support/testing/declarative.rb +7 -21
  138. data/lib/active_support/testing/isolation.rb +29 -69
  139. data/lib/active_support/testing/setup_and_teardown.rb +17 -2
  140. data/lib/active_support/testing/tagged_logging.rb +2 -2
  141. data/lib/active_support/testing/time_helpers.rb +134 -0
  142. data/lib/active_support/time.rb +0 -2
  143. data/lib/active_support/time_with_zone.rb +60 -40
  144. data/lib/active_support/values/time_zone.rb +101 -101
  145. data/lib/active_support/values/unicode_tables.dat +0 -0
  146. data/lib/active_support/version.rb +4 -7
  147. data/lib/active_support/xml_mini/jdom.rb +6 -5
  148. data/lib/active_support/xml_mini/libxml.rb +1 -3
  149. data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
  150. data/lib/active_support/xml_mini/nokogiri.rb +1 -3
  151. data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
  152. data/lib/active_support/xml_mini/rexml.rb +7 -8
  153. data/lib/active_support/xml_mini.rb +33 -15
  154. data/lib/active_support.rb +27 -2
  155. metadata +43 -43
  156. data/lib/active_support/basic_object.rb +0 -11
  157. data/lib/active_support/buffered_logger.rb +0 -21
  158. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  159. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  160. data/lib/active_support/core_ext/logger.rb +0 -67
  161. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  162. data/lib/active_support/core_ext/proc.rb +0 -17
  163. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  164. data/lib/active_support/file_watcher.rb +0 -36
  165. data/lib/active_support/json/variable.rb +0 -18
  166. data/lib/active_support/testing/pending.rb +0 -14
@@ -1,115 +1,19 @@
1
- require 'active_support/core_ext/big_decimal/conversions'
2
- require 'active_support/core_ext/object/blank'
3
- require 'active_support/core_ext/hash/keys'
4
- require 'active_support/i18n'
5
-
6
1
  module ActiveSupport
7
2
  module NumberHelper
8
- extend self
9
-
10
- DEFAULTS = {
11
- # Used in number_to_delimited
12
- # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
13
- format: {
14
- # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
15
- separator: ".",
16
- # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three)
17
- delimiter: ",",
18
- # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
19
- precision: 3,
20
- # If set to true, precision will mean the number of significant digits instead
21
- # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
22
- significant: false,
23
- # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
24
- strip_insignificant_zeros: false
25
- },
26
-
27
- # Used in number_to_currency
28
- currency: {
29
- format: {
30
- format: "%u%n",
31
- negative_format: "-%u%n",
32
- unit: "$",
33
- # These five are to override number.format and are optional
34
- separator: ".",
35
- delimiter: ",",
36
- precision: 2,
37
- significant: false,
38
- strip_insignificant_zeros: false
39
- }
40
- },
41
-
42
- # Used in number_to_percentage
43
- percentage: {
44
- format: {
45
- delimiter: "",
46
- format: "%n%"
47
- }
48
- },
49
-
50
- # Used in number_to_rounded
51
- precision: {
52
- format: {
53
- delimiter: ""
54
- }
55
- },
56
-
57
- # Used in number_to_human_size and number_to_human
58
- human: {
59
- format: {
60
- # These five are to override number.format and are optional
61
- delimiter: "",
62
- precision: 3,
63
- significant: true,
64
- strip_insignificant_zeros: true
65
- },
66
- # Used in number_to_human_size
67
- storage_units: {
68
- # Storage units output formatting.
69
- # %u is the storage unit, %n is the number (default: 2 MB)
70
- format: "%n %u",
71
- units: {
72
- byte: "Bytes",
73
- kb: "KB",
74
- mb: "MB",
75
- gb: "GB",
76
- tb: "TB"
77
- }
78
- },
79
- # Used in number_to_human
80
- decimal_units: {
81
- format: "%n %u",
82
- # Decimal units output formatting
83
- # By default we will only quantify some of the exponents
84
- # but the commented ones might be defined or overridden
85
- # by the user.
86
- units: {
87
- # femto: Quadrillionth
88
- # pico: Trillionth
89
- # nano: Billionth
90
- # micro: Millionth
91
- # mili: Thousandth
92
- # centi: Hundredth
93
- # deci: Tenth
94
- unit: "",
95
- # ten:
96
- # one: Ten
97
- # other: Tens
98
- # hundred: Hundred
99
- thousand: "Thousand",
100
- million: "Million",
101
- billion: "Billion",
102
- trillion: "Trillion",
103
- quadrillion: "Quadrillion"
104
- }
105
- }
106
- }
107
- }
108
-
109
- DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
110
- -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto }
3
+ extend ActiveSupport::Autoload
4
+
5
+ eager_autoload do
6
+ autoload :NumberConverter
7
+ autoload :NumberToRoundedConverter
8
+ autoload :NumberToDelimitedConverter
9
+ autoload :NumberToHumanConverter
10
+ autoload :NumberToHumanSizeConverter
11
+ autoload :NumberToPhoneConverter
12
+ autoload :NumberToCurrencyConverter
13
+ autoload :NumberToPercentageConverter
14
+ end
111
15
 
112
- STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb]
16
+ extend self
113
17
 
114
18
  # Formats a +number+ into a US phone number (e.g., (555)
115
19
  # 123-9876). You can customize the format in the +options+ hash.
@@ -137,27 +41,7 @@ module ActiveSupport
137
41
  # number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: '.')
138
42
  # # => +1.123.555.1234 x 1343
139
43
  def number_to_phone(number, options = {})
140
- return unless number
141
- options = options.symbolize_keys
142
-
143
- number = number.to_s.strip
144
- area_code = options[:area_code]
145
- delimiter = options[:delimiter] || "-"
146
- extension = options[:extension]
147
- country_code = options[:country_code]
148
-
149
- if area_code
150
- number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
151
- else
152
- number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
153
- number.slice!(0, 1) if number.start_with?(delimiter) && !delimiter.blank?
154
- end
155
-
156
- str = ''
157
- str << "+#{country_code}#{delimiter}" unless country_code.blank?
158
- str << number
159
- str << " x #{extension}" unless extension.blank?
160
- str
44
+ NumberToPhoneConverter.convert(number, options)
161
45
  end
162
46
 
163
47
  # Formats a +number+ into a currency string (e.g., $13.65). You
@@ -199,25 +83,7 @@ module ActiveSupport
199
83
  # number_to_currency(1234567890.50, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
200
84
  # # => 1234567890,50 &pound;
201
85
  def number_to_currency(number, options = {})
202
- return unless number
203
- options = options.symbolize_keys
204
-
205
- currency = i18n_format_options(options[:locale], :currency)
206
- currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
207
-
208
- defaults = default_format_options(:currency).merge!(currency)
209
- defaults[:negative_format] = "-" + options[:format] if options[:format]
210
- options = defaults.merge!(options)
211
-
212
- unit = options.delete(:unit)
213
- format = options.delete(:format)
214
-
215
- if number.to_f.phase != 0
216
- format = options.delete(:negative_format)
217
- number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '')
218
- end
219
-
220
- format.gsub('%n', self.number_to_rounded(number, options)).gsub('%u', unit)
86
+ NumberToCurrencyConverter.convert(number, options)
221
87
  end
222
88
 
223
89
  # Formats a +number+ as a percentage string (e.g., 65%). You can
@@ -253,14 +119,7 @@ module ActiveSupport
253
119
  # number_to_percentage('98a') # => 98a%
254
120
  # number_to_percentage(100, format: '%n %') # => 100 %
255
121
  def number_to_percentage(number, options = {})
256
- return unless number
257
- options = options.symbolize_keys
258
-
259
- defaults = format_options(options[:locale], :percentage)
260
- options = defaults.merge!(options)
261
-
262
- format = options[:format] || "%n%"
263
- format.gsub('%n', self.number_to_rounded(number, options))
122
+ NumberToPercentageConverter.convert(number, options)
264
123
  end
265
124
 
266
125
  # Formats a +number+ with grouped thousands using +delimiter+
@@ -289,15 +148,7 @@ module ActiveSupport
289
148
  # number_to_delimited(98765432.98, delimiter: ' ', separator: ',')
290
149
  # # => 98 765 432,98
291
150
  def number_to_delimited(number, options = {})
292
- options = options.symbolize_keys
293
-
294
- return number unless valid_float?(number)
295
-
296
- options = format_options(options[:locale]).merge!(options)
297
-
298
- parts = number.to_s.split('.')
299
- parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
300
- parts.join(options[:separator])
151
+ NumberToDelimitedConverter.convert(number, options)
301
152
  end
302
153
 
303
154
  # Formats a +number+ with the specified level of
@@ -340,39 +191,7 @@ module ActiveSupport
340
191
  # number_to_rounded(1111.2345, precision: 2, separator: ',', delimiter: '.')
341
192
  # # => 1.111,23
342
193
  def number_to_rounded(number, options = {})
343
- return number unless valid_float?(number)
344
- number = Float(number)
345
- options = options.symbolize_keys
346
-
347
- defaults = format_options(options[:locale], :precision)
348
- options = defaults.merge!(options)
349
-
350
- precision = options.delete :precision
351
- significant = options.delete :significant
352
- strip_insignificant_zeros = options.delete :strip_insignificant_zeros
353
-
354
- if significant && precision > 0
355
- if number == 0
356
- digits, rounded_number = 1, 0
357
- else
358
- digits = (Math.log10(number.abs) + 1).floor
359
- multiplier = 10 ** (digits - precision)
360
- rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier
361
- digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
362
- end
363
- precision -= digits
364
- precision = 0 if precision < 0 # don't let it be negative
365
- else
366
- rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
367
- rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
368
- end
369
- formatted_number = self.number_to_delimited("%01.#{precision}f" % rounded_number, options)
370
- if strip_insignificant_zeros
371
- escaped_separator = Regexp.escape(options[:separator])
372
- formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
373
- else
374
- formatted_number
375
- end
194
+ NumberToRoundedConverter.convert(number, options)
376
195
  end
377
196
 
378
197
  # Formats the bytes in +number+ into a more understandable
@@ -413,43 +232,10 @@ module ActiveSupport
413
232
  # number_to_human_size(1234567, precision: 2) # => 1.2 MB
414
233
  # number_to_human_size(483989, precision: 2) # => 470 KB
415
234
  # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
416
- #
417
- # Non-significant zeros after the fractional separator are stripped out by
418
- # default (set <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
419
- #
420
- # number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB"
421
- # number_to_human_size(524288000, precision: 5) # => "500 MB"
235
+ # number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
236
+ # number_to_human_size(524288000, precision: 5) # => "500 MB"
422
237
  def number_to_human_size(number, options = {})
423
- options = options.symbolize_keys
424
-
425
- return number unless valid_float?(number)
426
- number = Float(number)
427
-
428
- defaults = format_options(options[:locale], :human)
429
- options = defaults.merge!(options)
430
-
431
- #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
432
- options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
433
-
434
- storage_units_format = translate_number_value_with_default('human.storage_units.format', :locale => options[:locale], :raise => true)
435
-
436
- base = options[:prefix] == :si ? 1000 : 1024
437
-
438
- if number.to_i < base
439
- unit = translate_number_value_with_default('human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
440
- storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
441
- else
442
- max_exp = STORAGE_UNITS.size - 1
443
- exponent = (Math.log(number) / Math.log(base)).to_i # Convert to base
444
- exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
445
- number /= base ** exponent
446
-
447
- unit_key = STORAGE_UNITS[exponent]
448
- unit = translate_number_value_with_default("human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
449
-
450
- formatted_number = self.number_to_rounded(number, options)
451
- storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
452
- end
238
+ NumberToHumanSizeConverter.convert(number, options)
453
239
  end
454
240
 
455
241
  # Pretty prints (formats and approximates) a number in a way it
@@ -486,12 +272,12 @@ module ActiveSupport
486
272
  # string containing an i18n scope where to find this hash. It
487
273
  # might have the following keys:
488
274
  # * *integers*: <tt>:unit</tt>, <tt>:ten</tt>,
489
- # *<tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
490
- # *<tt>:billion</tt>, <tt>:trillion</tt>,
491
- # *<tt>:quadrillion</tt>
275
+ # <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
276
+ # <tt>:billion</tt>, <tt>:trillion</tt>,
277
+ # <tt>:quadrillion</tt>
492
278
  # * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>,
493
- # *<tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
494
- # *<tt>:pico</tt>, <tt>:femto</tt>
279
+ # <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
280
+ # <tt>:pico</tt>, <tt>:femto</tt>
495
281
  # * <tt>:format</tt> - Sets the format of the output string
496
282
  # (defaults to "%n %u"). The field types are:
497
283
  # * %u - The quantifier (ex.: 'thousand')
@@ -515,12 +301,15 @@ module ActiveSupport
515
301
  # separator: ',',
516
302
  # significant: false) # => "1,2 Million"
517
303
  #
304
+ # number_to_human(500000000, precision: 5) # => "500 Million"
305
+ # number_to_human(12345012345, significant: false) # => "12.345 Billion"
306
+ #
518
307
  # Non-significant zeros after the decimal separator are stripped
519
308
  # out by default (set <tt>:strip_insignificant_zeros</tt> to
520
309
  # +false+ to change that):
521
310
  #
522
- # number_to_human(12345012345, significant_digits: 6) # => "12.345 Billion"
523
- # number_to_human(500000000, precision: 5) # => "500 Million"
311
+ # number_to_human(12.00001) # => "12"
312
+ # number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
524
313
  #
525
314
  # ==== Custom Unit Quantifiers
526
315
  #
@@ -550,88 +339,7 @@ module ActiveSupport
550
339
  # number_to_human(1, units: :distance) # => "1 meter"
551
340
  # number_to_human(0.34, units: :distance) # => "34 centimeters"
552
341
  def number_to_human(number, options = {})
553
- options = options.symbolize_keys
554
-
555
- return number unless valid_float?(number)
556
- number = Float(number)
557
-
558
- defaults = format_options(options[:locale], :human)
559
- options = defaults.merge!(options)
560
-
561
- #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
562
- options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
563
-
564
- inverted_du = DECIMAL_UNITS.invert
565
-
566
- units = options.delete :units
567
- unit_exponents = case units
568
- when Hash
569
- units
570
- when String, Symbol
571
- I18n.translate(:"#{units}", :locale => options[:locale], :raise => true)
572
- when nil
573
- translate_number_value_with_default("human.decimal_units.units", :locale => options[:locale], :raise => true)
574
- else
575
- raise ArgumentError, ":units must be a Hash or String translation scope."
576
- end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
577
-
578
- number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
579
- display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0
580
- number /= 10 ** display_exponent
581
-
582
- unit = case units
583
- when Hash
584
- units[DECIMAL_UNITS[display_exponent]] || ''
585
- when String, Symbol
586
- I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
587
- else
588
- translate_number_value_with_default("human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
589
- end
590
-
591
- decimal_format = options[:format] || translate_number_value_with_default('human.decimal_units.format', :locale => options[:locale])
592
- formatted_number = self.number_to_rounded(number, options)
593
- decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip
594
- end
595
-
596
- def self.private_module_and_instance_method(method_name) #:nodoc:
597
- private method_name
598
- private_class_method method_name
599
- end
600
- private_class_method :private_module_and_instance_method
601
-
602
- def format_options(locale, namespace = nil) #:nodoc:
603
- default_format_options(namespace).merge!(i18n_format_options(locale, namespace))
604
- end
605
- private_module_and_instance_method :format_options
606
-
607
- def default_format_options(namespace = nil) #:nodoc:
608
- options = DEFAULTS[:format].dup
609
- options.merge!(DEFAULTS[namespace][:format]) if namespace
610
- options
611
- end
612
- private_module_and_instance_method :default_format_options
613
-
614
- def i18n_format_options(locale, namespace = nil) #:nodoc:
615
- options = I18n.translate(:'number.format', locale: locale, default: {}).dup
616
- if namespace
617
- options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {}))
618
- end
619
- options
620
- end
621
- private_module_and_instance_method :i18n_format_options
622
-
623
- def translate_number_value_with_default(key, i18n_options = {}) #:nodoc:
624
- default = key.split('.').reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
625
-
626
- I18n.translate(key, { default: default, scope: :number }.merge!(i18n_options))
627
- end
628
- private_module_and_instance_method :translate_number_value_with_default
629
-
630
- def valid_float?(number) #:nodoc:
631
- Float(number)
632
- rescue ArgumentError, TypeError
633
- false
342
+ NumberToHumanConverter.convert(number, options)
634
343
  end
635
- private_module_and_instance_method :valid_float?
636
344
  end
637
345
  end
@@ -40,6 +40,14 @@ module ActiveSupport
40
40
  end
41
41
  end
42
42
 
43
+ # +InheritableOptions+ provides a constructor to build an +OrderedOptions+
44
+ # hash inherited from another hash.
45
+ #
46
+ # Use this if you already have some hash and you want to create a new one based on it.
47
+ #
48
+ # h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' })
49
+ # h.girl # => 'Mary'
50
+ # h.boy # => 'John'
43
51
  class InheritableOptions < OrderedOptions
44
52
  def initialize(parent = nil)
45
53
  if parent.kind_of?(OrderedOptions)
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
1
3
  module ActiveSupport
2
4
  # This module is used to encapsulate access to thread local variables.
3
5
  #
@@ -32,21 +34,22 @@ module ActiveSupport
32
34
  #
33
35
  # If the class has an initializer, it must accept no arguments.
34
36
  module PerThreadRegistry
35
- protected
37
+ def self.extended(object)
38
+ object.instance_variable_set '@per_thread_registry_key', object.name.freeze
39
+ end
36
40
 
41
+ def instance
42
+ Thread.current[@per_thread_registry_key] ||= new
43
+ end
44
+
45
+ protected
37
46
  def method_missing(name, *args, &block) # :nodoc:
38
47
  # Caches the method definition as a singleton method of the receiver.
39
- define_singleton_method(name) do |*a, &b|
40
- per_thread_registry_instance.public_send(name, *a, &b)
41
- end
48
+ #
49
+ # By letting #delegate handle it, we avoid an enclosure that'll capture args.
50
+ singleton_class.delegate name, to: :instance
42
51
 
43
52
  send(name, *args, &block)
44
53
  end
45
-
46
- private
47
-
48
- def per_thread_registry_instance
49
- Thread.current[name] ||= new
50
- end
51
54
  end
52
55
  end
@@ -0,0 +1,27 @@
1
+ require 'digest'
2
+
3
+ module ActiveSupport
4
+ module SecurityUtils
5
+ # Constant time string comparison.
6
+ #
7
+ # The values compared should be of fixed length, such as strings
8
+ # that have already been processed by HMAC. This should not be used
9
+ # on variable length plaintext strings because it could leak length info
10
+ # via timing attacks.
11
+ def secure_compare(a, b)
12
+ return false unless a.bytesize == b.bytesize
13
+
14
+ l = a.unpack "C#{a.bytesize}"
15
+
16
+ res = 0
17
+ b.each_byte { |byte| res |= byte ^ l.shift }
18
+ res == 0
19
+ end
20
+ module_function :secure_compare
21
+
22
+ def variable_size_secure_compare(a, b) # :nodoc:
23
+ secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
24
+ end
25
+ module_function :variable_size_secure_compare
26
+ end
27
+ end
@@ -31,22 +31,54 @@ module ActiveSupport
31
31
 
32
32
  # Attach the subscriber to a namespace.
33
33
  def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications)
34
+ @namespace = namespace
35
+ @subscriber = subscriber
36
+ @notifier = notifier
37
+
34
38
  subscribers << subscriber
35
39
 
40
+ # Add event subscribers for all existing methods on the class.
36
41
  subscriber.public_methods(false).each do |event|
37
- next if %w{ start finish }.include?(event.to_s)
42
+ add_event_subscriber(event)
43
+ end
44
+ end
38
45
 
39
- notifier.subscribe("#{event}.#{namespace}", subscriber)
46
+ # Adds event subscribers for all new methods added to the class.
47
+ def method_added(event)
48
+ # Only public methods are added as subscribers, and only if a notifier
49
+ # has been set up. This means that subscribers will only be set up for
50
+ # classes that call #attach_to.
51
+ if public_method_defined?(event) && notifier
52
+ add_event_subscriber(event)
40
53
  end
41
54
  end
42
55
 
43
56
  def subscribers
44
57
  @@subscribers ||= []
45
58
  end
59
+
60
+ protected
61
+
62
+ attr_reader :subscriber, :notifier, :namespace
63
+
64
+ def add_event_subscriber(event)
65
+ return if %w{ start finish }.include?(event.to_s)
66
+
67
+ pattern = "#{event}.#{namespace}"
68
+
69
+ # don't add multiple subscribers (eg. if methods are redefined)
70
+ return if subscriber.patterns.include?(pattern)
71
+
72
+ subscriber.patterns << pattern
73
+ notifier.subscribe(pattern, subscriber)
74
+ end
46
75
  end
47
76
 
77
+ attr_reader :patterns # :nodoc:
78
+
48
79
  def initialize
49
80
  @queue_key = [self.class.name, object_id].join "-"
81
+ @patterns = []
50
82
  super
51
83
  end
52
84
 
@@ -71,7 +103,7 @@ module ActiveSupport
71
103
  private
72
104
 
73
105
  def event_stack
74
- SubscriberQueueRegistry.get_queue(@queue_key)
106
+ SubscriberQueueRegistry.instance.get_queue(@queue_key)
75
107
  end
76
108
  end
77
109
 
@@ -1,42 +1,75 @@
1
1
  gem 'minitest' # make sure we get the gem, not stdlib
2
- require 'minitest/unit'
2
+ require 'minitest'
3
3
  require 'active_support/testing/tagged_logging'
4
4
  require 'active_support/testing/setup_and_teardown'
5
5
  require 'active_support/testing/assertions'
6
6
  require 'active_support/testing/deprecation'
7
- require 'active_support/testing/pending'
8
7
  require 'active_support/testing/declarative'
9
8
  require 'active_support/testing/isolation'
10
9
  require 'active_support/testing/constant_lookup'
10
+ require 'active_support/testing/time_helpers'
11
11
  require 'active_support/core_ext/kernel/reporting'
12
12
  require 'active_support/deprecation'
13
13
 
14
- begin
15
- silence_warnings { require 'mocha/setup' }
16
- rescue LoadError
17
- end
18
-
19
14
  module ActiveSupport
20
- class TestCase < ::MiniTest::Unit::TestCase
21
- Assertion = MiniTest::Assertion
22
- alias_method :method_name, :__name__
15
+ class TestCase < ::Minitest::Test
16
+ Assertion = Minitest::Assertion
23
17
 
24
- $tags = {}
25
- def self.for_tag(tag)
26
- yield if $tags[tag]
27
- end
18
+ class << self
19
+ # Sets the order in which test cases are run.
20
+ #
21
+ # ActiveSupport::TestCase.test_order = :random # => :random
22
+ #
23
+ # Valid values are:
24
+ # * +:random+ (to run tests in random order)
25
+ # * +:parallel+ (to run tests in parallel)
26
+ # * +:sorted+ (to run tests alphabetically by method name)
27
+ # * +:alpha+ (equivalent to +:sorted+)
28
+ def test_order=(new_order)
29
+ ActiveSupport.test_order = new_order
30
+ end
31
+
32
+ # Returns the order in which test cases are run.
33
+ #
34
+ # ActiveSupport::TestCase.test_order # => :sorted
35
+ #
36
+ # Possible values are +:random+, +:parallel+, +:alpha+, +:sorted+.
37
+ # Defaults to +:sorted+.
38
+ def test_order
39
+ test_order = ActiveSupport.test_order
28
40
 
29
- # FIXME: we have tests that depend on run order, we should fix that and
30
- # remove this method.
31
- def self.test_order # :nodoc:
32
- :sorted
41
+ if test_order.nil?
42
+ ActiveSupport::Deprecation.warn "You did not specify a value for the " \
43
+ "configuration option `active_support.test_order`. In Rails 5, " \
44
+ "the default value of this option will change from `:sorted` to " \
45
+ "`:random`.\n" \
46
+ "To disable this warning and keep the current behavior, you can add " \
47
+ "the following line to your `config/environments/test.rb`:\n" \
48
+ "\n" \
49
+ " Rails.application.configure do\n" \
50
+ " config.active_support.test_order = :sorted\n" \
51
+ " end\n" \
52
+ "\n" \
53
+ "Alternatively, you can opt into the future behavior by setting this " \
54
+ "option to `:random`."
55
+
56
+ test_order = :sorted
57
+ self.test_order = test_order
58
+ end
59
+
60
+ test_order
61
+ end
62
+
63
+ alias :my_tests_are_order_dependent! :i_suck_and_my_tests_are_order_dependent!
33
64
  end
34
65
 
66
+ alias_method :method_name, :name
67
+
35
68
  include ActiveSupport::Testing::TaggedLogging
36
69
  include ActiveSupport::Testing::SetupAndTeardown
37
70
  include ActiveSupport::Testing::Assertions
38
71
  include ActiveSupport::Testing::Deprecation
39
- include ActiveSupport::Testing::Pending
72
+ include ActiveSupport::Testing::TimeHelpers
40
73
  extend ActiveSupport::Testing::Declarative
41
74
 
42
75
  # test/unit backwards compatibility methods