activesupport 6.1.4.1 → 7.0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +325 -395
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/backtrace_cleaner.rb +2 -2
  8. data/lib/active_support/benchmarkable.rb +2 -2
  9. data/lib/active_support/cache/file_store.rb +15 -9
  10. data/lib/active_support/cache/mem_cache_store.rb +148 -37
  11. data/lib/active_support/cache/memory_store.rb +24 -16
  12. data/lib/active_support/cache/null_store.rb +10 -2
  13. data/lib/active_support/cache/redis_cache_store.rb +68 -85
  14. data/lib/active_support/cache/strategy/local_cache.rb +38 -61
  15. data/lib/active_support/cache.rb +299 -147
  16. data/lib/active_support/callbacks.rb +184 -85
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +5 -5
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  20. data/lib/active_support/concurrency/share_lock.rb +2 -2
  21. data/lib/active_support/configurable.rb +8 -5
  22. data/lib/active_support/configuration_file.rb +1 -1
  23. data/lib/active_support/core_ext/array/access.rb +1 -5
  24. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  25. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  27. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  28. data/lib/active_support/core_ext/array.rb +1 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  31. data/lib/active_support/core_ext/date/blank.rb +1 -1
  32. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  33. data/lib/active_support/core_ext/date/conversions.rb +14 -14
  34. data/lib/active_support/core_ext/date/deprecated_conversions.rb +40 -0
  35. data/lib/active_support/core_ext/date.rb +1 -0
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  39. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  40. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  41. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +36 -0
  42. data/lib/active_support/core_ext/date_time.rb +1 -0
  43. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  44. data/lib/active_support/core_ext/enumerable.rb +112 -38
  45. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  46. data/lib/active_support/core_ext/hash/conversions.rb +0 -1
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  49. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  50. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  51. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  52. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  53. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  54. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  55. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  56. data/lib/active_support/core_ext/name_error.rb +2 -8
  57. data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
  58. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  59. data/lib/active_support/core_ext/numeric.rb +1 -0
  60. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  61. data/lib/active_support/core_ext/object/blank.rb +2 -2
  62. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  63. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  64. data/lib/active_support/core_ext/object/json.rb +30 -25
  65. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  66. data/lib/active_support/core_ext/object/try.rb +20 -20
  67. data/lib/active_support/core_ext/object/with_options.rb +21 -2
  68. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  69. data/lib/active_support/core_ext/pathname.rb +3 -0
  70. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  71. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  72. data/lib/active_support/core_ext/range/deprecated_conversions.rb +36 -0
  73. data/lib/active_support/core_ext/range/each.rb +1 -1
  74. data/lib/active_support/core_ext/range/include_time_with_zone.rb +3 -26
  75. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  76. data/lib/active_support/core_ext/range.rb +1 -1
  77. data/lib/active_support/core_ext/securerandom.rb +1 -1
  78. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  79. data/lib/active_support/core_ext/string/filters.rb +1 -1
  80. data/lib/active_support/core_ext/string/inflections.rb +1 -5
  81. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  82. data/lib/active_support/core_ext/string/output_safety.rb +94 -38
  83. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  84. data/lib/active_support/core_ext/time/calculations.rb +13 -8
  85. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  86. data/lib/active_support/core_ext/time/deprecated_conversions.rb +73 -0
  87. data/lib/active_support/core_ext/time/zones.rb +10 -26
  88. data/lib/active_support/core_ext/time.rb +1 -0
  89. data/lib/active_support/core_ext/uri.rb +3 -27
  90. data/lib/active_support/core_ext.rb +1 -0
  91. data/lib/active_support/current_attributes.rb +31 -14
  92. data/lib/active_support/dependencies/interlock.rb +10 -18
  93. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  94. data/lib/active_support/dependencies.rb +58 -788
  95. data/lib/active_support/deprecation/behaviors.rb +8 -5
  96. data/lib/active_support/deprecation/disallowed.rb +3 -3
  97. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  98. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  99. data/lib/active_support/deprecation.rb +2 -2
  100. data/lib/active_support/descendants_tracker.rb +174 -68
  101. data/lib/active_support/digest.rb +5 -3
  102. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  103. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  104. data/lib/active_support/duration.rb +81 -51
  105. data/lib/active_support/encrypted_configuration.rb +45 -3
  106. data/lib/active_support/encrypted_file.rb +21 -10
  107. data/lib/active_support/environment_inquirer.rb +1 -1
  108. data/lib/active_support/error_reporter.rb +117 -0
  109. data/lib/active_support/evented_file_update_checker.rb +20 -7
  110. data/lib/active_support/execution_context/test_helper.rb +13 -0
  111. data/lib/active_support/execution_context.rb +53 -0
  112. data/lib/active_support/execution_wrapper.rb +43 -21
  113. data/lib/active_support/executor/test_helper.rb +7 -0
  114. data/lib/active_support/fork_tracker.rb +19 -12
  115. data/lib/active_support/gem_version.rb +5 -5
  116. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  117. data/lib/active_support/html_safe_translation.rb +43 -0
  118. data/lib/active_support/i18n.rb +1 -0
  119. data/lib/active_support/i18n_railtie.rb +1 -1
  120. data/lib/active_support/inflector/inflections.rb +23 -7
  121. data/lib/active_support/inflector/methods.rb +29 -55
  122. data/lib/active_support/inflector/transliterate.rb +1 -1
  123. data/lib/active_support/isolated_execution_state.rb +72 -0
  124. data/lib/active_support/json/encoding.rb +3 -3
  125. data/lib/active_support/key_generator.rb +22 -5
  126. data/lib/active_support/lazy_load_hooks.rb +28 -4
  127. data/lib/active_support/locale/en.yml +1 -1
  128. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  129. data/lib/active_support/log_subscriber.rb +15 -5
  130. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  131. data/lib/active_support/message_encryptor.rb +12 -6
  132. data/lib/active_support/message_verifier.rb +46 -14
  133. data/lib/active_support/messages/metadata.rb +2 -2
  134. data/lib/active_support/multibyte/chars.rb +10 -11
  135. data/lib/active_support/multibyte/unicode.rb +0 -12
  136. data/lib/active_support/multibyte.rb +1 -1
  137. data/lib/active_support/notifications/fanout.rb +91 -65
  138. data/lib/active_support/notifications/instrumenter.rb +32 -15
  139. data/lib/active_support/notifications.rb +23 -23
  140. data/lib/active_support/number_helper/number_converter.rb +1 -3
  141. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  142. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  143. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  144. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  145. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  146. data/lib/active_support/number_helper.rb +4 -5
  147. data/lib/active_support/option_merger.rb +10 -18
  148. data/lib/active_support/ordered_hash.rb +1 -1
  149. data/lib/active_support/ordered_options.rb +1 -1
  150. data/lib/active_support/parameter_filter.rb +20 -11
  151. data/lib/active_support/per_thread_registry.rb +5 -0
  152. data/lib/active_support/railtie.rb +69 -19
  153. data/lib/active_support/reloader.rb +1 -1
  154. data/lib/active_support/rescuable.rb +12 -12
  155. data/lib/active_support/ruby_features.rb +7 -0
  156. data/lib/active_support/secure_compare_rotator.rb +2 -2
  157. data/lib/active_support/string_inquirer.rb +0 -2
  158. data/lib/active_support/subscriber.rb +7 -18
  159. data/lib/active_support/tagged_logging.rb +2 -2
  160. data/lib/active_support/test_case.rb +13 -21
  161. data/lib/active_support/testing/assertions.rb +36 -6
  162. data/lib/active_support/testing/deprecation.rb +52 -1
  163. data/lib/active_support/testing/isolation.rb +30 -29
  164. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  165. data/lib/active_support/testing/parallelization/server.rb +4 -0
  166. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  167. data/lib/active_support/testing/parallelization.rb +4 -0
  168. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  169. data/lib/active_support/testing/stream.rb +3 -5
  170. data/lib/active_support/testing/tagged_logging.rb +1 -1
  171. data/lib/active_support/testing/time_helpers.rb +13 -2
  172. data/lib/active_support/time_with_zone.rb +43 -22
  173. data/lib/active_support/values/time_zone.rb +35 -14
  174. data/lib/active_support/version.rb +1 -1
  175. data/lib/active_support/xml_mini/jdom.rb +1 -1
  176. data/lib/active_support/xml_mini/libxml.rb +5 -5
  177. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  178. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  179. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  180. data/lib/active_support/xml_mini/rexml.rb +1 -1
  181. data/lib/active_support/xml_mini.rb +5 -4
  182. data/lib/active_support.rb +17 -1
  183. metadata +26 -23
  184. data/lib/active_support/core_ext/marshal.rb +0 -26
  185. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -7,6 +7,16 @@ require "active_support/core_ext/object/try"
