activesupport 6.1.0 → 7.1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1075 -325
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +32 -7
  8. data/lib/active_support/benchmarkable.rb +3 -2
  9. data/lib/active_support/broadcast_logger.rb +251 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +53 -20
  14. data/lib/active_support/cache/mem_cache_store.rb +201 -62
  15. data/lib/active_support/cache/memory_store.rb +86 -24
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +186 -193
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +63 -71
  20. data/lib/active_support/cache.rb +487 -249
  21. data/lib/active_support/callbacks.rb +227 -105
  22. data/lib/active_support/code_generator.rb +70 -0
  23. data/lib/active_support/concern.rb +9 -7
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/concurrency/share_lock.rb +2 -2
  27. data/lib/active_support/configurable.rb +18 -5
  28. data/lib/active_support/configuration_file.rb +7 -2
  29. data/lib/active_support/core_ext/array/access.rb +1 -5
  30. data/lib/active_support/core_ext/array/conversions.rb +15 -13
  31. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  33. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  34. data/lib/active_support/core_ext/class/subclasses.rb +37 -26
  35. data/lib/active_support/core_ext/date/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  37. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  38. data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
  39. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  40. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  41. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  42. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  43. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  44. data/lib/active_support/core_ext/enumerable.rb +85 -83
  45. data/lib/active_support/core_ext/erb/util.rb +196 -0
  46. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  47. data/lib/active_support/core_ext/hash/conversions.rb +1 -2
  48. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  49. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  50. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  51. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  52. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  53. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  54. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  55. data/lib/active_support/core_ext/module/attribute_accessors.rb +8 -0
  56. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
  57. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  58. data/lib/active_support/core_ext/module/delegation.rb +81 -43
  59. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  60. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  61. data/lib/active_support/core_ext/name_error.rb +2 -8
  62. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  63. data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
  64. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  65. data/lib/active_support/core_ext/object/blank.rb +2 -2
  66. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  67. data/lib/active_support/core_ext/object/duplicable.rb +31 -11
  68. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  69. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  70. data/lib/active_support/core_ext/object/json.rb +49 -27
  71. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  72. data/lib/active_support/core_ext/object/try.rb +20 -20
  73. data/lib/active_support/core_ext/object/with.rb +44 -0
  74. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  75. data/lib/active_support/core_ext/object.rb +1 -0
  76. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  77. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  78. data/lib/active_support/core_ext/pathname.rb +4 -0
  79. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  80. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  81. data/lib/active_support/core_ext/range/each.rb +1 -1
  82. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  83. data/lib/active_support/core_ext/range.rb +1 -2
  84. data/lib/active_support/core_ext/securerandom.rb +25 -13
  85. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  86. data/lib/active_support/core_ext/string/filters.rb +21 -15
  87. data/lib/active_support/core_ext/string/indent.rb +1 -1
  88. data/lib/active_support/core_ext/string/inflections.rb +17 -10
  89. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  90. data/lib/active_support/core_ext/string/output_safety.rb +85 -165
  91. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  92. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  93. data/lib/active_support/core_ext/time/calculations.rb +30 -8
  94. data/lib/active_support/core_ext/time/conversions.rb +15 -13
  95. data/lib/active_support/core_ext/time/zones.rb +12 -28
  96. data/lib/active_support/core_ext.rb +2 -1
  97. data/lib/active_support/current_attributes.rb +47 -20
  98. data/lib/active_support/deep_mergeable.rb +53 -0
  99. data/lib/active_support/dependencies/autoload.rb +17 -12
  100. data/lib/active_support/dependencies/interlock.rb +10 -18
  101. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  102. data/lib/active_support/dependencies.rb +58 -788
  103. data/lib/active_support/deprecation/behaviors.rb +66 -40
  104. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  105. data/lib/active_support/deprecation/deprecators.rb +104 -0
  106. data/lib/active_support/deprecation/disallowed.rb +6 -8
  107. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  108. data/lib/active_support/deprecation/method_wrappers.rb +9 -26
  109. data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
  110. data/lib/active_support/deprecation/reporting.rb +43 -26
  111. data/lib/active_support/deprecation.rb +32 -5
  112. data/lib/active_support/deprecator.rb +7 -0
  113. data/lib/active_support/descendants_tracker.rb +150 -72
  114. data/lib/active_support/digest.rb +5 -3
  115. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  116. data/lib/active_support/duration/iso8601_serializer.rb +9 -3
  117. data/lib/active_support/duration.rb +83 -52
  118. data/lib/active_support/encrypted_configuration.rb +72 -9
  119. data/lib/active_support/encrypted_file.rb +29 -13
  120. data/lib/active_support/environment_inquirer.rb +23 -3
  121. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  122. data/lib/active_support/error_reporter.rb +203 -0
  123. data/lib/active_support/evented_file_update_checker.rb +20 -7
  124. data/lib/active_support/execution_context/test_helper.rb +13 -0
  125. data/lib/active_support/execution_context.rb +53 -0
  126. data/lib/active_support/execution_wrapper.rb +44 -22
  127. data/lib/active_support/executor/test_helper.rb +7 -0
  128. data/lib/active_support/file_update_checker.rb +4 -2
  129. data/lib/active_support/fork_tracker.rb +28 -11
  130. data/lib/active_support/gem_version.rb +4 -4
  131. data/lib/active_support/gzip.rb +2 -0
  132. data/lib/active_support/hash_with_indifferent_access.rb +44 -19
  133. data/lib/active_support/html_safe_translation.rb +53 -0
  134. data/lib/active_support/i18n.rb +2 -1
  135. data/lib/active_support/i18n_railtie.rb +21 -14
  136. data/lib/active_support/inflector/inflections.rb +25 -7
  137. data/lib/active_support/inflector/methods.rb +50 -64
  138. data/lib/active_support/inflector/transliterate.rb +4 -2
  139. data/lib/active_support/isolated_execution_state.rb +76 -0
  140. data/lib/active_support/json/decoding.rb +2 -1
  141. data/lib/active_support/json/encoding.rb +27 -45
  142. data/lib/active_support/key_generator.rb +31 -6
  143. data/lib/active_support/lazy_load_hooks.rb +33 -7
  144. data/lib/active_support/locale/en.yml +4 -2
  145. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  146. data/lib/active_support/log_subscriber.rb +97 -35
  147. data/lib/active_support/logger.rb +9 -60
  148. data/lib/active_support/logger_thread_safe_level.rb +11 -34
  149. data/lib/active_support/message_encryptor.rb +206 -56
  150. data/lib/active_support/message_encryptors.rb +141 -0
  151. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  152. data/lib/active_support/message_pack/extensions.rb +292 -0
  153. data/lib/active_support/message_pack/serializer.rb +63 -0
  154. data/lib/active_support/message_pack.rb +50 -0
  155. data/lib/active_support/message_verifier.rb +235 -84
  156. data/lib/active_support/message_verifiers.rb +135 -0
  157. data/lib/active_support/messages/codec.rb +65 -0
  158. data/lib/active_support/messages/metadata.rb +112 -46
  159. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  160. data/lib/active_support/messages/rotator.rb +34 -32
  161. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  162. data/lib/active_support/multibyte/chars.rb +12 -11
  163. data/lib/active_support/multibyte/unicode.rb +9 -49
  164. data/lib/active_support/multibyte.rb +1 -1
  165. data/lib/active_support/notifications/fanout.rb +304 -114
  166. data/lib/active_support/notifications/instrumenter.rb +117 -35
  167. data/lib/active_support/notifications.rb +25 -25
  168. data/lib/active_support/number_helper/number_converter.rb +14 -7
  169. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  170. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  171. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -4
  172. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  173. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  174. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  175. data/lib/active_support/number_helper.rb +379 -319
  176. data/lib/active_support/option_merger.rb +10 -18
  177. data/lib/active_support/ordered_hash.rb +4 -4
  178. data/lib/active_support/ordered_options.rb +15 -1
  179. data/lib/active_support/parameter_filter.rb +105 -81
  180. data/lib/active_support/proxy_object.rb +2 -0
  181. data/lib/active_support/railtie.rb +83 -21
  182. data/lib/active_support/reloader.rb +13 -5
  183. data/lib/active_support/rescuable.rb +18 -16
  184. data/lib/active_support/ruby_features.rb +7 -0
  185. data/lib/active_support/secure_compare_rotator.rb +18 -11
  186. data/lib/active_support/security_utils.rb +1 -1
  187. data/lib/active_support/string_inquirer.rb +3 -3
  188. data/lib/active_support/subscriber.rb +11 -40
  189. data/lib/active_support/syntax_error_proxy.rb +60 -0
  190. data/lib/active_support/tagged_logging.rb +65 -25
  191. data/lib/active_support/test_case.rb +166 -27
  192. data/lib/active_support/testing/assertions.rb +61 -15
  193. data/lib/active_support/testing/autorun.rb +0 -2
  194. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  195. data/lib/active_support/testing/deprecation.rb +53 -2
  196. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  197. data/lib/active_support/testing/isolation.rb +30 -29
  198. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  199. data/lib/active_support/testing/parallelization/server.rb +4 -0
  200. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  201. data/lib/active_support/testing/parallelization.rb +4 -0
  202. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  203. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  204. data/lib/active_support/testing/stream.rb +4 -6
  205. data/lib/active_support/testing/strict_warnings.rb +39 -0
  206. data/lib/active_support/testing/tagged_logging.rb +1 -1
  207. data/lib/active_support/testing/time_helpers.rb +49 -16
  208. data/lib/active_support/time_with_zone.rb +39 -28
  209. data/lib/active_support/values/time_zone.rb +50 -18
  210. data/lib/active_support/version.rb +1 -1
  211. data/lib/active_support/xml_mini/jdom.rb +4 -11
  212. data/lib/active_support/xml_mini/libxml.rb +5 -5
  213. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  214. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  215. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  216. data/lib/active_support/xml_mini/rexml.rb +2 -2
  217. data/lib/active_support/xml_mini.rb +7 -6
  218. data/lib/active_support.rb +28 -1
  219. metadata +150 -18
  220. data/lib/active_support/core_ext/marshal.rb +0 -26
  221. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
  222. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  223. data/lib/active_support/core_ext/uri.rb +0 -29
  224. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  225. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/module/delegation"
