activesupport 5.2.4.4 → 6.1.1

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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +353 -435
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +14 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +29 -3
  9. data/lib/active_support/benchmarkable.rb +1 -1
  10. data/lib/active_support/cache.rb +142 -78
  11. data/lib/active_support/cache/file_store.rb +33 -33
  12. data/lib/active_support/cache/mem_cache_store.rb +32 -20
  13. data/lib/active_support/cache/memory_store.rb +59 -33
  14. data/lib/active_support/cache/null_store.rb +8 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +70 -43
  16. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  17. data/lib/active_support/callbacks.rb +81 -64
  18. data/lib/active_support/concern.rb +70 -3
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  20. data/lib/active_support/concurrency/share_lock.rb +0 -1
  21. data/lib/active_support/configurable.rb +10 -14
  22. data/lib/active_support/configuration_file.rb +46 -0
  23. data/lib/active_support/core_ext.rb +1 -1
  24. data/lib/active_support/core_ext/array.rb +1 -1
  25. data/lib/active_support/core_ext/array/access.rb +18 -6
  26. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  30. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  31. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  32. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  36. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  37. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  38. data/lib/active_support/core_ext/enumerable.rb +171 -75
  39. data/lib/active_support/core_ext/hash.rb +1 -2
  40. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  41. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  42. data/lib/active_support/core_ext/hash/except.rb +2 -2
  43. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  44. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  45. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  46. data/lib/active_support/core_ext/kernel.rb +0 -1
  47. data/lib/active_support/core_ext/load_error.rb +1 -1
  48. data/lib/active_support/core_ext/marshal.rb +2 -0
  49. data/lib/active_support/core_ext/module.rb +0 -1
  50. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  53. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  54. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  55. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  56. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  57. data/lib/active_support/core_ext/name_error.rb +29 -2
  58. data/lib/active_support/core_ext/numeric.rb +0 -1
  59. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  60. data/lib/active_support/core_ext/object/blank.rb +1 -2
  61. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  62. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  63. data/lib/active_support/core_ext/object/json.rb +14 -2
  64. data/lib/active_support/core_ext/object/try.rb +17 -7
  65. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  66. data/lib/active_support/core_ext/range/compare_range.rb +34 -13
  67. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  68. data/lib/active_support/core_ext/range/each.rb +0 -1
  69. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  70. data/lib/active_support/core_ext/regexp.rb +8 -5
  71. data/lib/active_support/core_ext/securerandom.rb +23 -3
  72. data/lib/active_support/core_ext/string/access.rb +5 -16
  73. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  74. data/lib/active_support/core_ext/string/filters.rb +42 -1
  75. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  76. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  77. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  78. data/lib/active_support/core_ext/string/output_safety.rb +70 -13
  79. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  80. data/lib/active_support/core_ext/string/strip.rb +3 -1
  81. data/lib/active_support/core_ext/symbol.rb +3 -0
  82. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  83. data/lib/active_support/core_ext/time/calculations.rb +50 -3
  84. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  85. data/lib/active_support/core_ext/uri.rb +6 -1
  86. data/lib/active_support/current_attributes.rb +15 -2
  87. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  88. data/lib/active_support/dependencies.rb +109 -34
  89. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  90. data/lib/active_support/deprecation.rb +6 -1
  91. data/lib/active_support/deprecation/behaviors.rb +16 -3
  92. data/lib/active_support/deprecation/disallowed.rb +56 -0
  93. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  94. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  95. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  96. data/lib/active_support/deprecation/reporting.rb +50 -7
  97. data/lib/active_support/descendants_tracker.rb +59 -9
  98. data/lib/active_support/duration.rb +90 -38
  99. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  100. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  101. data/lib/active_support/encrypted_configuration.rb +0 -4
  102. data/lib/active_support/encrypted_file.rb +22 -4
  103. data/lib/active_support/environment_inquirer.rb +20 -0
  104. data/lib/active_support/evented_file_update_checker.rb +82 -117
  105. data/lib/active_support/execution_wrapper.rb +1 -0
  106. data/lib/active_support/file_update_checker.rb +0 -1
  107. data/lib/active_support/fork_tracker.rb +62 -0
  108. data/lib/active_support/gem_version.rb +4 -4
  109. data/lib/active_support/hash_with_indifferent_access.rb +64 -41
  110. data/lib/active_support/i18n.rb +1 -0
  111. data/lib/active_support/i18n_railtie.rb +15 -8
  112. data/lib/active_support/inflector/inflections.rb +2 -7
  113. data/lib/active_support/inflector/methods.rb +49 -58
  114. data/lib/active_support/inflector/transliterate.rb +47 -18
  115. data/lib/active_support/json/decoding.rb +25 -26
  116. data/lib/active_support/json/encoding.rb +11 -3
  117. data/lib/active_support/key_generator.rb +1 -33
  118. data/lib/active_support/lazy_load_hooks.rb +5 -2
  119. data/lib/active_support/locale/en.rb +33 -0
  120. data/lib/active_support/locale/en.yml +7 -3
  121. data/lib/active_support/log_subscriber.rb +39 -9
  122. data/lib/active_support/logger.rb +2 -17
  123. data/lib/active_support/logger_silence.rb +11 -19
  124. data/lib/active_support/logger_thread_safe_level.rb +50 -6
  125. data/lib/active_support/message_encryptor.rb +8 -13
  126. data/lib/active_support/message_verifier.rb +10 -10
  127. data/lib/active_support/messages/metadata.rb +11 -2
  128. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  129. data/lib/active_support/messages/rotator.rb +10 -9
  130. data/lib/active_support/multibyte/chars.rb +10 -68
  131. data/lib/active_support/multibyte/unicode.rb +15 -327
  132. data/lib/active_support/notifications.rb +72 -8
  133. data/lib/active_support/notifications/fanout.rb +116 -16
  134. data/lib/active_support/notifications/instrumenter.rb +71 -9
  135. data/lib/active_support/number_helper.rb +38 -12
  136. data/lib/active_support/number_helper/number_converter.rb +5 -6
  137. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  138. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  139. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  140. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  141. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  142. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  143. data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
  144. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  145. data/lib/active_support/option_merger.rb +22 -3
  146. data/lib/active_support/ordered_hash.rb +1 -1
  147. data/lib/active_support/ordered_options.rb +13 -3
  148. data/lib/active_support/parameter_filter.rb +133 -0
  149. data/lib/active_support/per_thread_registry.rb +1 -1
  150. data/lib/active_support/rails.rb +1 -10
  151. data/lib/active_support/railtie.rb +23 -1
  152. data/lib/active_support/reloader.rb +4 -5
  153. data/lib/active_support/rescuable.rb +4 -4
  154. data/lib/active_support/secure_compare_rotator.rb +51 -0
  155. data/lib/active_support/security_utils.rb +19 -12
  156. data/lib/active_support/string_inquirer.rb +4 -3
  157. data/lib/active_support/subscriber.rb +72 -28
  158. data/lib/active_support/tagged_logging.rb +42 -8
  159. data/lib/active_support/test_case.rb +91 -0
  160. data/lib/active_support/testing/assertions.rb +30 -9
  161. data/lib/active_support/testing/deprecation.rb +0 -1
  162. data/lib/active_support/testing/file_fixtures.rb +2 -0
  163. data/lib/active_support/testing/isolation.rb +2 -2
  164. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  165. data/lib/active_support/testing/parallelization.rb +51 -0
  166. data/lib/active_support/testing/parallelization/server.rb +78 -0
  167. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  168. data/lib/active_support/testing/stream.rb +1 -2
  169. data/lib/active_support/testing/time_helpers.rb +47 -12
  170. data/lib/active_support/time_with_zone.rb +81 -47
  171. data/lib/active_support/values/time_zone.rb +32 -17
  172. data/lib/active_support/xml_mini.rb +2 -10
  173. data/lib/active_support/xml_mini/jdom.rb +2 -3
  174. data/lib/active_support/xml_mini/libxml.rb +2 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  178. data/lib/active_support/xml_mini/rexml.rb +10 -3
  179. metadata +58 -32
  180. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  181. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  182. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  183. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  184. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  185. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  186. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  187. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -2,6 +2,8 @@
