activesupport 4.2.11.3 → 5.0.0.beta1

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 (174) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +309 -485
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/active_support.rb +8 -15
  6. data/lib/active_support/array_inquirer.rb +44 -0
  7. data/lib/active_support/backtrace_cleaner.rb +1 -1
  8. data/lib/active_support/cache.rb +59 -72
  9. data/lib/active_support/cache/file_store.rb +27 -19
  10. data/lib/active_support/cache/mem_cache_store.rb +71 -60
  11. data/lib/active_support/cache/memory_store.rb +16 -21
  12. data/lib/active_support/cache/null_store.rb +1 -4
  13. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  14. data/lib/active_support/callbacks.rb +107 -111
  15. data/lib/active_support/concern.rb +1 -1
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +142 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext.rb +2 -1
  20. data/lib/active_support/core_ext/array.rb +1 -0
  21. data/lib/active_support/core_ext/array/access.rb +13 -1
  22. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  23. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  24. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class.rb +0 -1
  27. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  28. data/lib/active_support/core_ext/class/subclasses.rb +5 -2
  29. data/lib/active_support/core_ext/date.rb +1 -1
  30. data/lib/active_support/core_ext/date/blank.rb +12 -0
  31. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  32. data/lib/active_support/core_ext/date/conversions.rb +3 -3
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +93 -27
  34. data/lib/active_support/core_ext/date_and_time/zones.rb +1 -2
  35. data/lib/active_support/core_ext/date_time.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +7 -23
  38. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  39. data/lib/active_support/core_ext/enumerable.rb +27 -17
  40. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  41. data/lib/active_support/core_ext/hash/compact.rb +15 -19
  42. data/lib/active_support/core_ext/hash/conversions.rb +21 -2
  43. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  44. data/lib/active_support/core_ext/hash/except.rb +9 -8
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  46. data/lib/active_support/core_ext/hash/keys.rb +22 -18
  47. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  48. data/lib/active_support/core_ext/hash/transform_values.rb +13 -7
  49. data/lib/active_support/core_ext/integer/time.rb +1 -1
  50. data/lib/active_support/core_ext/kernel.rb +0 -1
  51. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  52. data/lib/active_support/core_ext/kernel/reporting.rb +0 -84
  53. data/lib/active_support/core_ext/load_error.rb +4 -2
  54. data/lib/active_support/core_ext/marshal.rb +8 -13
  55. data/lib/active_support/core_ext/module.rb +1 -0
  56. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  57. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  58. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  59. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -7
  60. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  61. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  62. data/lib/active_support/core_ext/module/delegation.rb +7 -14
  63. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -13
  64. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  65. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  66. data/lib/active_support/core_ext/name_error.rb +15 -2
  67. data/lib/active_support/core_ext/numeric.rb +1 -0
  68. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  69. data/lib/active_support/core_ext/numeric/conversions.rb +12 -23
  70. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  71. data/lib/active_support/core_ext/numeric/time.rb +20 -0
  72. data/lib/active_support/core_ext/object.rb +0 -1
  73. data/lib/active_support/core_ext/object/blank.rb +11 -2
  74. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  75. data/lib/active_support/core_ext/object/duplicable.rb +39 -70
  76. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  77. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  78. data/lib/active_support/core_ext/object/json.rb +9 -7
  79. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  80. data/lib/active_support/core_ext/object/try.rb +67 -21
  81. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  82. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  83. data/lib/active_support/core_ext/range/each.rb +16 -18
  84. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  85. data/lib/active_support/core_ext/securerandom.rb +23 -0
  86. data/lib/active_support/core_ext/string/access.rb +1 -1
  87. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  88. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  89. data/lib/active_support/core_ext/string/filters.rb +1 -2
  90. data/lib/active_support/core_ext/string/inflections.rb +23 -5
  91. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  92. data/lib/active_support/core_ext/string/output_safety.rb +8 -9
  93. data/lib/active_support/core_ext/string/strip.rb +3 -6
  94. data/lib/active_support/core_ext/struct.rb +3 -6
  95. data/lib/active_support/core_ext/time.rb +0 -2
  96. data/lib/active_support/core_ext/time/calculations.rb +18 -16
  97. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  98. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  99. data/lib/active_support/core_ext/time/zones.rb +19 -3
  100. data/lib/active_support/core_ext/uri.rb +1 -3
  101. data/lib/active_support/dependencies.rb +79 -44
  102. data/lib/active_support/dependencies/interlock.rb +47 -0
  103. data/lib/active_support/deprecation/behaviors.rb +12 -0
  104. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  105. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  106. data/lib/active_support/deprecation/reporting.rb +13 -2
  107. data/lib/active_support/duration.rb +5 -8
  108. data/lib/active_support/evented_file_update_checker.rb +150 -0
  109. data/lib/active_support/file_update_checker.rb +1 -1
  110. data/lib/active_support/gem_version.rb +5 -5
  111. data/lib/active_support/hash_with_indifferent_access.rb +15 -17
  112. data/lib/active_support/i18n_railtie.rb +25 -4
  113. data/lib/active_support/inflector/inflections.rb +36 -5
  114. data/lib/active_support/inflector/methods.rb +87 -89
  115. data/lib/active_support/inflector/transliterate.rb +36 -21
  116. data/lib/active_support/json/decoding.rb +2 -8
  117. data/lib/active_support/json/encoding.rb +0 -50
  118. data/lib/active_support/key_generator.rb +4 -4
  119. data/lib/active_support/log_subscriber.rb +1 -1
  120. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  121. data/lib/active_support/logger.rb +4 -52
  122. data/lib/active_support/logger_silence.rb +3 -5
  123. data/lib/active_support/message_encryptor.rb +4 -11
  124. data/lib/active_support/message_verifier.rb +64 -8
  125. data/lib/active_support/multibyte/chars.rb +12 -3
  126. data/lib/active_support/multibyte/unicode.rb +6 -8
  127. data/lib/active_support/notifications.rb +2 -2
  128. data/lib/active_support/notifications/fanout.rb +5 -5
  129. data/lib/active_support/notifications/instrumenter.rb +19 -2
  130. data/lib/active_support/number_helper.rb +21 -15
  131. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -4
  132. data/lib/active_support/number_helper/number_to_delimited_converter.rb +7 -2
  133. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  134. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -1
  135. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  136. data/lib/active_support/number_helper/number_to_rounded_converter.rb +28 -25
  137. data/lib/active_support/ordered_options.rb +15 -1
  138. data/lib/active_support/per_thread_registry.rb +3 -0
  139. data/lib/active_support/rails.rb +2 -2
  140. data/lib/active_support/railtie.rb +6 -1
  141. data/lib/active_support/rescuable.rb +4 -4
  142. data/lib/active_support/security_utils.rb +0 -7
  143. data/lib/active_support/string_inquirer.rb +1 -1
  144. data/lib/active_support/subscriber.rb +5 -10
  145. data/lib/active_support/tagged_logging.rb +3 -1
  146. data/lib/active_support/test_case.rb +13 -25
  147. data/lib/active_support/testing/assertions.rb +15 -13
  148. data/lib/active_support/testing/autorun.rb +8 -1
  149. data/lib/active_support/testing/composite_filter.rb +54 -0
  150. data/lib/active_support/testing/deprecation.rb +9 -8
  151. data/lib/active_support/testing/file_fixtures.rb +34 -0
  152. data/lib/active_support/testing/isolation.rb +22 -8
  153. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  154. data/lib/active_support/testing/stream.rb +42 -0
  155. data/lib/active_support/testing/time_helpers.rb +6 -6
  156. data/lib/active_support/time_with_zone.rb +135 -53
  157. data/lib/active_support/values/time_zone.rb +80 -46
  158. data/lib/active_support/values/unicode_tables.dat +0 -0
  159. data/lib/active_support/xml_mini.rb +15 -30
  160. data/lib/active_support/xml_mini/jdom.rb +1 -1
  161. data/lib/active_support/xml_mini/libxml.rb +5 -3
  162. data/lib/active_support/xml_mini/libxmlsax.rb +4 -1
  163. data/lib/active_support/xml_mini/nokogiri.rb +5 -3
  164. data/lib/active_support/xml_mini/nokogirisax.rb +3 -1
  165. data/lib/active_support/xml_mini/rexml.rb +3 -1
  166. metadata +57 -21
  167. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  168. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  169. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -15
  170. data/lib/active_support/core_ext/date_time/compatibility.rb +0 -16
  171. data/lib/active_support/core_ext/object/itself.rb +0 -15
  172. data/lib/active_support/core_ext/thread.rb +0 -86
  173. data/lib/active_support/core_ext/time/compatibility.rb +0 -14
  174. data/lib/active_support/logger_thread_safe_level.rb +0 -32
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  require 'active_support/json'
3
2
  require 'active_support/core_ext/string/access'