3
4
  require "securerandom"
4
5
 
5
6
  module ActiveSupport
@@ -9,17 +10,50 @@ module ActiveSupport
9
10
  attr_reader :id
10
11
 
11
12
  def initialize(notifier)
13
+ unless notifier.respond_to?(:build_handle)
14
+ notifier = LegacyHandle::Wrapper.new(notifier)
15
+ end
16
+
12
17
  @id = unique_id
13
18
  @notifier = notifier
14
19
  end
15
20
 
21
+ class LegacyHandle # :nodoc:
22
+ class Wrapper # :nodoc:
23
+ def initialize(notifier)
24
+ @notifier = notifier
25
+ end
26
+
27
+ def build_handle(name, id, payload)
28
+ LegacyHandle.new(@notifier, name, id, payload)
29
+ end
30
+
31
+ delegate :start, :finish, to: :@notifier
32
+ end
33
+
34
+ def initialize(notifier, name, id, payload)
35
+ @notifier = notifier
36
+ @name = name
37
+ @id = id
38
+ @payload = payload
39
+ end
40
+
41
+ def start
42
+ @listener_state = @notifier.start @name, @id, @payload
43
+ end
44
+
45
+ def finish
46
+ @notifier.finish(@name, @id, @payload, @listener_state)
47
+ end
48
+ end
49
+
16
50
  # Given a block, instrument it by measuring the time taken to execute
