activesupport 6.0.4.4 → 7.0.4.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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +257 -532
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +2 -2
  6. data/lib/active_support/backtrace_cleaner.rb +5 -5
  7. data/lib/active_support/benchmarkable.rb +3 -3
  8. data/lib/active_support/cache/file_store.rb +16 -10
  9. data/lib/active_support/cache/mem_cache_store.rb +163 -42
  10. data/lib/active_support/cache/memory_store.rb +57 -29
  11. data/lib/active_support/cache/null_store.rb +10 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +79 -98
  13. data/lib/active_support/cache/strategy/local_cache.rb +49 -57
  14. data/lib/active_support/cache.rb +378 -179
  15. data/lib/active_support/callbacks.rb +230 -122
  16. data/lib/active_support/code_generator.rb +65 -0
  17. data/lib/active_support/concern.rb +49 -5
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  19. data/lib/active_support/concurrency/share_lock.rb +2 -2
  20. data/lib/active_support/configurable.rb +9 -6
  21. data/lib/active_support/configuration_file.rb +51 -0
  22. data/lib/active_support/core_ext/array/access.rb +1 -5
  23. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  24. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  25. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  26. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  27. data/lib/active_support/core_ext/array.rb +1 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  31. data/lib/active_support/core_ext/class/subclasses.rb +9 -22
  32. data/lib/active_support/core_ext/date/blank.rb +1 -1
  33. data/lib/active_support/core_ext/date/calculations.rb +9 -9
  34. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  35. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  36. data/lib/active_support/core_ext/date.rb +1 -0
  37. data/lib/active_support/core_ext/date_and_time/calculations.rb +17 -4
  38. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  39. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  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 +22 -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 +164 -23
  45. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  46. data/lib/active_support/core_ext/hash/conversions.rb +2 -3
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  49. data/lib/active_support/core_ext/hash/keys.rb +2 -2
  50. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  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/load_error.rb +1 -1
  54. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  55. data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
  56. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
  57. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  58. data/lib/active_support/core_ext/module/delegation.rb +40 -36
  59. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  60. data/lib/active_support/core_ext/name_error.rb +23 -2
  61. data/lib/active_support/core_ext/numeric/conversions.rb +80 -73
  62. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  63. data/lib/active_support/core_ext/numeric.rb +1 -0
  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 +1 -1
  67. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  68. data/lib/active_support/core_ext/object/json.rb +42 -26
  69. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  70. data/lib/active_support/core_ext/object/try.rb +20 -20
  71. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  72. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  73. data/lib/active_support/core_ext/pathname.rb +3 -0
  74. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  75. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  76. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  77. data/lib/active_support/core_ext/range/each.rb +1 -1
  78. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
  79. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  80. data/lib/active_support/core_ext/range.rb +1 -1
  81. data/lib/active_support/core_ext/regexp.rb +8 -1
  82. data/lib/active_support/core_ext/securerandom.rb +1 -1
  83. data/lib/active_support/core_ext/string/access.rb +5 -24
  84. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  85. data/lib/active_support/core_ext/string/filters.rb +1 -1
  86. data/lib/active_support/core_ext/string/inflections.rb +39 -5
  87. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  88. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  89. data/lib/active_support/core_ext/string/output_safety.rb +92 -41
  90. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  91. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  92. data/lib/active_support/core_ext/symbol.rb +3 -0
  93. data/lib/active_support/core_ext/time/calculations.rb +25 -7
  94. data/lib/active_support/core_ext/time/conversions.rb +15 -12
  95. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  96. data/lib/active_support/core_ext/time/zones.rb +7 -22
  97. data/lib/active_support/core_ext/time.rb +1 -0
  98. data/lib/active_support/core_ext/uri.rb +3 -23
  99. data/lib/active_support/core_ext.rb +2 -1
  100. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  101. data/lib/active_support/current_attributes.rb +39 -16
  102. data/lib/active_support/dependencies/interlock.rb +10 -18
  103. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  104. data/lib/active_support/dependencies.rb +58 -769
  105. data/lib/active_support/deprecation/behaviors.rb +23 -7
  106. data/lib/active_support/deprecation/disallowed.rb +56 -0
  107. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  108. data/lib/active_support/deprecation/method_wrappers.rb +6 -5
  109. data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
  110. data/lib/active_support/deprecation/reporting.rb +50 -7
  111. data/lib/active_support/deprecation.rb +7 -2
  112. data/lib/active_support/descendants_tracker.rb +174 -64
  113. data/lib/active_support/digest.rb +5 -3
  114. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  115. data/lib/active_support/duration/iso8601_serializer.rb +24 -10
  116. data/lib/active_support/duration.rb +134 -55
  117. data/lib/active_support/encrypted_configuration.rb +13 -2
  118. data/lib/active_support/encrypted_file.rb +32 -3
  119. data/lib/active_support/environment_inquirer.rb +20 -0
  120. data/lib/active_support/error_reporter.rb +117 -0
  121. data/lib/active_support/evented_file_update_checker.rb +72 -138
  122. data/lib/active_support/execution_context/test_helper.rb +13 -0
  123. data/lib/active_support/execution_context.rb +53 -0
  124. data/lib/active_support/execution_wrapper.rb +43 -21
  125. data/lib/active_support/executor/test_helper.rb +7 -0
  126. data/lib/active_support/fork_tracker.rb +71 -0
  127. data/lib/active_support/gem_version.rb +3 -3
  128. data/lib/active_support/hash_with_indifferent_access.rb +51 -25
  129. data/lib/active_support/html_safe_translation.rb +43 -0
  130. data/lib/active_support/i18n.rb +1 -0
  131. data/lib/active_support/i18n_railtie.rb +14 -19
  132. data/lib/active_support/inflector/inflections.rb +24 -9
  133. data/lib/active_support/inflector/methods.rb +29 -49
  134. data/lib/active_support/inflector/transliterate.rb +5 -5
  135. data/lib/active_support/isolated_execution_state.rb +72 -0
  136. data/lib/active_support/json/decoding.rb +4 -4
  137. data/lib/active_support/json/encoding.rb +8 -4
  138. data/lib/active_support/key_generator.rb +23 -6
  139. data/lib/active_support/lazy_load_hooks.rb +28 -4
  140. data/lib/active_support/locale/en.yml +8 -4
  141. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  142. data/lib/active_support/log_subscriber.rb +23 -5
  143. data/lib/active_support/logger.rb +1 -1
  144. data/lib/active_support/logger_silence.rb +2 -26
  145. data/lib/active_support/logger_thread_safe_level.rb +34 -21
  146. data/lib/active_support/message_encryptor.rb +16 -13
  147. data/lib/active_support/message_verifier.rb +50 -18
  148. data/lib/active_support/messages/metadata.rb +2 -2
  149. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  150. data/lib/active_support/messages/rotator.rb +6 -5
  151. data/lib/active_support/multibyte/chars.rb +13 -52
  152. data/lib/active_support/multibyte/unicode.rb +1 -87
  153. data/lib/active_support/multibyte.rb +1 -1
  154. data/lib/active_support/notifications/fanout.rb +110 -69
  155. data/lib/active_support/notifications/instrumenter.rb +37 -29
  156. data/lib/active_support/notifications.rb +55 -28
  157. data/lib/active_support/number_helper/number_converter.rb +2 -4
  158. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  159. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  160. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  161. data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
  162. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  163. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  164. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  165. data/lib/active_support/number_helper.rb +29 -16
  166. data/lib/active_support/option_merger.rb +11 -18
  167. data/lib/active_support/ordered_hash.rb +1 -1
  168. data/lib/active_support/ordered_options.rb +9 -3
  169. data/lib/active_support/parameter_filter.rb +21 -11
  170. data/lib/active_support/per_thread_registry.rb +6 -1
  171. data/lib/active_support/rails.rb +1 -4
  172. data/lib/active_support/railtie.rb +77 -5
  173. data/lib/active_support/reloader.rb +1 -1
  174. data/lib/active_support/rescuable.rb +16 -16
  175. data/lib/active_support/ruby_features.rb +7 -0
  176. data/lib/active_support/secure_compare_rotator.rb +51 -0
  177. data/lib/active_support/security_utils.rb +19 -12
  178. data/lib/active_support/string_inquirer.rb +2 -2
  179. data/lib/active_support/subscriber.rb +19 -25
  180. data/lib/active_support/tagged_logging.rb +31 -6
  181. data/lib/active_support/test_case.rb +13 -21
  182. data/lib/active_support/testing/assertions.rb +50 -13
  183. data/lib/active_support/testing/deprecation.rb +52 -1
  184. data/lib/active_support/testing/isolation.rb +2 -2
  185. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  186. data/lib/active_support/testing/parallelization/server.rb +82 -0
  187. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  188. data/lib/active_support/testing/parallelization.rb +16 -95
  189. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  190. data/lib/active_support/testing/stream.rb +3 -5
  191. data/lib/active_support/testing/tagged_logging.rb +1 -1
  192. data/lib/active_support/testing/time_helpers.rb +53 -5
  193. data/lib/active_support/time_with_zone.rb +126 -62
  194. data/lib/active_support/values/time_zone.rb +54 -23
  195. data/lib/active_support/version.rb +1 -1
  196. data/lib/active_support/xml_mini/jdom.rb +1 -1
  197. data/lib/active_support/xml_mini/libxml.rb +5 -5
  198. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  199. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  200. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  201. data/lib/active_support/xml_mini/rexml.rb +9 -2
  202. data/lib/active_support/xml_mini.rb +5 -4
  203. data/lib/active_support.rb +29 -1
  204. metadata +46 -45
  205. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  206. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  207. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  208. data/lib/active_support/core_ext/marshal.rb +0 -24
  209. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  210. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  211. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  212. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -3,11 +3,12 @@