4
3
  require 'active_support/core_ext/string/behavior'
@@ -87,9 +86,19 @@ module ActiveSupport #:nodoc:
87
86
  end
88
87
 
89
88
  # Works like <tt>String#slice!</tt>, but returns an instance of
90
- # Chars, or nil if the string was not modified.
89
+ # Chars, or nil if the string was not modified. The string will not be
90
+ # modified if the range given is out of bounds
91
+ #
92
+ # string = 'Welcome'
93
+ # string.mb_chars.slice!(3) # => #<ActiveSupport::Multibyte::Chars:0x000000038109b8 @wrapped_string="c">
94
+ # string # => 'Welome'
95
+ # string.mb_chars.slice!(0..3) # => #<ActiveSupport::Multibyte::Chars:0x00000002eb80a0 @wrapped_string="Welo">
96
+ # string # => 'me'
91
97
  def slice!(*args)
92
- chars(@wrapped_string.slice!(*args))
98
+ string_sliced = @wrapped_string.slice!(*args)
99
+ if string_sliced
100
+ chars(string_sliced)
101
+ end
93
102
  end
94
103
 
95
104
  # Reverses all characters in the string.
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  module ActiveSupport
3
2
  module Multibyte
4
3
  module Unicode
@@ -11,7 +10,7 @@ module ActiveSupport
11
10
  NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