2
2
 
3
3
  require "mutex_m"
4
4
  require "concurrent/map"
5
+ require "set"
6
+ require "active_support/core_ext/object/try"
5
7
 
6
8
  module ActiveSupport
7
9
  module Notifications
@@ -13,16 +15,22 @@ module ActiveSupport
13
15
  include Mutex_m
14
16
 
15
17
  def initialize
16
- @subscribers = []
18
+ @string_subscribers = Hash.new { |h, k| h[k] = [] }
19
+ @other_subscribers = []
17
20
  @listeners_for = Concurrent::Map.new
18
21
  super
19
22
  end
20
23
 
21
- def subscribe(pattern = nil, callable = nil, &block)
22
- subscriber = Subscribers.new(pattern, callable || block)
24
+ def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
25
+ subscriber = Subscribers.new(pattern, callable || block, monotonic)
23
26
  synchronize do
24
- @subscribers << subscriber
25
- @listeners_for.clear
27
+ if String === pattern
28
+ @string_subscribers[pattern] << subscriber
29
+ @listeners_for.delete(pattern)
30
+ else
31
+ @other_subscribers << subscriber
32
+ @listeners_for.clear
33
+ end
26
34
  end
27
35
  subscriber
28
36
  end
@@ -31,12 +39,19 @@ module ActiveSupport
31
39
  synchronize do