17
51
  # and publish it. Without a block, simply send a message via the
18
52
  # notifier. Notice that events get sent even if an error occurs in the
19
53
  # passed-in block.
20
54
  def instrument(name, payload = {})
21
- # some of the listeners might have state
22
- listeners_state = start name, payload
55
+ handle = build_handle(name, payload)
56
+ handle.start
23
57
  begin
24
58
  yield payload if block_given?
25
59
  rescue Exception => e
@@ -27,10 +61,28 @@ module ActiveSupport
27
61
  payload[:exception_object] = e
28
62
  raise e
29
63
  ensure
30
- finish_with_state listeners_state, name, payload
64
+ handle.finish
31
65
  end
32
66
  end
33
67
 
68
+ # Returns a "handle" for an event with the given +name+ and +payload+.
69
+ #
70
+ # #start and #finish must each be called exactly once on the returned object.
71
+ #
72
+ # Where possible, it's best to use #instrument, which will record the
73
+ # start and finish of the event and correctly handle any exceptions.
74
+ # +build_handle+ is a low-level API intended for cases where using
75
+ # +instrument+ isn't possible.
76
+ #
77
+ # See ActiveSupport::Notifications::Fanout::Handle.
78
+ def build_handle(name, payload)
79
+ @notifier.build_handle(name, @id, payload)
80
+ end
81
+
82
+ def new_event(name, payload = {}) # :nodoc:
83
+ Event.new(name, nil, nil, @id, payload)
84
+ end
85
+
34
86
  # Send a start notification with +name+ and +payload+.