7
7
 
8
8
  module ActiveSupport
9
9
  module Notifications
10
+ class InstrumentationSubscriberError < RuntimeError
11
+ attr_reader :exceptions
12
+
13
+ def initialize(exceptions)
14
+ @exceptions = exceptions
15
+ exception_class_names = exceptions.map { |e| e.class.name }
16
+ super "Exception(s) occurred within instrumentation subscribers: #{exception_class_names.join(', ')}"
17
+ end
18
+ end
19
+
10
20
  # This is a default queue implementation that ships with Notifications.
11
21
  # It just pushes events to all registered log subscribers.
12
22
  #
@@ -24,12 +34,15 @@ module ActiveSupport
24
34
  def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
25
35
  subscriber = Subscribers.new(pattern, callable || block, monotonic)
26
36
  synchronize do
27
- if String === pattern
37
+ case pattern
38
+ when String
28
39
  @string_subscribers[pattern] << subscriber
29
40
  @listeners_for.delete(pattern)
30
- else
41
+ when NilClass, Regexp
31
42
  @other_subscribers << subscriber
32
43
  @listeners_for.clear
44
+ else
45
+ raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
33
46
  end
34
47
  end
35
48
  subscriber
@@ -56,15 +69,40 @@ module ActiveSupport
56
69
  end