12
11
 
13
12
  # The Unicode version that is supported by the implementation
14
- UNICODE_VERSION = '7.0.0'
13
+ UNICODE_VERSION = '8.0.0'
15
14
 
16
15
  # The default normalization used for operations that require
17
16
  # normalization. It can be set to any of the normalizations
@@ -58,7 +57,7 @@ module ActiveSupport
58
57
  # Returns a regular expression pattern that matches the passed Unicode
59
58
  # codepoints.
60
59
  def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
61
- array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
60
+ array_of_codepoints.collect{ |e| [e].pack 'U*'.freeze }.join('|'.freeze)
62
61
  end
63
62
  TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u
64
63
  LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u
@@ -211,9 +210,8 @@ module ActiveSupport
211
210
  codepoints
212
211
  end
213
212
 
214
- # Ruby >= 2.1 has String#scrub, which is faster than the workaround used for < 2.1.
215
213
  # Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
216
- if '<3'.respond_to?(:scrub) && !defined?(Rubinius)
214
+ if !defined?(Rubinius)
217
215
  # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
218
216
  # resulting in a valid UTF-8 string.
219
217
  #
@@ -258,7 +256,7 @@ module ActiveSupport
258
256
  # * <tt>string</tt> - The string to perform normalization on.
259
257
  # * <tt>form</tt> - The form you want to normalize in. Should be one of
260
258
  # the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
261
- # Default is ActiveSupport::Multibyte.default_normalization_form.
259
+ # Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
262
260
  def normalize(string, form=nil)
263
261
  form ||= @default_normalization_form
264
262
  # See http://www.unicode.org/reports/tr15, Table 1
@@ -274,7 +272,7 @@ module ActiveSupport
274
272
  compose(reorder_characters(decompose(:compatibility, codepoints)))
275
273
  else
276
274
  raise ArgumentError, "#{form} is not a valid normalization variant", caller
277
- end.pack('U*')
275
+ end.pack('U*'.freeze)
278
276
  end