32
40
  case subscriber_or_name
33
41
  when String
34
- @subscribers.reject! { |s| s.matches?(subscriber_or_name) }
42
+ @string_subscribers[subscriber_or_name].clear
43
+ @listeners_for.delete(subscriber_or_name)
44
+ @other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
35
45
  else
36
- @subscribers.delete(subscriber_or_name)
46
+ pattern = subscriber_or_name.try(:pattern)
47
+ if String === pattern
48
+ @string_subscribers[pattern].delete(subscriber_or_name)
49
+ @listeners_for.delete(pattern)
50
+ else
51
+ @other_subscribers.delete(subscriber_or_name)
52
+ @listeners_for.clear
53
+ end
37
54
  end
38
-
39
- @listeners_for.clear
40
55
  end
41
56
  end
42
57
 
@@ -56,7 +71,8 @@ module ActiveSupport
56
71
  # this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
57
72
  @listeners_for[name] || synchronize do
58
73
  # use synchronisation when accessing @subscribers
59
- @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
74
+ @listeners_for[name] ||=
75
+ @string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
60
76
  end
61
77
  end
62
78
 
@@ -69,13 +85,26 @@ module ActiveSupport
69
85
  end
70
86
 
71
87
  module Subscribers # :nodoc:
72
- def self.new(pattern, listener)
88
+ def self.new(pattern, listener, monotonic)
89
+ subscriber_class = monotonic ? MonotonicTimed : Timed
90
+
73
91
  if listener.respond_to?(:start) && listener.respond_to?(:finish)
74
- subscriber = Evented.new pattern, listener
92
+ subscriber_class = Evented
75
93
  else
76
- subscriber = Timed.new pattern, listener
94
+ # Doing all this to detect a block like `proc { |x| }` vs
95
+ # `proc { |*x| }` or `proc { |**x| }`
96
+ if listener.respond_to?(:parameters)
97
+ params = listener.parameters
98
+ if params.length == 1 && params.first.first == :opt
99
+ subscriber_class = EventObject
100
+ end
101
+ end
77
102
  end
78
103
 
104
+ wrap_all pattern, subscriber_class.new(pattern, listener)
105
+ end
106
+
107
+ def self.wrap_all(pattern, subscriber)
79
108
  unless pattern