3
3
  module ActiveSupport
4
4
  module Messages
5
5
  module Rotator # :nodoc:
6
- def initialize(*, **options)
7
- super
6
+ def initialize(*secrets, on_rotation: nil, **options)
7
+ super(*secrets, **options)
8
8
 
9
9
  @options = options
10
10
  @rotations = []
11
+ @on_rotation = on_rotation
11
12
  end
12
13
 
13
14
  def rotate(*secrets, **options)
@@ -17,7 +18,7 @@ module ActiveSupport
17
18
  module Encryptor
18
19
  include Rotator
19
20
 
20
- def decrypt_and_verify(*args, on_rotation: nil, **options)
21
+ def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
21
22
  super
22
23
  rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
23
24
  run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
@@ -32,7 +33,7 @@ module ActiveSupport
32
33
  module Verifier
33
34
  include Rotator
34
35
 
35
- def verified(*args, on_rotation: nil, **options)
36
+ def verified(*args, on_rotation: @on_rotation, **options)
36
37
  super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
37
38
  end
38
39
 
@@ -46,7 +47,7 @@ module ActiveSupport
46
47
  def run_rotations(on_rotation)
47
48
  @rotations.find do |rotation|
48
49
  if message = yield(rotation) rescue next
49
- on_rotation.call if on_rotation
50
+ on_rotation&.call
50
51
  return message