279
277
 
280
278
  def downcase(string)
@@ -339,7 +337,7 @@ module ActiveSupport
339
337
  end
340
338
 
341
339
  # Redefine the === method so we can write shorter rules for grapheme cluster breaks
342
- @boundary.each do |k,_|
340
+ @boundary.each_key do |k|
343
341
  @boundary[k].instance_eval do
344
342
  def ===(other)
345
343
  detect { |i| i === other } ? true : false
@@ -69,8 +69,8 @@ module ActiveSupport
69
69
  # is able to take the arguments as they come and provide an object-oriented
70
70
  # interface to that data.
71
71
  #
72
- # It is also possible to pass an object as the second parameter passed to the
73
- # <tt>subscribe</tt> method instead of a block:
72
+ # It is also possible to pass an object which responds to <tt>call</tt> method
73
+ # as the second parameter to the <tt>subscribe</tt> method instead of a block:
74
74
  #
75
75
  # module ActionController
76
76
  # class PageRequest
@@ -1,5 +1,5 @@
1
1
  require 'mutex_m'
2
- require 'thread_safe'
2
+ require 'concurrent/map'
3
3
 
4
4
  module ActiveSupport
5
5
  module Notifications
@@ -12,7 +12,7 @@ module ActiveSupport
12
12
 
13
13
  def initialize
14
14
  @subscribers = []
15
- @listeners_for = ThreadSafe::Cache.new
15
+ @listeners_for = Concurrent::Map.new
16
16
  super
17
17
  end
18
18
 
@@ -42,8 +42,8 @@ module ActiveSupport
42
42
  listeners_for(name).each { |s| s.start(name, id, payload) }
43
43
  end
44
44
 
45
- def finish(name, id, payload)
46
- listeners_for(name).each { |s| s.finish(name, id, payload) }
45
+ def finish(name, id, payload, listeners = listeners_for(name))
46
+ listeners.each { |s| s.finish(name, id, payload) }
47
47
  end
48
48
 
49
49
  def publish(name, *args)
@@ -51,7 +51,7 @@ module ActiveSupport
51
51
  end
52
52
 
53
53
  def listeners_for(name)
54
- # this is correctly done double-checked locking (ThreadSafe::Cache's lookups have volatile semantics)
54
+ # this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
55
55
  @listeners_for[name] || synchronize do
56
56
  # use synchronisation when accessing @subscribers
57
57
  @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
@@ -15,14 +15,15 @@ module ActiveSupport
15
15
  # and publish it. Notice that events get sent even if an error occurs
16
16
  # in the passed-in block.
17
17
  def instrument(name, payload={})
18
- start name, payload
18
+ # some of the listeners might have state
19
+ listeners_state = start name, payload
19
20
  begin
20
21
  yield payload
21
22
  rescue Exception => e
22
23
  payload[:exception] = [e.class.name, e.message]
23
24
  raise e
24
25
  ensure
25
- finish name, payload
26
+ finish_with_state listeners_state, name, payload
26
27
  end
27
28
  end
28
29
 
@@ -36,6 +37,10 @@ module ActiveSupport
36
37
  @notifier.finish name, @id, payload
37
38
  end
38
39
 
40
+ def finish_with_state(listeners_state, name, payload)
41
+ @notifier.finish name, @id, payload, listeners_state
42
+ end
43
+
39
44
  private
40
45
 
41
46
  def unique_id
@@ -57,6 +62,18 @@ module ActiveSupport
57
62
  @duration = nil
58
63
  end
59
64
 
65
+ # Returns the difference in milliseconds between when the execution of the
66
+ # event started and when it ended.
67
+ #
68
+ # ActiveSupport::Notifications.subscribe('wait') do |*args|
69
+ # @event = ActiveSupport::Notifications::Event.new(*args)
70
+ # end
71
+ #
72
+ # ActiveSupport::Notifications.instrument('wait') do
73
+ # sleep 1
74
+ # end
75
+ #
76
+ # @event.duration # => 1000.138
60
77
  def duration
61
78
  @duration ||= 1000.0 * (self.end - time)