57
70
 
58
71
  def start(name, id, payload)
59
- listeners_for(name).each { |s| s.start(name, id, payload) }
72
+ iterate_guarding_exceptions(listeners_for(name)) { |s| s.start(name, id, payload) }
60
73
  end
61
74
 
62
75
  def finish(name, id, payload, listeners = listeners_for(name))
63
- listeners.each { |s| s.finish(name, id, payload) }
76
+ iterate_guarding_exceptions(listeners) { |s| s.finish(name, id, payload) }
64
77
  end
65
78
 
66
79
  def publish(name, *args)
67
- listeners_for(name).each { |s| s.publish(name, *args) }
80
+ iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
81
+ end
82
+
83
+ def publish_event(event)
84
+ iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
85
+ end
86
+
87
+ def iterate_guarding_exceptions(listeners)
88
+ exceptions = nil
89
+
90
+ listeners.each do |s|
91
+ yield s
92
+ rescue Exception => e
93
+ exceptions ||= []
94
+ exceptions << e
95
+ end
96
+
97
+ if exceptions
98
+ if exceptions.size == 1
99
+ raise exceptions.first
100
+ else
101
+ raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
102
+ end
103
+ end
104
+
105
+ listeners
68
106
  end
69
107
 
70
108
  def listeners_for(name)
@@ -91,33 +129,30 @@ module ActiveSupport
91
129
  if listener.respond_to?(:start) && listener.respond_to?(:finish)