51
52
  end
52
53
  end
@@ -5,8 +5,8 @@ require "active_support/core_ext/string/access"
5
5
  require "active_support/core_ext/string/behavior"
6
6
  require "active_support/core_ext/module/delegation"
7
7
 
8
- module ActiveSupport #:nodoc:
9
- module Multibyte #:nodoc:
8
+ module ActiveSupport # :nodoc:
9
+ module Multibyte # :nodoc:
10
10
  # Chars enables you to work transparently with UTF-8 encoding in the Ruby
11
11
  # String class without having extensive knowledge about the encoding. A
12
12
  # Chars object accepts a string upon initialization and proxies String
@@ -48,7 +48,7 @@ module ActiveSupport #:nodoc:
48
48
  alias to_s wrapped_string
49
49
  alias to_str wrapped_string
50
50
 
51
- delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
51
+ delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
52
52
 
53
53
  # Creates a new Chars instance by wrapping _string_.
54
54
  def initialize(string)
@@ -59,7 +59,7 @@ module ActiveSupport #:nodoc:
59
59
  # Forward all undefined methods to the wrapped string.
60
60
  def method_missing(method, *args, &block)
61
61
  result = @wrapped_string.__send__(method, *args, &block)
62
- if /!$/.match?(method)
62
+ if method.end_with?("!")
63
63
  self if result