35
87
  def start(name, payload)
36
88
  @notifier.start name, @id, payload
@@ -52,22 +104,42 @@ module ActiveSupport
52
104
  end
53
105
 
54
106
  class Event
55
- attr_reader :name, :time, :end, :transaction_id, :children
107
+ attr_reader :name, :transaction_id
56
108
  attr_accessor :payload
57
109
 
58
110
  def initialize(name, start, ending, transaction_id, payload)
59
111
  @name = name
60
112
  @payload = payload.dup
61
- @time = start
113
+ @time = start ? start.to_f * 1_000.0 : start
62
114
  @transaction_id = transaction_id
63
- @end = ending
64
- @children = []
65
- @cpu_time_start = 0
66
- @cpu_time_finish = 0
115
+ @end = ending ? ending.to_f * 1_000.0 : ending
116
+ @cpu_time_start = 0.0
117
+ @cpu_time_finish = 0.0
67
118
  @allocation_count_start = 0
68
119
  @allocation_count_finish = 0
69
120
  end
70
121
 
122
+ def time
123
+ @time / 1000.0 if @time
124
+ end
125
+
126
+ def end
127
+ @end / 1000.0 if @end
128
+ end
129
+
130
+ def record # :nodoc:
131
+ start!
132
+ begin
133
+ yield payload if block_given?
134
+ rescue Exception => e
135
+ payload[:exception] = [e.class.name, e.message]
136
+ payload[:exception_object] = e
137
+ raise e
138
+ ensure
139
+ finish!
140
+ end
141
+ end
142
+
71
143
  # Record information at the time this event starts
72
144
  def start!
73
145
  @time = now
@@ -82,24 +154,42 @@ module ActiveSupport
82
154
  @allocation_count_finish = now_allocations
83
155
  end
84
156
 
85
- # Returns the CPU time (in milliseconds) passed since the call to
86
- # +start!+ and the call to +finish!+
157
+ # Returns the CPU time (in milliseconds) passed between the call to
158
+ # #start! and the call to #finish!.
87
159
  def cpu_time
88
- (@cpu_time_finish - @cpu_time_start) * 1000
160
+ @cpu_time_finish - @cpu_time_start
89
161
  end
90
162
 