92
130
  subscriber_class = Evented
93
131
  else
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
132
+ # Doing this to detect a single argument block or callable
133
+ # like `proc { |x| }` vs `proc { |*x| }`, `proc { |**x| }`,
134
+ # or `proc { |x, **y| }`
135
+ procish = listener.respond_to?(:parameters) ? listener : listener.method(:call)
136
+
137
+ if procish.arity == 1 && procish.parameters.length == 1
138
+ subscriber_class = EventObject
101
139
  end
102
140
  end
103
141
 
104
- wrap_all pattern, subscriber_class.new(pattern, listener)
105
- end
106
-
107
- def self.wrap_all(pattern, subscriber)
108
- unless pattern
109
- AllMessages.new(subscriber)
110
- else
111
- subscriber
112
- end
142
+ subscriber_class.new(pattern, listener)
113
143
  end
114
144
 
115
- class Matcher #:nodoc:
145
+ class Matcher # :nodoc:
116
146
  attr_reader :pattern, :exclusions
117
147
 
118
148
  def self.wrap(pattern)
119
- return pattern if String === pattern
120
- new(pattern)
149
+ if String === pattern
150
+ pattern
151
+ elsif pattern.nil?
152
+ AllMessages.new
153
+ else
154
+ new(pattern)
155
+ end
121
156
  end
122
157
 
123
158
  def initialize(pattern)
@@ -132,15 +167,26 @@ module ActiveSupport
132
167
  def ===(name)
133
168
  pattern === name && !exclusions.include?(name)
134
169
  end
170
+
171
+ class AllMessages
172
+ def ===(name)
173
+ true
174
+ end
175
+
176
+ def unsubscribe!(*)
177
+ false
178
+ end
179
+ end
135
180
  end
136
181
 
137
- class Evented #:nodoc:
182
+ class Evented # :nodoc:
138
183
  attr_reader :pattern
139
184
 
140
185
  def initialize(pattern, delegate)
141
186
  @pattern = Matcher.wrap(pattern)
142
187
  @delegate = delegate
143
188
  @can_publish = delegate.respond_to?(:publish)
189
+ @can_publish_event = delegate.respond_to?(:publish_event)
144
190
  end
145
191
 
146
192
  def publish(name, *args)
@@ -149,6 +195,14 @@ module ActiveSupport
149
195
  end
150
196
  end
151
197
 
198
+ def publish_event(event)
199
+ if @can_publish_event
200
+ @delegate.publish_event event
201
+ else
202
+ publish(event.name, event.time, event.end, event.transaction_id, event.payload)
203
+ end
204
+ end
205
+
152
206
  def start(name, id, payload)
153
207
  @delegate.start name, id, payload
154
208
  end
@@ -161,10 +215,6 @@ module ActiveSupport
161
215
  pattern === name
162
216
  end
163
217
 
164
- def matches?(name)
165
- pattern && pattern === name
166
- end
167
-
168
218
  def unsubscribe!(name)
169
219
  pattern.unsubscribe!(name)
170
220
  end
@@ -176,12 +226,12 @@ module ActiveSupport
176
226
  end
177
227
 
178
228
  def start(name, id, payload)
179
- timestack = Thread.current[:_timestack] ||= []
229
+ timestack = IsolatedExecutionState[:_timestack] ||= []
180
230
  timestack.push Time.now
181
231
  end
182
232
 
183
233
  def finish(name, id, payload)
184
- timestack = Thread.current[:_timestack]
234
+ timestack = IsolatedExecutionState[:_timestack]
185
235
  started = timestack.pop
186
236
  @delegate.call(name, started, Time.now, id, payload)
187
237
  end
@@ -193,66 +243,42 @@ module ActiveSupport
193
243
  end
194
244
 
195
245
  def start(name, id, payload)