64
64
  else
65
65
  result.kind_of?(String) ? chars(result) : result
@@ -73,17 +73,6 @@ module ActiveSupport #:nodoc:
73
73
  @wrapped_string.respond_to?(method, include_private)
74
74
  end
75
75
 
76
- # Returns +true+ when the proxy class can handle the string. Returns
77
- # +false+ otherwise.
78
- def self.consumes?(string)
79
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
80
- ActiveSupport::Multibyte::Chars.consumes? is deprecated and will be
81
- removed from Rails 6.1. Use string.is_utf8? instead.
82
- MSG
83
-
84
- string.encoding == Encoding::UTF_8
85
- end
86
-
87
76
  # Works just like <tt>String#split</tt>, with the exception that the items
88
77
  # in the resulting list are Chars instances instead of String. This makes
89
78
  # chaining methods easier.
@@ -113,7 +102,7 @@ module ActiveSupport #:nodoc:
113
102
  #
114
103
  # 'Café'.mb_chars.reverse.to_s # => 'éfaC'
115
104
  def reverse
116
- chars(@wrapped_string.scan(/\X/).reverse.join)
105
+ chars(@wrapped_string.grapheme_clusters.reverse.join)
117
106
  end
118
107
 
119
108
  # Limits the byte size of the string to a number of bytes without breaking
@@ -134,46 +123,18 @@ module ActiveSupport #:nodoc:
134
123
  end
135
124
  alias_method :titlecase, :titleize
136
125
 
137
- # Returns the KC normalization of the string by default. NFKC is
138
- # considered the best normalization form for passing strings to databases
139
- # and validations.
140
- #
141
- # * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
142
- # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
143
- # ActiveSupport::Multibyte::Unicode.default_normalization_form
144
- def normalize(form = nil)
145
- form ||= Unicode.default_normalization_form
146
-
147
- # See https://www.unicode.org/reports/tr15, Table 1
148
- if alias_form = Unicode::NORMALIZATION_FORM_ALIASES[form]
149
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
150
- ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
151
- removed from Rails 6.1. Use #unicode_normalize(:#{alias_form}) instead.
152
- MSG
153
-
154
- send(:unicode_normalize, alias_form)
155
- else
156
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
157
- ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
158
- removed from Rails 6.1. Use #unicode_normalize instead.
159
- MSG
160
-
161
- raise ArgumentError, "#{form} is not a valid normalization variant", caller
162
- end
163
- end
164
-
165
126
  # Performs canonical decomposition on all the characters.
166
127
  #
167
- # 'é'.length # => 2
168
- # 'é'.mb_chars.decompose.to_s.length # => 3
128
+ # 'é'.length # => 1
129
+ # 'é'.mb_chars.decompose.to_s.length # => 2
169
130
  def decompose
170
131
  chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
171
132
  end
172
133
 
173
134
  # Performs composition on all the characters.
174
135
  #
175
- # 'é'.length # => 3
176
- # 'é'.mb_chars.compose.to_s.length # => 2
136
+ # 'é'.length # => 1
137
+ # 'é'.mb_chars.compose.to_s.length # => 1
177
138
  def compose
178
139
  chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
179
140
  end
@@ -181,9 +142,9 @@ module ActiveSupport #:nodoc:
181
142
  # Returns the number of grapheme clusters in the string.
182
143
  #
183
144
  # 'क्षि'.mb_chars.length # => 4
184
- # 'क्षि'.mb_chars.grapheme_length # => 3
145
+ # 'क्षि'.mb_chars.grapheme_length # => 2
185
146
  def grapheme_length
186
- @wrapped_string.scan(/\X/).length
147
+ @wrapped_string.grapheme_clusters.length
187
148
  end
188
149
 
189
150
  # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
@@ -195,13 +156,13 @@ module ActiveSupport #:nodoc:
195
156
  chars(Unicode.tidy_bytes(@wrapped_string, force))
196
157
  end
197
158
 
198
- def as_json(options = nil) #:nodoc:
159
+ def as_json(options = nil) # :nodoc:
199
160
  to_s.as_json(options)