91
- # Returns the idle time time (in milliseconds) passed since the call to
92
- # +start!+ and the call to +finish!+
163
+ # Returns the idle time time (in milliseconds) passed between the call to
164
+ # #start! and the call to #finish!.
93
165
  def idle_time
94
- duration - cpu_time
166
+ diff = duration - cpu_time
167
+ diff > 0.0 ? diff : 0.0
95
168
  end
96
169
 
97
- # Returns the number of allocations made since the call to +start!+ and
98
- # the call to +finish!+
170
+ # Returns the number of allocations made between the call to #start! and
171
+ # the call to #finish!.
99
172
  def allocations
100
173
  @allocation_count_finish - @allocation_count_start
101
174
  end
102
175
 
176
+ def children # :nodoc:
177
+ ActiveSupport.deprecator.warn <<~EOM
178
+ ActiveSupport::Notifications::Event#children is deprecated and will
179
+ be removed in Rails 7.2.
180
+ EOM
181
+ []
182
+ end
183
+
184
+ def parent_of?(event) # :nodoc:
185
+ ActiveSupport.deprecator.warn <<~EOM
186
+ ActiveSupport::Notifications::Event#parent_of? is deprecated and will
187
+ be removed in Rails 7.2.
188
+ EOM
189
+ start = (time - event.time) * 1000
190
+ start <= 0 && (start + duration >= event.duration)
191
+ end
192
+
103
193
  # Returns the difference in milliseconds between when the execution of the
104
194
  # event started and when it ended.
105
195
  #
@@ -113,41 +203,33 @@ module ActiveSupport
113
203
  #
114
204
  # @event.duration # => 1000.138
115
205
  def duration
116
- 1000.0 * (self.end - time)
117
- end
118
-
119
- def <<(event)
120
- @children << event
121
- end
122
-
123
- def parent_of?(event)
124
- @children.include? event
206
+ @end - @time
125
207
  end
126
208
 
127
209
  private
128
210
  def now
129
- Concurrent.monotonic_time
211
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
130
212
  end
131
213
 
132
214
  begin
133
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
215
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
134
216
 
135
217
  def now_cpu
136
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
218
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
137
219
  end
138
220
  rescue
139
- def now_cpu
140
- 0
221
+ def now_cpu # rubocop:disable Lint/DuplicateMethods
222
+ 0.0
141
223
  end
142
224
  end
143
225
 
144
- if defined?(JRUBY_VERSION)
226
+ if GC.stat.key?(:total_allocated_objects)
145
227
  def now_allocations
146
- 0
228
+ GC.stat(:total_allocated_objects)
147
229
  end
148
- else
230
+ else # Likely on JRuby, TruffleRuby
149
231
  def now_allocations
150
- GC.stat :total_allocated_objects
232
+ 0
151
233
  end
152
234
  end
153
235
  end
@@ -2,12 +2,11 @@
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
- # <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
9
+ # +ActiveSupport::Notifications+ provides an instrumentation API for
11
10
  # Ruby.
12
11
  #
13
12
  # == Instrumenters
@@ -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
  #
@@ -178,7 +177,7 @@ module ActiveSupport
178
177
  #
179
178
  # Subscribers using a regexp or other pattern-matching object will remain subscribed
180
179
  # to all events that match their original pattern, unless those events match a string
181
- # passed to `unsubscribe`:
180
+ # passed to +unsubscribe+:
182
181
  #
183
182
  # subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
184
183
  # ActiveSupport::Notifications.unsubscribe('render_template.action_view')
@@ -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
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "bigdecimal"
4
+ require "bigdecimal/util"
3
5
  require "active_support/core_ext/big_decimal/conversions"
4
- require "active_support/core_ext/object/blank"
5
6
  require "active_support/core_ext/hash/keys"
6
7
  require "active_support/i18n"
7
8
  require "active_support/core_ext/class/attribute"
@@ -122,13 +123,14 @@ module ActiveSupport
122
123
 
123
124
  def initialize(number, options)
124
125
  @number = number