196
- timestack = Thread.current[:_timestack_monotonic] ||= []
197
- timestack.push Concurrent.monotonic_time
246
+ timestack = IsolatedExecutionState[:_timestack_monotonic] ||= []
247
+ timestack.push Process.clock_gettime(Process::CLOCK_MONOTONIC)
198
248
  end
199
249
 
200
250
  def finish(name, id, payload)
201
- timestack = Thread.current[:_timestack_monotonic]
251
+ timestack = IsolatedExecutionState[:_timestack_monotonic]
202
252
  started = timestack.pop
203
- @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
253
+ @delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
204
254
  end
205
255
  end
206
256
 
207
257
  class EventObject < Evented
208
258
  def start(name, id, payload)
209
- stack = Thread.current[:_event_stack] ||= []
259
+ stack = IsolatedExecutionState[:_event_stack] ||= []
210
260
  event = build_event name, id, payload
211
261
  event.start!
212
262
  stack.push event
213
263
  end
214
264
 
215
265
  def finish(name, id, payload)
216
- stack = Thread.current[:_event_stack]
266
+ stack = IsolatedExecutionState[:_event_stack]
217
267
  event = stack.pop
218
268
  event.payload = payload
219
269
  event.finish!
220
270
  @delegate.call event
221
271
  end
222
272
 
273
+ def publish_event(event)
274
+ @delegate.call event
275
+ end
276
+
223
277
  private
224
278
  def build_event(name, id, payload)
225
279
  ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
226
280
  end
227
281
  end
228
-
229
- class AllMessages # :nodoc:
230
- def initialize(delegate)
231
- @delegate = delegate
232
- end
233
-
234
- def start(name, id, payload)
235
- @delegate.start name, id, payload
236
- end
237
-
238
- def finish(name, id, payload)
239
- @delegate.finish name, id, payload
240
- end
241
-
242
- def publish(name, *args)
243
- @delegate.publish name, *args
244
- end
245
-
246
- def subscribed_to?(name)
247
- true
248
- end
249
-
250
- def unsubscribe!(*)
251
- false
252
- end
253
-
254
- alias :matches? :===
255
- end
256
282
  end
257
283
  end
258
284
  end
@@ -31,6 +31,10 @@ module ActiveSupport
31
31
  end
32
32
  end
33
33
 
34
+ def new_event(name, payload = {}) # :nodoc:
35
+ Event.new(name, nil, nil, @id, payload)
36
+ end
37
+
34
38
  # Send a start notification with +name+ and +payload+.
35
39
  def start(name, payload)
36
40
  @notifier.start name, @id, payload
@@ -58,16 +62,29 @@ module ActiveSupport
58
62
  def initialize(name, start, ending, transaction_id, payload)
59
63
  @name = name
60
64
  @payload = payload.dup
61
- @time = start
65
+ @time = start ? start.to_f * 1_000.0 : start
62
66
  @transaction_id = transaction_id
63
- @end = ending
67
+ @end = ending ? ending.to_f * 1_000.0 : ending
64
68
  @children = []
65
- @cpu_time_start = 0
66
- @cpu_time_finish = 0
69
+ @cpu_time_start = 0.0
70
+ @cpu_time_finish = 0.0
67
71
  @allocation_count_start = 0
68
72
  @allocation_count_finish = 0
69
73
  end
70
74
 
75
+ def record
76
+ start!
77
+ begin
78
+ yield payload if block_given?
79
+ rescue Exception => e
80
+ payload[:exception] = [e.class.name, e.message]
81
+ payload[:exception_object] = e
82
+ raise e
83
+ ensure
84
+ finish!
85
+ end
86
+ end
87
+
71
88
  # Record information at the time this event starts
72
89
  def start!
73
90
  @time = now
@@ -85,7 +102,7 @@ module ActiveSupport
85
102
  # Returns the CPU time (in milliseconds) passed since the call to
86
103
  # +start!+ and the call to +finish!+
87
104
  def cpu_time