200
161
  end
201
162
 
202
163
  %w(reverse tidy_bytes).each do |method|
203
164
  define_method("#{method}!") do |*args|
204
- @wrapped_string = send(method, *args).to_s
165
+ @wrapped_string = public_send(method, *args).to_s
205
166
  self
206
167
  end
207
168
  end
@@ -5,55 +5,9 @@ module ActiveSupport
5
5
  module Unicode
6
6
  extend self
7
7
 
8
- # A list of all available normalization forms.
9
- # See https://www.unicode.org/reports/tr15/tr15-29.html for more
10
- # information about normalization.
11
- NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
12
-
13
- NORMALIZATION_FORM_ALIASES = { # :nodoc:
14
- c: :nfc,
15
- d: :nfd,
16
- kc: :nfkc,
17
- kd: :nfkd
18
- }
19
-
20
8
  # The Unicode version that is supported by the implementation
21
9
  UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
22
10
 
23
- # The default normalization used for operations that require
24
- # normalization. It can be set to any of the normalizations
25
- # in NORMALIZATION_FORMS.
26
- #
27
- # ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
28
- attr_accessor :default_normalization_form
29
- @default_normalization_form = :kc
30
-
31
- # Unpack the string at grapheme boundaries. Returns a list of character
32
- # lists.
33
- #
34
- # Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
35
- # Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
36
- def unpack_graphemes(string)
37
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
38
- ActiveSupport::Multibyte::Unicode#unpack_graphemes is deprecated and will be
39
- removed from Rails 6.1. Use string.scan(/\X/).map(&:codepoints) instead.
40
- MSG
41
-
42
- string.scan(/\X/).map(&:codepoints)
43
- end
44
-
45
- # Reverse operation of unpack_graphemes.
46
- #
47
- # Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
48
- def pack_graphemes(unpacked)
49
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
50
- ActiveSupport::Multibyte::Unicode#pack_graphemes is deprecated and will be
51
- removed from Rails 6.1. Use array.flatten.pack("U*") instead.
52
- MSG
53
-
54
- unpacked.flatten.pack("U*")
55
- end
56
-
57
11
  # Decompose composed characters to the decomposed form.
58
12
  def decompose(type, codepoints)
59
13
  if type == :compatibility
@@ -76,7 +30,7 @@ module ActiveSupport
76
30
  # Passing +true+ will forcibly tidy all bytes, assuming that the string's
77
31
  # encoding is entirely CP1252 or ISO-8859-1.
78
32
  def tidy_bytes(string, force = false)
79
- return string if string.empty?
33
+ return string if string.empty? || string.ascii_only?
80
34
  return recode_windows1252_chars(string) if force
81
35
  string.scrub { |bad| recode_windows1252_chars(bad) }
82
36
  end
@@ -107,46 +61,6 @@ module ActiveSupport
107
61
  end
108
62
  end
109
63
 
110
- # Returns the KC normalization of the string by default. NFKC is
111
- # considered the best normalization form for passing strings to databases
112
- # and validations.
113
- #
114
- # * <tt>string</tt> - The string to perform normalization on.
115
- # * <tt>form</tt> - The form you want to normalize in. Should be one of
116
- # the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
117
- # Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
118
- def normalize(string, form = nil)
119
- form ||= @default_normalization_form
120
-
121
- # See https://www.unicode.org/reports/tr15, Table 1
122
- if alias_form = NORMALIZATION_FORM_ALIASES[form]
123
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
124
- ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
125
- removed from Rails 6.1. Use String#unicode_normalize(:#{alias_form}) instead.
126
- MSG
127
-
128
- string.unicode_normalize(alias_form)
129
- else
130
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
131
- ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
132
- removed from Rails 6.1. Use String#unicode_normalize instead.
133
- MSG
134
-
135
- raise ArgumentError, "#{form} is not a valid normalization variant", caller
136
- end
137
- end
138
-
139
- %w(downcase upcase swapcase).each do |method|
140
- define_method(method) do |string|
141
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
142
- ActiveSupport::Multibyte::Unicode##{method} is deprecated and
143
- will be removed from Rails 6.1. Use String methods directly.
144
- MSG
145
-
146
- string.send(method)
147
- end
148
- end
149
-
150
64
  private