125
- @opts = options.symbolize_keys
126
+ @opts = options.symbolize_keys
127
+ @options = nil
126
128
  end
127
129
 
128
130
  def execute
129
131
  if !number
130
132
  nil
131
- elsif validate_float? && !valid_float?
133
+ elsif validate_float? && !valid_bigdecimal
132
134
  number
133
135
  else
134
136
  convert
@@ -173,10 +175,15 @@ module ActiveSupport
173
175
  key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
174
176
  end
175
177
 
176
- def valid_float?
177
- Float(number)
178
- rescue ArgumentError, TypeError
179
- false
178
+ def valid_bigdecimal
179
+ case number
180
+ when Float, Rational
181
+ number.to_d(0)
182
+ when String
183
+ BigDecimal(number, exception: false)
184
+ else
185
+ number.to_d rescue nil
186
+ end
180
187
  end
181
188
  end
182
189
  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_d = valid_bigdecimal
14
+ if number_d
15
+ if number_d.negative?
16
+ number_d = number_d.abs
17
+ format = options[:negative_format] if (number_d * 10**options[:precision]) >= 0.5
18
+ end
19
+ number_s = NumberToRoundedConverter.convert(number_d, 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,8 +4,8 @@ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
7
- class NumberToHumanSizeConverter < NumberConverter #:nodoc:
8
- STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
7
+ class NumberToHumanSizeConverter < NumberConverter # :nodoc:
8
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb, :zb]
9
9
 
10
10
  self.namespace = :human
11
11
  self.validate_float = true
@@ -43,13 +43,13 @@ module ActiveSupport
43
43
 
44
44
  def exponent
45
45
  max = STORAGE_UNITS.size - 1
46
- exp = (Math.log(number) / Math.log(base)).to_i
46
+ exp = (Math.log(number.abs) / Math.log(base)).to_i
47
47
  exp = max if exp > max # avoid overflow for the highest unit
48
48
  exp
49
49
  end
50
50
 
51
51
  def smaller_than_base?
52
- number.to_i < base
52
+ number.to_i.abs < base
53
53
  end
54
54
 
55
55
  def base
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/object/blank"
3
4
  require "active_support/number_helper/number_converter"
4
5
 
5
6
  module ActiveSupport
6
7
  module NumberHelper
7
- class NumberToPhoneConverter < NumberConverter #:nodoc:
8
+ class NumberToPhoneConverter < NumberConverter # :nodoc:
8
9
  def convert
9
10
  str = country_code(opts[:country_code]).dup
10
11
  str << convert_to_phone_number(number.to_s.strip)
@@ -20,14 +20,18 @@ module ActiveSupport
20
20
  end
21
21
 
22
22
  formatted_string =
23
- if rounded_number.nan? || rounded_number.infinite? || rounded_number == rounded_number.to_i
24
- "%00.#{precision}f" % rounded_number
25
- else
23
+ if rounded_number.finite?
26
24
  s = rounded_number.to_s("F")
27
- s << "0" * precision
28
25
  a, b = s.split(".", 2)
29
- a << "."
30
- a << b[0, precision]
26
+ if precision != 0
27
+ b << "0" * precision
28
+ a << "."
29
+ a << b[0, precision]
30
+ end
31
+ a
32
+ else
33
+ # Infinity/NaN
34
+ "%f" % rounded_number
31
35
  end
32
36
  else
33
37
  formatted_string = rounded_number
@@ -13,7 +13,7 @@ module ActiveSupport
13
13
  precision = absolute_precision(number)
14
14
  return number unless precision
15
15
 
16
- rounded_number = convert_to_decimal(number).round(precision, options.fetch(:round_mode, :default))
16
+ rounded_number = convert_to_decimal(number).round(precision, options.fetch(:round_mode, :default).to_sym)
17
17
  rounded_number.zero? ? rounded_number.abs : rounded_number # prevent showing negative zeros
18
18
  end
19
19
 
@@ -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