80
109
  AllMessages.new(subscriber)
81
110
  else
@@ -83,9 +112,33 @@ module ActiveSupport
83
112
  end
84
113
  end
85
114
 
115
+ class Matcher #:nodoc:
116
+ attr_reader :pattern, :exclusions
117
+
118
+ def self.wrap(pattern)
119
+ return pattern if String === pattern
120
+ new(pattern)
121
+ end
122
+
123
+ def initialize(pattern)
124
+ @pattern = pattern
125
+ @exclusions = Set.new
126
+ end
127
+
128
+ def unsubscribe!(name)
129
+ exclusions << -name if pattern === name
130
+ end
131
+
132
+ def ===(name)
133
+ pattern === name && !exclusions.include?(name)
134
+ end
135
+ end
136
+
86
137
  class Evented #:nodoc:
138
+ attr_reader :pattern
139
+
87
140
  def initialize(pattern, delegate)
88
- @pattern = pattern
141
+ @pattern = Matcher.wrap(pattern)
89
142
  @delegate = delegate
90
143
  @can_publish = delegate.respond_to?(:publish)
91
144
  end
@@ -105,11 +158,15 @@ module ActiveSupport
105
158
  end
106
159
 
107
160
  def subscribed_to?(name)
108
- @pattern === name
161
+ pattern === name
109
162
  end
110
163
 
111
164
  def matches?(name)
112
- @pattern && @pattern === name
165
+ pattern && pattern === name
166
+ end
167
+
168
+ def unsubscribe!(name)
169
+ pattern.unsubscribe!(name)
113
170
  end
114
171
  end
115
172
 
@@ -130,6 +187,45 @@ module ActiveSupport
130
187
  end
131
188
  end
132
189
 
190
+ class MonotonicTimed < Evented # :nodoc:
191
+ def publish(name, *args)
192
+ @delegate.call name, *args
193
+ end
194
+
195
+ def start(name, id, payload)
196
+ timestack = Thread.current[:_timestack_monotonic] ||= []
197
+ timestack.push Concurrent.monotonic_time
198
+ end
199
+
200
+ def finish(name, id, payload)
201
+ timestack = Thread.current[:_timestack_monotonic]
202
+ started = timestack.pop
203
+ @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
204
+ end
205
+ end
206
+
207
+ class EventObject < Evented
208
+ def start(name, id, payload)
209
+ stack = Thread.current[:_event_stack] ||= []
210
+ event = build_event name, id, payload
211
+ event.start!
212
+ stack.push event
213
+ end
214
+
215
+ def finish(name, id, payload)
216
+ stack = Thread.current[:_event_stack]
217
+ event = stack.pop
218
+ event.payload = payload
219
+ event.finish!
220
+ @delegate.call event
221
+ end
222
+
223
+ private
224
+ def build_event(name, id, payload)
225
+ ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
226
+ end
227
+ end
228
+
133
229
  class AllMessages # :nodoc:
134
230
  def initialize(delegate)
135
231
  @delegate = delegate
@@ -151,6 +247,10 @@ module ActiveSupport
151
247
  true
152
248
  end
153
249
 
250
+ def unsubscribe!(*)
251
+ false
252
+ end
253
+
154
254
  alias :matches? :===
155
255
  end
156
256
  end
@@ -13,14 +13,15 @@ module ActiveSupport
13
13
  @notifier = notifier
14
14
  end
15
15
 
16
- # Instrument the given block by measuring the time taken to execute it
17
- # and publish it. Notice that events get sent even if an error occurs
18
- # in the passed-in block.
16
+ # Given a block, instrument it by measuring the time taken to execute
17
+ # and publish it. Without a block, simply send a message via the
18
+ # notifier. Notice that events get sent even if an error occurs in the
19
+ # passed-in block.
19
20
  def instrument(name, payload = {})
20
21
  # some of the listeners might have state
21
22
  listeners_state = start name, payload
22
23
  begin
23
- yield payload
24
+ yield payload if block_given?
24
25
  rescue Exception => e