88
- (@cpu_time_finish - @cpu_time_start) * 1000
105
+ @cpu_time_finish - @cpu_time_start
89
106
  end
90
107
 
91
108
  # Returns the idle time time (in milliseconds) passed since the call to
@@ -113,7 +130,7 @@ module ActiveSupport
113
130
  #
114
131
  # @event.duration # => 1000.138
115
132
  def duration
116
- 1000.0 * (self.end - time)
133
+ self.end - time
117
134
  end
118
135
 
119
136
  def <<(event)
@@ -126,28 +143,28 @@ module ActiveSupport
126
143
 
127
144
  private
128
145
  def now
129
- Concurrent.monotonic_time
146
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
130
147
  end
131
148
 
132
149
  begin
133
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
150
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
134
151
 
135
152
  def now_cpu
136
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
153
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
137
154
  end
138
155
  rescue
139
- def now_cpu
140
- 0
156
+ def now_cpu # rubocop:disable Lint/DuplicateMethods
157
+ 0.0
141
158
  end
142
159
  end
143
160
 
144
- if defined?(JRUBY_VERSION)
161
+ if GC.stat.key?(:total_allocated_objects)
145
162
  def now_allocations
146
- 0
163
+ GC.stat(:total_allocated_objects)
147
164
  end
148
- else
165
+ else # Likely on JRuby, TruffleRuby
149
166
  def now_allocations
150
- GC.stat :total_allocated_objects
167
+ 0
151
168
  end
152
169
  end
153
170
  end
@@ -2,10 +2,9 @@
2
2
 
3
3
  require "active_support/notifications/instrumenter"
4
4
  require "active_support/notifications/fanout"
5
- require "active_support/per_thread_registry"
6
5
 
7
6
  module ActiveSupport
8
- # = Notifications
7
+ # = \Notifications
9
8
  #
10
9
  # <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
11
10
  # Ruby.
@@ -85,7 +84,7 @@ module ActiveSupport
85
84
  # event.payload[:exception] # => ["ArgumentError", "Invalid value"]
86
85
  # event.payload[:exception_object] # => #<ArgumentError: Invalid value>
87
86
  #
88
- # As the earlier example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
87
+ # As the earlier example depicts, the class ActiveSupport::Notifications::Event
89
88
  # is able to take the arguments as they come and provide an object-oriented
90
89
  # interface to that data.
91
90
  #
@@ -198,6 +197,10 @@ module ActiveSupport
198
197
  notifier.publish(name, *args)
199
198
  end
200
199
 
200
+ def publish_event(event) # :nodoc:
201
+ notifier.publish_event(event)
202
+ end
203
+
201
204
  def instrument(name, payload = {})
202
205
  if notifier.listening?(name)
203
206
  instrumenter.instrument(name, payload) { yield payload if block_given? }
@@ -231,10 +234,22 @@ module ActiveSupport
231
234
  # ActiveSupport::Notifications.subscribe(/render/) do |event|
232
235
  # @event = event
233
236
  # end
237
+ #
238
+ # Raises an error if invalid event name type is passed:
239
+ #
240
+ # ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
241
+ # #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
242
+ #
234
243
  def subscribe(pattern = nil, callback = nil, &block)
235
244
  notifier.subscribe(pattern, callback, monotonic: false, &block)
236
245
  end
237
246
 
247
+ # Performs the same functionality as #subscribe, but the +start+ and
248
+ # +finish+ block arguments are in monotonic time instead of wall-clock
249
+ # time. Monotonic time will not jump forward or backward (due to NTP or
250
+ # Daylights Savings). Use +monotonic_subscribe+ when accuracy of time
251
+ # duration is important. For example, computing elapsed time between
252
+ # two events.
238
253
  def monotonic_subscribe(pattern = nil, callback = nil, &block)
239
254
  notifier.subscribe(pattern, callback, monotonic: true, &block)
240
255
  end
@@ -251,28 +266,13 @@ module ActiveSupport
251
266
  end