151
65
  def recode_windows1252_chars(string)
152
66
  string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ActiveSupport #:nodoc:
3
+ module ActiveSupport # :nodoc:
4
4
  module Multibyte
5
5
  autoload :Chars, "active_support/multibyte/chars"
6
6
  autoload :Unicode, "active_support/multibyte/unicode"
@@ -3,9 +3,20 @@
3
3
  require "mutex_m"
4
4
  require "concurrent/map"
5
5
  require "set"
6
+ require "active_support/core_ext/object/try"
6
7
 
7
8
  module ActiveSupport
8
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
+
9
20
  # This is a default queue implementation that ships with Notifications.
10
21
  # It just pushes events to all registered log subscribers.
11
22
  #
@@ -20,15 +31,18 @@ module ActiveSupport
20
31
  super
21
32
  end
22
33
 
23
- def subscribe(pattern = nil, callable = nil, &block)
24
- subscriber = Subscribers.new(pattern, callable || block)
34
+ def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
35
+ subscriber = Subscribers.new(pattern, callable || block, monotonic)
25
36
  synchronize do
26
- if String === pattern
37
+ case pattern
38
+ when String
27
39
  @string_subscribers[pattern] << subscriber
28
40
  @listeners_for.delete(pattern)
29
- else
41
+ when NilClass, Regexp
30
42
  @other_subscribers << subscriber
31
43
  @listeners_for.clear
44
+ else
45
+ raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
32
46
  end
33
47
  end
34
48
  subscriber
@@ -55,15 +69,40 @@ module ActiveSupport
55
69
  end
56
70
 
57
71
  def start(name, id, payload)
58
- listeners_for(name).each { |s| s.start(name, id, payload) }
72
+ iterate_guarding_exceptions(listeners_for(name)) { |s| s.start(name, id, payload) }
59
73
  end
60
74
 
61
75
  def finish(name, id, payload, listeners = listeners_for(name))
62
- listeners.each { |s| s.finish(name, id, payload) }
76
+ iterate_guarding_exceptions(listeners) { |s| s.finish(name, id, payload) }
63
77
  end
64
78
 
65
79
  def publish(name, *args)
66
- 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
67
106
  end
68
107
 
69
108
  def listeners_for(name)
@@ -84,43 +123,36 @@ module ActiveSupport
84
123
  end
85
124
 
86
125
  module Subscribers # :nodoc:
87
- def self.new(pattern, listener)
88
- subscriber_class = Timed
126
+ def self.new(pattern, listener, monotonic)
127
+ subscriber_class = monotonic ? MonotonicTimed : Timed
89
128
 
90
129
  if listener.respond_to?(:start) && listener.respond_to?(:finish)
91
130
  subscriber_class = Evented
92
131
  else
93
- # Doing all this to detect a block like `proc { |x| }` vs
94
- # `proc { |*x| }` or `proc { |**x| }`
95
- if listener.respond_to?(:parameters)
96
- params = listener.parameters
97
- if params.length == 1 && params.first.first == :opt
98
- subscriber_class = EventObject
99
- 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
100
139
  end
101
140
  end
102
141
 
103
- wrap_all pattern, subscriber_class.new(pattern, listener)
142
+ subscriber_class.new(pattern, listener)
104
143
  end
105
144
 
106
- def self.event_object_subscriber(pattern, block)
107
- wrap_all pattern, EventObject.new(pattern, block)
108
- end
109
-
110
- def self.wrap_all(pattern, subscriber)
111
- unless pattern
112
- AllMessages.new(subscriber)
113
- else
114
- subscriber
115
- end
116
- end
117
-
118
- class Matcher #:nodoc:
145
+ class Matcher # :nodoc:
119
146
  attr_reader :pattern, :exclusions
120
147
 
121
148
  def self.wrap(pattern)
122
- return pattern if String === pattern
123
- new(pattern)
149
+ if String === pattern
150
+ pattern
151
+ elsif pattern.nil?
152
+ AllMessages.new
153
+ else
154
+ new(pattern)
155
+ end
124
156
  end
125
157
 
126
158
  def initialize(pattern)