25
26
  payload[:exception] = [e.class.name, e.message]
26
27
  payload[:exception_object] = e
@@ -45,15 +46,14 @@ module ActiveSupport
45
46
  end
46
47
 
47
48
  private
48
-
49
49
  def unique_id
50
50
  SecureRandom.hex(10)
51
51
  end
52
52
  end
53
53
 
54
54
  class Event
55
- attr_reader :name, :time, :transaction_id, :payload, :children
56
- attr_accessor :end
55
+ attr_reader :name, :time, :end, :transaction_id, :children
56
+ attr_accessor :payload
57
57
 
58
58
  def initialize(name, start, ending, transaction_id, payload)
59
59
  @name = name
@@ -62,7 +62,42 @@ module ActiveSupport
62
62
  @transaction_id = transaction_id
63
63
  @end = ending
64
64
  @children = []
65
- @duration = nil
65
+ @cpu_time_start = 0
66
+ @cpu_time_finish = 0
67
+ @allocation_count_start = 0
68
+ @allocation_count_finish = 0
69
+ end
70
+
71
+ # Record information at the time this event starts
72
+ def start!
73
+ @time = now
74
+ @cpu_time_start = now_cpu
75
+ @allocation_count_start = now_allocations
76
+ end
77
+
78
+ # Record information at the time this event finishes
79
+ def finish!
80
+ @cpu_time_finish = now_cpu
81
+ @end = now
82
+ @allocation_count_finish = now_allocations
83
+ end
84
+
85
+ # Returns the CPU time (in milliseconds) passed since the call to
86
+ # +start!+ and the call to +finish!+
87
+ def cpu_time
88
+ (@cpu_time_finish - @cpu_time_start) * 1000
89
+ end
90
+
91
+ # Returns the idle time time (in milliseconds) passed since the call to
92
+ # +start!+ and the call to +finish!+
93
+ def idle_time
94
+ duration - cpu_time
95
+ end
96
+
97
+ # Returns the number of allocations made since the call to +start!+ and
98
+ # the call to +finish!+
99
+ def allocations
100
+ @allocation_count_finish - @allocation_count_start
66
101
  end
67
102
 
68
103
  # Returns the difference in milliseconds between when the execution of the
@@ -78,7 +113,7 @@ module ActiveSupport
78
113
  #
79
114
  # @event.duration # => 1000.138
80
115
  def duration
81
- @duration ||= 1000.0 * (self.end - time)
116
+ 1000.0 * (self.end - time)
82
117
  end
83
118
 
84
119
  def <<(event)
@@ -88,6 +123,33 @@ module ActiveSupport
88
123
  def parent_of?(event)
89
124
  @children.include? event
90
125
  end
126
+
127
+ private
128
+ def now
129
+ Concurrent.monotonic_time
130
+ end
131
+
132
+ begin
133
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
134
+
135
+ def now_cpu
136
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
137
+ end
138
+ rescue
139
+ def now_cpu
140
+ 0
141
+ end
142
+ end
143
+
144
+ if defined?(JRUBY_VERSION)
145
+ def now_allocations
146
+ 0
147
+ end
148
+ else
149
+ def now_allocations
150
+ GC.stat :total_allocated_objects
151
+ end
152
+ end
91
153
  end
92
154
  end
93
155
  end
@@ -71,6 +71,8 @@ module ActiveSupport
71
71
  # (defaults to current locale).
72
72
  # * <tt>:precision</tt> - Sets the level of precision (defaults
73
73
  # to 2).
74
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
75
+ # (defaults to :default. See BigDecimal::mode)
74
76
  # * <tt>:unit</tt> - Sets the denomination of the currency
75
77
  # (defaults to "$").
76
78
  # * <tt>:separator</tt> - Sets the separator between the units
@@ -85,6 +87,9 @@ module ActiveSupport
85
87
  # number given by <tt>:format</tt>). Accepts the same fields
86
88
  # than <tt>:format</tt>, except <tt>%n</tt> is here the