252
267
 
253
268
  def instrumenter
254
- InstrumentationRegistry.instance.instrumenter_for(notifier)
269
+ registry[notifier] ||= Instrumenter.new(notifier)
255
270
  end
256
- end
257
271
 
258
- # This class is a registry which holds all of the +Instrumenter+ objects
259
- # in a particular thread local. To access the +Instrumenter+ object for a
260
- # particular +notifier+, you can call the following method:
261
- #
262
- # InstrumentationRegistry.instrumenter_for(notifier)
263
- #
264
- # The instrumenters for multiple notifiers are held in a single instance of
265
- # this class.
266
- class InstrumentationRegistry # :nodoc:
267
- extend ActiveSupport::PerThreadRegistry
268
-
269
- def initialize
270
- @registry = {}
271
- end
272
-
273
- def instrumenter_for(notifier)
274
- @registry[notifier] ||= Instrumenter.new(notifier)
275
- end
272
+ private
273
+ def registry
274
+ ActiveSupport::IsolatedExecutionState[:active_support_notifications_registry] ||= {}
275
+ end
276
276
  end
277
277
 
278
278
  self.notifier = Fanout.new
@@ -174,9 +174,7 @@ module ActiveSupport
174
174
  end
175
175
 
176
176
  def valid_float?
177
- Float(number)
178
- rescue ArgumentError, TypeError
179
- false
177
+ Float(number, exception: false)
180
178
  end
181
179
  end
182
180
  end
@@ -8,16 +8,21 @@ module ActiveSupport
8
8
  self.namespace = :currency
9
9
 
10
10
  def convert
11
- number = self.number.to_s.strip
12
11
  format = options[:format]
13
12
 
14
- if number.sub!(/^-/, "") &&
15
- (options[:precision] != 0 || number.to_f > 0.5)
16
- format = options[:negative_format]
13
+ number_f = valid_float?
14
+ if number_f
15
+ if number_f.negative?
16
+ number_f = number_f.abs
17
+ format = options[:negative_format] if (number_f * 10**options[:precision]) >= 0.5
18
+ end
19
+ number_s = NumberToRoundedConverter.convert(number_f, options)
20
+ else
21
+ number_s = number.to_s.strip
22
+ format = options[:negative_format] if number_s.sub!(/^-/, "")
17
23
  end
18
24
 
19
- rounded_number = NumberToRoundedConverter.convert(number, options)
20
- format.gsub("%n", rounded_number).gsub("%u", options[:unit])
25
+ format.gsub("%n", number_s).gsub("%u", options[:unit])
21
26
  end
22
27
 
23
28
  private
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
7
- class NumberToDelimitedConverter < NumberConverter #:nodoc:
7
+ class NumberToDelimitedConverter < NumberConverter # :nodoc:
8
8
  self.validate_float = true
9
9
 
10
10
  DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
7
- class NumberToHumanSizeConverter < NumberConverter #:nodoc:
7
+ class NumberToHumanSizeConverter < NumberConverter # :nodoc:
8
8
  STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
9
9
 
10
10
  self.namespace = :human
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
7
- class NumberToPhoneConverter < NumberConverter #:nodoc:
7
+ class NumberToPhoneConverter < NumberConverter # :nodoc:
8
8
  def convert
9
9
  str = country_code(opts[:country_code]).dup
10
10
  str << convert_to_phone_number(number.to_s.strip)
@@ -35,16 +35,12 @@ module ActiveSupport
35
35
  end
36
36
 
37
37
  def absolute_precision(number)
38
- if significant && options[:precision] > 0
38
+ if options[:significant] && options[:precision] > 0
39
39
  options[:precision] - digit_count(convert_to_decimal(number))
40
40
  else
41
41
  options[:precision]
42
42
  end
43
43
  end
44
-
45
- def significant
46
- options[:significant]
47
- end
48
44
  end