62
79
  end
@@ -94,9 +94,9 @@ module ActiveSupport
94
94
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
95
95
  # (defaults to current locale).
96
96
  # * <tt>:precision</tt> - Sets the precision of the number
97
- # (defaults to 3).
98
- # * <tt>:significant</tt> - If +true+, precision will be the #
99
- # of significant_digits. If +false+, the # of fractional
97
+ # (defaults to 3). Keeps the number's precision if nil.
98
+ # * <tt>:significant</tt> - If +true+, precision will be the number
99
+ # of significant_digits. If +false+, the number of fractional
100
100
  # digits (defaults to +false+).
101
101
  # * <tt>:separator</tt> - Sets the separator between the
102
102
  # fractional and integer digits (defaults to ".").
@@ -115,9 +115,10 @@ module ActiveSupport
115
115
  # number_to_percentage(100, precision: 0) # => 100%
116
116
  # number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000%
117
117
  # number_to_percentage(302.24398923423, precision: 5) # => 302.24399%
118
- # number_to_percentage(1000, locale: :fr) # => 1 000,000%
118
+ # number_to_percentage(1000, locale: :fr) # => 1000,000%
119
+ # number_to_percentage(1000, precision: nil) # => 1000%
119
120
  # number_to_percentage('98a') # => 98a%
120
- # number_to_percentage(100, format: '%n %') # => 100 %
121
+ # number_to_percentage(100, format: '%n %') # => 100.000 %
121
122
  def number_to_percentage(number, options = {})
122
123
  NumberToPercentageConverter.convert(number, options)
123
124
  end
@@ -134,6 +135,9 @@ module ActiveSupport
134
135
  # to ",").
135
136
  # * <tt>:separator</tt> - Sets the separator between the
136
137
  # fractional and integer digits (defaults to ".").
138
+ # * <tt>:delimiter_pattern</tt> - Sets a custom regular expression used for
139
+ # deriving the placement of delimiter. Helpful when using currency formats
140
+ # like INR.
137
141
  #
138
142
  # ==== Examples
139
143
  #
@@ -146,7 +150,10 @@ module ActiveSupport
146
150
  # number_to_delimited(12345678.05, locale: :fr) # => 12 345 678,05
147
151
  # number_to_delimited('112a') # => 112a
148
152
  # number_to_delimited(98765432.98, delimiter: ' ', separator: ',')
149
- # # => 98 765 432,98
153
+ # # => 98 765 432,98
154
+ # number_to_delimited("123456.78",
155
+ # delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/)
156
+ # # => 1,23,456.78
150
157
  def number_to_delimited(number, options = {})
151
158
  NumberToDelimitedConverter.convert(number, options)
152
159
  end
@@ -161,9 +168,9 @@ module ActiveSupport
161
168
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
162
169
  # (defaults to current locale).
163
170
  # * <tt>:precision</tt> - Sets the precision of the number
164
- # (defaults to 3).
165
- # * <tt>:significant</tt> - If +true+, precision will be the #
166
- # of significant_digits. If +false+, the # of fractional
171
+ # (defaults to 3). Keeps the number's precision if nil.
172
+ # * <tt>:significant</tt> - If +true+, precision will be the number
173
+ # of significant_digits. If +false+, the number of fractional
167
174
  # digits (defaults to +false+).
168
175
  # * <tt>:separator</tt> - Sets the separator between the
169
176
  # fractional and integer digits (defaults to ".").
@@ -182,6 +189,7 @@ module ActiveSupport
182
189
  # number_to_rounded(111.2345, significant: true) # => 111
183
190
  # number_to_rounded(111.2345, precision: 1, significant: true) # => 100
184
191
  # number_to_rounded(13, precision: 5, significant: true) # => 13.000
192
+ # number_to_rounded(13, precision: nil) # => 13
185
193
  # number_to_rounded(111.234, locale: :fr) # => 111,234
186
194
  #
187
195
  # number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true)
@@ -208,8 +216,8 @@ module ActiveSupport
208
216
  # (defaults to current locale).
209
217
  # * <tt>:precision</tt> - Sets the precision of the number