87
89
  # absolute value of the number.
90
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
91
+ # insignificant zeros after the decimal separator (defaults to
92
+ # +false+).
88
93
  #
89
94
  # ==== Examples
90
95
  #
@@ -94,12 +99,20 @@ module ActiveSupport
94
99
  # number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
95
100
  # number_to_currency('123a456') # => "$123a456"
96
101
  #
102
+ # number_to_currency("123a456", raise: true) # => InvalidNumberError
103
+ #
104
+ # number_to_currency(-0.456789, precision: 0)
105
+ # # => "$0"
97
106
  # number_to_currency(-1234567890.50, negative_format: '(%u%n)')
98
107
  # # => "($1,234,567,890.50)"
99
108
  # number_to_currency(1234567890.50, unit: '&pound;', separator: ',', delimiter: '')
100
109
  # # => "&pound;1234567890,50"
101
110
  # number_to_currency(1234567890.50, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
102
111
  # # => "1234567890,50 &pound;"
112
+ # number_to_currency(1234567890.50, strip_insignificant_zeros: true)
113
+ # # => "$1,234,567,890.5"
114
+ # number_to_currency(1234567890.50, precision: 0, round_mode: :up)
115
+ # # => "$1,234,567,891"
103
116
  def number_to_currency(number, options = {})
104
117
  NumberToCurrencyConverter.convert(number, options)
105
118
  end
@@ -113,6 +126,8 @@ module ActiveSupport
113
126
  # (defaults to current locale).
114
127
  # * <tt>:precision</tt> - Sets the precision of the number
115
128
  # (defaults to 3). Keeps the number's precision if +nil+.
129
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
130
+ # (defaults to :default. See BigDecimal::mode)
116
131
  # * <tt>:significant</tt> - If +true+, precision will be the number
117
132
  # of significant_digits. If +false+, the number of fractional
118
133
  # digits (defaults to +false+).
@@ -128,15 +143,16 @@ module ActiveSupport
128
143
  #
129
144
  # ==== Examples
130
145
  #
131
- # number_to_percentage(100) # => "100.000%"
132
- # number_to_percentage('98') # => "98.000%"
133
- # number_to_percentage(100, precision: 0) # => "100%"
134
- # number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
135
- # number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
136
- # number_to_percentage(1000, locale: :fr) # => "1000,000%"
137
- # number_to_percentage(1000, precision: nil) # => "1000%"
138
- # number_to_percentage('98a') # => "98a%"
139
- # number_to_percentage(100, format: '%n %') # => "100.000 %"
146
+ # number_to_percentage(100) # => "100.000%"
147
+ # number_to_percentage('98') # => "98.000%"
148
+ # number_to_percentage(100, precision: 0) # => "100%"
149
+ # number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
150
+ # number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
151
+ # number_to_percentage(1000, locale: :fr) # => "1000,000%"
152
+ # number_to_percentage(1000, precision: nil) # => "1000%"
153
+ # number_to_percentage('98a') # => "98a%"
154
+ # number_to_percentage(100, format: '%n %') # => "100.000 %"
155
+ # number_to_percentage(302.24398923423, precision: 5, round_mode: :down) # => "302.24398%"
140
156
  def number_to_percentage(number, options = {})
141
157
  NumberToPercentageConverter.convert(number, options)
142
158
  end
@@ -187,6 +203,8 @@ module ActiveSupport
187
203
  # (defaults to current locale).
188
204
  # * <tt>:precision</tt> - Sets the precision of the number
189
205
  # (defaults to 3). Keeps the number's precision if +nil+.
206
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
207
+ # (defaults to :default. See BigDecimal::mode)
190
208
  # * <tt>:significant</tt> - If +true+, precision will be the number
191
209
  # of significant_digits. If +false+, the number of fractional
192
210
  # digits (defaults to +false+).
@@ -208,6 +226,7 @@ module ActiveSupport
208
226
  # number_to_rounded(111.2345, precision: 1, significant: true) # => "100"