49
45
  end
50
46
  end
@@ -99,8 +99,6 @@ module ActiveSupport
99
99
  # number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
100
100
  # number_to_currency('123a456') # => "$123a456"
101
101
  #
102
- # number_to_currency("123a456", raise: true) # => InvalidNumberError
103
- #
104
102
  # number_to_currency(-0.456789, precision: 0)
105
103
  # # => "$0"
106
104
  # number_to_currency(-1234567890.50, negative_format: '(%u%n)')
@@ -360,13 +358,14 @@ module ActiveSupport
360
358
  # out by default (set <tt>:strip_insignificant_zeros</tt> to
361
359
  # +false+ to change that):
362
360
  #
363
- # number_to_human(12.00001) # => "12"
364
- # number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
361
+ # number_to_human(12.00001) # => "12"
362
+ # number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
365
363
  #
366
364
  # ==== Custom Unit Quantifiers
367
365
  #
368
366
  # You can also use your own custom unit quantifiers:
369
- # number_to_human(500000, units: { unit: 'ml', thousand: 'lt' }) # => "500 lt"
367
+ #
368
+ # number_to_human(500000, units: { unit: 'ml', thousand: 'lt' }) # => "500 lt"
370
369
  #
371
370
  # If in your I18n locale you have:
372
371
  #
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/hash/deep_merge"
4
- require "active_support/core_ext/symbol/starts_ends_with"
5
4
 
6
5
  module ActiveSupport
7
- class OptionMerger #:nodoc:
6
+ class OptionMerger # :nodoc:
8
7
  instance_methods.each do |method|
9
8
  undef_method(method) unless method.start_with?("__", "instance_eval", "class", "object_id")
10
9
  end
@@ -16,8 +15,8 @@ module ActiveSupport
16
15
  private
17
16
  def method_missing(method, *arguments, &block)
18
17
  options = nil
19
- if arguments.first.is_a?(Proc)
20
- proc = arguments.pop
18
+ if arguments.size == 1 && arguments.first.is_a?(Proc)
19
+ proc = arguments.shift
21
20
  arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
22
21
  elsif arguments.last.respond_to?(:to_hash)
23
22
  options = @options.deep_merge(arguments.pop)
@@ -25,22 +24,15 @@ module ActiveSupport
25
24
  options = @options
26
25
  end
27
26
 
28
- invoke_method(method, arguments, options, &block)
29
- end
30
-
31
- if RUBY_VERSION >= "2.7"
32
- def invoke_method(method, arguments, options, &block)
33
- if options
34
- @context.__send__(method, *arguments, **options, &block)
35
- else
36
- @context.__send__(method, *arguments, &block)
37
- end
38
- end
39
- else
40
- def invoke_method(method, arguments, options, &block)
41
- arguments << options.dup if options
27
+ if options
28
+ @context.__send__(method, *arguments, **options, &block)
29
+ else
42
30
  @context.__send__(method, *arguments, &block)
43
31
  end
44
32
  end
33
+
34
+ def respond_to_missing?(*arguments)
35
+ @context.respond_to?(*arguments)
36
+ end
45
37
  end
46
38
  end
@@ -21,7 +21,7 @@ module ActiveSupport
21
21
  #
22
22
  # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
23
23
  # with other implementations.
24
- class OrderedHash < ::Hash
24
+ class OrderedHash < ::Hash # :nodoc:
25
25
  def to_yaml_type
26
26
  "!tag:yaml.org,2002:omap"
27
27
  end
@@ -68,7 +68,7 @@ module ActiveSupport
68
68
  end
69
69
  end
70
70
 
71
- # +InheritableOptions+ provides a constructor to build an +OrderedOptions+
71
+ # +InheritableOptions+ provides a constructor to build an OrderedOptions
72
72
  # hash inherited from another hash.
73
73
  #
74
74
  # Use this if you already have some hash and you want to create a new one based on it.