210
218
  # (defaults to 3).
211
- # * <tt>:significant</tt> - If +true+, precision will be the #
212
- # of significant_digits. If +false+, the # of fractional
219
+ # * <tt>:significant</tt> - If +true+, precision will be the number
220
+ # of significant_digits. If +false+, the number of fractional
213
221
  # digits (defaults to +true+)
214
222
  # * <tt>:separator</tt> - Sets the separator between the
215
223
  # fractional and integer digits (defaults to ".").
@@ -218,8 +226,6 @@ module ActiveSupport
218
226
  # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
219
227
  # insignificant zeros after the decimal separator (defaults to
220
228
  # +true+)
221
- # * <tt>:prefix</tt> - If +:si+ formats the number using the SI
222
- # prefix (defaults to :binary)
223
229
  #
224
230
  # ==== Examples
225
231
  #
@@ -258,8 +264,8 @@ module ActiveSupport
258
264
  # (defaults to current locale).
259
265
  # * <tt>:precision</tt> - Sets the precision of the number
260
266
  # (defaults to 3).
261
- # * <tt>:significant</tt> - If +true+, precision will be the #
262
- # of significant_digits. If +false+, the # of fractional
267
+ # * <tt>:significant</tt> - If +true+, precision will be the number
268
+ # of significant_digits. If +false+, the number of fractional
263
269
  # digits (defaults to +true+)
264
270
  # * <tt>:separator</tt> - Sets the separator between the
265
271
  # fractional and integer digits (defaults to ".").
@@ -13,7 +13,7 @@ module ActiveSupport
13
13
  end
14
14
 
15
15
  rounded_number = NumberToRoundedConverter.convert(number, options)
16
- format.gsub(/%n/, rounded_number).gsub(/%u/, options[:unit])
16
+ format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, options[:unit])
17
17
  end
18
18
 
19
19
  private
@@ -23,20 +23,20 @@ module ActiveSupport
23
23
  end
24
24
 
25
25
  def absolute_value(number)
26
- number.respond_to?("abs") ? number.abs : number.sub(/\A-/, '')
26
+ number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, '')
27
27
  end
28
28
 
29
29
  def options
30
30
  @options ||= begin
31
31
  defaults = default_format_options.merge(i18n_opts)
32
- # Override negative format if format options is given
32
+ # Override negative format if format options are given
33
33
  defaults[:negative_format] = "-#{opts[:format]}" if opts[:format]
34
34
  defaults.merge!(opts)
35
35
  end
36
36
  end
37
37
 
38
38
  def i18n_opts
39
- # Set International negative format if not exists
39
+ # Set International negative format if it does not exist
40
40
  i18n = i18n_format_options
41
41
  i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format]
42
42
  i18n
@@ -3,7 +3,7 @@ module ActiveSupport
3
3
  class NumberToDelimitedConverter < NumberConverter #:nodoc:
4
4
  self.validate_float = true
5
5
 
6
- DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
6
+ DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
7
7
 
8
8
  def convert
9
9
  parts.join(options[:separator])
@@ -13,11 +13,16 @@ module ActiveSupport
13
13
 
14
14
  def parts
15
15
  left, right = number.to_s.split('.')
16
- left.gsub!(DELIMITED_REGEX) do |digit_to_delimit|
16
+ left.gsub!(delimiter_pattern) do |digit_to_delimit|
17
17
  "#{digit_to_delimit}#{options[:delimiter]}"
18
18
  end
19
19
  [left, right].compact
20
20
  end
21
+
22
+ def delimiter_pattern
23
+ options.fetch(:delimiter_pattern, DEFAULT_DELIMITER_REGEX)
24
+ end
25
+
21
26
  end
22
27
  end
23
28
  end
@@ -20,10 +20,12 @@ module ActiveSupport
20
20
  exponent = calculate_exponent(units)
21
21
  @number = number / (10 ** exponent)
22
22
 
23
+ until (rounded_number = NumberToRoundedConverter.convert(number, options)) != NumberToRoundedConverter.convert(1000, options)
24
+ @number = number / 1000.0
25
+ exponent += 3
26
+ end
23
27
  unit = determine_unit(units, exponent)