209
227
  # number_to_rounded(13, precision: 5, significant: true) # => "13.000"
210
228
  # number_to_rounded(13, precision: nil) # => "13"
229
+ # number_to_rounded(389.32314, precision: 0, round_mode: :up) # => "390"
211
230
  # number_to_rounded(111.234, locale: :fr) # => "111,234"
212
231
  #
213
232
  # number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true)
@@ -221,7 +240,7 @@ module ActiveSupport
221
240
  end
222
241
 
223
242
  # Formats the bytes in +number+ into a more understandable
224
- # representation (e.g., giving it 1500 yields 1.5 KB). This
243
+ # representation (e.g., giving it 1500 yields 1.46 KB). This
225
244
  # method is useful for reporting file sizes to users. You can
226
245
  # customize the format in the +options+ hash.
227
246
  #
@@ -234,6 +253,8 @@ module ActiveSupport
234
253
  # (defaults to current locale).
235
254
  # * <tt>:precision</tt> - Sets the precision of the number
236
255
  # (defaults to 3).
256
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
257
+ # (defaults to :default. See BigDecimal::mode)
237
258
  # * <tt>:significant</tt> - If +true+, precision will be the number
238
259
  # of significant_digits. If +false+, the number of fractional
239
260
  # digits (defaults to +true+)
@@ -257,6 +278,7 @@ module ActiveSupport
257
278
  # number_to_human_size(1234567890123456789) # => "1.07 EB"
258
279
  # number_to_human_size(1234567, precision: 2) # => "1.2 MB"
259
280
  # number_to_human_size(483989, precision: 2) # => "470 KB"
281
+ # number_to_human_size(483989, precision: 2, round_mode: :up) # => "480 KB"
260
282
  # number_to_human_size(1234567, precision: 2, separator: ',') # => "1,2 MB"
261
283
  # number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
262
284
  # number_to_human_size(524288000, precision: 5) # => "500 MB"
@@ -265,7 +287,7 @@ module ActiveSupport
265
287
  end
266
288
 
267
289
  # Pretty prints (formats and approximates) a number in a way it
268
- # is more readable by humans (eg.: 1200000000 becomes "1.2
290
+ # is more readable by humans (e.g.: 1200000000 becomes "1.2
269
291
  # Billion"). This is useful for numbers that can get very large
270
292
  # (and too hard to read).
271
293
  #
@@ -273,7 +295,7 @@ module ActiveSupport
273
295
  # size.
274
296
  #
275
297
  # You can also define your own unit-quantifier names if you want
276
- # to use other decimal units (eg.: 1500 becomes "1.5
298
+ # to use other decimal units (e.g.: 1500 becomes "1.5
277
299
  # kilometers", 0.150 becomes "150 milliliters", etc). You may
278
300
  # define a wide range of unit quantifiers, even fractional ones
279
301
  # (centi, deci, mili, etc).
@@ -284,6 +306,8 @@ module ActiveSupport
284
306
  # (defaults to current locale).
285
307
  # * <tt>:precision</tt> - Sets the precision of the number
286
308
  # (defaults to 3).
309
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
310
+ # (defaults to :default. See BigDecimal::mode)
287
311
  # * <tt>:significant</tt> - If +true+, precision will be the number
288
312
  # of significant_digits. If +false+, the number of fractional
289
313
  # digits (defaults to +true+)
@@ -321,6 +345,8 @@ module ActiveSupport
321
345
  # number_to_human(1234567890123456789) # => "1230 Quadrillion"
322
346
  # number_to_human(489939, precision: 2) # => "490 Thousand"
323
347
  # number_to_human(489939, precision: 4) # => "489.9 Thousand"
348
+ # number_to_human(489939, precision: 2
349
+ # , round_mode: :down) # => "480 Thousand"
324
350
  # number_to_human(1234567, precision: 4,
325
351
  # significant: false) # => "1.2346 Million"
326
352
  # number_to_human(1234567, precision: 1,