@@ -135,15 +167,26 @@ module ActiveSupport
135
167
  def ===(name)
136
168
  pattern === name && !exclusions.include?(name)
137
169
  end
170
+
171
+ class AllMessages
172
+ def ===(name)
173
+ true
174
+ end
175
+
176
+ def unsubscribe!(*)
177
+ false
178
+ end
179
+ end
138
180
  end
139
181
 
140
- class Evented #:nodoc:
182
+ class Evented # :nodoc:
141
183
  attr_reader :pattern
142
184
 
143
185
  def initialize(pattern, delegate)
144
186
  @pattern = Matcher.wrap(pattern)
145
187
  @delegate = delegate
146
188
  @can_publish = delegate.respond_to?(:publish)
189
+ @can_publish_event = delegate.respond_to?(:publish_event)
147
190
  end
148
191
 
149
192
  def publish(name, *args)
@@ -152,6 +195,14 @@ module ActiveSupport
152
195
  end
153
196
  end
154
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
+
155
206
  def start(name, id, payload)
156
207
  @delegate.start name, id, payload
157
208
  end
@@ -164,10 +215,6 @@ module ActiveSupport
164
215
  pattern === name
165
216
  end
166
217
 
167
- def matches?(name)
168
- pattern && pattern === name
169
- end
170
-
171
218
  def unsubscribe!(name)
172
219
  pattern.unsubscribe!(name)
173
220
  end
@@ -179,65 +226,59 @@ module ActiveSupport
179
226
  end
180
227
 
181
228
  def start(name, id, payload)
182
- timestack = Thread.current[:_timestack] ||= []
229
+ timestack = IsolatedExecutionState[:_timestack] ||= []
183
230
  timestack.push Time.now
184
231
  end
185
232
 
186
233
  def finish(name, id, payload)
187
- timestack = Thread.current[:_timestack]
234
+ timestack = IsolatedExecutionState[:_timestack]
188
235
  started = timestack.pop
189
236
  @delegate.call(name, started, Time.now, id, payload)
190
237
  end
191
238
  end
192
239
 
240
+ class MonotonicTimed < Evented # :nodoc:
241
+ def publish(name, *args)
242
+ @delegate.call name, *args
243
+ end
244
+
245
+ def start(name, id, payload)
246
+ timestack = IsolatedExecutionState[:_timestack_monotonic] ||= []
247
+ timestack.push Process.clock_gettime(Process::CLOCK_MONOTONIC)
248
+ end
249
+
250
+ def finish(name, id, payload)
251
+ timestack = IsolatedExecutionState[:_timestack_monotonic]
252
+ started = timestack.pop
253
+ @delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
254
+ end
255
+ end
256
+
193
257
  class EventObject < Evented
194
258
  def start(name, id, payload)
195
- stack = Thread.current[:_event_stack] ||= []
259
+ stack = IsolatedExecutionState[:_event_stack] ||= []
196
260
  event = build_event name, id, payload
197
261
  event.start!
198
262
  stack.push event
199
263
  end
200
264
 
201
265
  def finish(name, id, payload)
202
- stack = Thread.current[:_event_stack]
266
+ stack = IsolatedExecutionState[:_event_stack]
203
267
  event = stack.pop
268
+ event.payload = payload
204
269
  event.finish!
205
270
  @delegate.call event
206
271
  end
207
272
 
273
+ def publish_event(event)
274
+ @delegate.call event
275
+ end
276
+
208
277
  private
209
278
  def build_event(name, id, payload)
210
279
  ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
211
280
  end
212
281
  end
213
-
214
- class AllMessages # :nodoc:
215
- def initialize(delegate)
216
- @delegate = delegate
217
- end
218
-
219
- def start(name, id, payload)
220
- @delegate.start name, id, payload
221
- end
222
-
223
- def finish(name, id, payload)
224
- @delegate.finish name, id, payload
225
- end
226
-
227
- def publish(name, *args)
228
- @delegate.publish name, *args
229
- end
230
-
231
- def subscribed_to?(name)
232
- true
233
- end
234
-
235
- def unsubscribe!(*)
236
- false
237
- end
238
-
239
- alias :matches? :===
240
- end
241
282
  end
242
283
  end
243
284
  end