24
-
25
- rounded_number = NumberToRoundedConverter.convert(number, options)
26
- format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip
28
+ format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, unit).strip
27
29
  end
28
30
 
29
31
  private
@@ -59,7 +61,7 @@ module ActiveSupport
59
61
  translate_in_locale("human.decimal_units.units", raise: true)
60
62
  else
61
63
  raise ArgumentError, ":units must be a Hash or String translation scope."
62
- end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by { |e| -e }
64
+ end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by(&:-@)
63
65
  end
64
66
  end
65
67
  end
@@ -7,6 +7,10 @@ module ActiveSupport
7
7
  self.validate_float = true
8
8
 
9
9
  def convert
10
+ if opts.key?(:prefix)
11
+ ActiveSupport::Deprecation.warn('The :prefix option of `number_to_human_size` is deprecated and will be removed in Rails 5.1 with no replacement.')
12
+ end
13
+
10
14
  @number = Float(number)
11
15
 
12
16
  # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
@@ -20,7 +24,7 @@ module ActiveSupport
20
24
  human_size = number / (base ** exponent)
21
25
  number_to_format = NumberToRoundedConverter.convert(human_size, options)
22
26
  end
23
- conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit)
27
+ conversion_format.gsub('%n'.freeze, number_to_format).gsub('%u'.freeze, unit)
24
28
  end
25
29
 
26
30
  private
@@ -5,7 +5,7 @@ module ActiveSupport
5
5
 
6
6
  def convert
7
7
  rounded_number = NumberToRoundedConverter.convert(number, options)
8
- options[:format].gsub(/%n/, rounded_number)
8
+ options[:format].gsub('%n'.freeze, rounded_number)
9
9
  end
10
10
  end
11
11
  end
@@ -6,36 +6,39 @@ module ActiveSupport
6
6
 
7
7
  def convert
8
8
  precision = options.delete :precision
9
- significant = options.delete :significant
10
9
 
11
- case number
12
- when Float, String
13
- @number = BigDecimal(number.to_s)
14
- when Rational
15
- @number = BigDecimal(number, digit_count(number.to_i) + precision)
16
- else
17
- @number = number.to_d
18
- end
19
-
20
- if significant && precision > 0
21
- digits, rounded_number = digits_and_rounded_number(precision)
22
- precision -= digits
23
- precision = 0 if precision < 0 # don't let it be negative
24
- else
25
- rounded_number = number.round(precision)
26
- rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite?
27
- rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
28
- end
10
+ if precision
11
+ case number
12
+ when Float, String
13
+ @number = BigDecimal(number.to_s)
14
+ when Rational
15
+ @number = BigDecimal(number, digit_count(number.to_i) + precision)
16
+ else
17
+ @number = number.to_d
18
+ end
29
19
 
30
- formatted_string =
31
- if BigDecimal === rounded_number && rounded_number.finite?
32
- s = rounded_number.to_s('F') + '0'*precision
33
- a, b = s.split('.', 2)
34
- a + '.' + b[0, precision]
20
+ if options.delete(:significant) && precision > 0
21
+ digits, rounded_number = digits_and_rounded_number(precision)
22
+ precision -= digits
23
+ precision = 0 if precision < 0 # don't let it be negative
35
24
  else
36
- "%00.#{precision}f" % rounded_number
25
+ rounded_number = number.round(precision)
26
+ rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite?
27
+ rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
37
28
  end
38
29
 
30
+ formatted_string =
31
+ if BigDecimal === rounded_number && rounded_number.finite?
32
+ s = rounded_number.to_s('F') + '0'*precision
33
+ a, b = s.split('.', 2)
34
+ a + '.' + b[0, precision]
35
+ else
36
+ "%00.#{precision}f" % rounded_number
37
+ end
38
+ else
39
+ formatted_string = number
40
+ end
41
+
39
42
  delimited_number = NumberToDelimitedConverter.convert(formatted_string, options)
40
43
  format_number(delimited_number)
41
44
  end