activesupport 7.1.5 → 7.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +113 -1173
  3. data/lib/active_support/array_inquirer.rb +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +10 -3
  5. data/lib/active_support/broadcast_logger.rb +18 -19
  6. data/lib/active_support/cache/file_store.rb +15 -10
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -74
  8. data/lib/active_support/cache/memory_store.rb +2 -1
  9. data/lib/active_support/cache/redis_cache_store.rb +16 -13
  10. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  11. data/lib/active_support/cache.rb +59 -67
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/code_generator.rb +10 -15
  14. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  15. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  16. data/lib/active_support/core_ext/date/blank.rb +4 -0
  17. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  18. data/lib/active_support/core_ext/date_and_time/compatibility.rb +12 -9
  19. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  20. data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
  21. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  22. data/lib/active_support/core_ext/erb/util.rb +5 -0
  23. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  24. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  25. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  26. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  27. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  28. data/lib/active_support/core_ext/object/blank.rb +45 -1
  29. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  30. data/lib/active_support/core_ext/object/json.rb +4 -6
  31. data/lib/active_support/core_ext/object/with.rb +5 -3
  32. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  33. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  34. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/string/filters.rb +1 -1
  36. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  37. data/lib/active_support/core_ext/time/calculations.rb +12 -27
  38. data/lib/active_support/core_ext/time/compatibility.rb +2 -3
  39. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  40. data/lib/active_support/core_ext.rb +0 -1
  41. data/lib/active_support/current_attributes.rb +33 -40
  42. data/lib/active_support/delegation.rb +188 -0
  43. data/lib/active_support/dependencies/autoload.rb +0 -12
  44. data/lib/active_support/deprecation/constant_accessor.rb +1 -3
  45. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  46. data/lib/active_support/deprecation/reporting.rb +9 -4
  47. data/lib/active_support/deprecation.rb +8 -5
  48. data/lib/active_support/descendants_tracker.rb +9 -87
  49. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  50. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  51. data/lib/active_support/duration.rb +11 -6
  52. data/lib/active_support/error_reporter.rb +41 -3
  53. data/lib/active_support/evented_file_update_checker.rb +0 -1
  54. data/lib/active_support/execution_wrapper.rb +0 -1
  55. data/lib/active_support/file_update_checker.rb +1 -1
  56. data/lib/active_support/fork_tracker.rb +2 -38
  57. data/lib/active_support/gem_version.rb +3 -3
  58. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  59. data/lib/active_support/html_safe_translation.rb +3 -0
  60. data/lib/active_support/log_subscriber.rb +0 -12
  61. data/lib/active_support/logger.rb +15 -2
  62. data/lib/active_support/message_pack/extensions.rb +15 -2
  63. data/lib/active_support/multibyte/chars.rb +2 -2
  64. data/lib/active_support/notifications/fanout.rb +4 -7
  65. data/lib/active_support/notifications/instrumenter.rb +21 -18
  66. data/lib/active_support/notifications.rb +28 -27
  67. data/lib/active_support/number_helper/number_converter.rb +2 -2
  68. data/lib/active_support/option_merger.rb +2 -2
  69. data/lib/active_support/ordered_options.rb +53 -15
  70. data/lib/active_support/proxy_object.rb +8 -5
  71. data/lib/active_support/railtie.rb +4 -11
  72. data/lib/active_support/string_inquirer.rb +1 -1
  73. data/lib/active_support/syntax_error_proxy.rb +11 -1
  74. data/lib/active_support/test_case.rb +3 -1
  75. data/lib/active_support/testing/assertions.rb +4 -4
  76. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  77. data/lib/active_support/testing/deprecation.rb +5 -12
  78. data/lib/active_support/testing/isolation.rb +18 -8
  79. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  80. data/lib/active_support/testing/strict_warnings.rb +5 -4
  81. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  82. data/lib/active_support/time_with_zone.rb +9 -10
  83. data/lib/active_support/values/time_zone.rb +1 -1
  84. data/lib/active_support/xml_mini.rb +11 -2
  85. data/lib/active_support.rb +7 -8
  86. metadata +20 -70
  87. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  88. data/lib/active_support/ruby_features.rb +0 -7
@@ -150,7 +150,7 @@ module ActiveSupport
150
150
  def halted_callback_hook(filter, name)
151
151
  end
152
152
 
153
- module Conditionals # :nodoc:
153
+ module Conditionals # :nodoc: all
154
154
  class Value
155
155
  def initialize(&block)
156
156
  @block = block
@@ -159,128 +159,76 @@ module ActiveSupport
159
159
  end
160
160
  end
161
161
 
162
- module Filters
162
+ module Filters # :nodoc: all
163
163
  Environment = Struct.new(:target, :halted, :value)
164
164
 
165
165
  class Before
166
- def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter, name)
166
+ def initialize(user_callback, user_conditions, chain_config, filter, name)
167
167
  halted_lambda = chain_config[:terminator]
168
-
169
- if user_conditions.any?
170
- halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
171
- else
172
- halting(callback_sequence, user_callback, halted_lambda, filter, name)
173
- end
168
+ @user_callback, @user_conditions, @halted_lambda, @filter, @name = user_callback, user_conditions, halted_lambda, filter, name
169
+ freeze
174
170
  end
171
+ attr_reader :user_callback, :user_conditions, :halted_lambda, :filter, :name
175
172
 
176
- def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
177
- callback_sequence.before do |env|
178
- target = env.target
179
- value = env.value
180
- halted = env.halted
173
+ def call(env)
174
+ target = env.target
175
+ value = env.value
176
+ halted = env.halted
181
177
 
182
- if !halted && user_conditions.all? { |c| c.call(target, value) }
183
- result_lambda = -> { user_callback.call target, value }
184
- env.halted = halted_lambda.call(target, result_lambda)
185
- if env.halted
186
- target.send :halted_callback_hook, filter, name
187
- end
178
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
179
+ result_lambda = -> { user_callback.call target, value }
180
+ env.halted = halted_lambda.call(target, result_lambda)
181
+ if env.halted
182
+ target.send :halted_callback_hook, filter, name
188
183
  end
189
-
190
- env
191
184
  end
192
- end
193
- private_class_method :halting_and_conditional
194
-
195
- def self.halting(callback_sequence, user_callback, halted_lambda, filter, name)
196
- callback_sequence.before do |env|
197
- target = env.target
198
- value = env.value
199
- halted = env.halted
200
185
 
201
- unless halted
202
- result_lambda = -> { user_callback.call target, value }
203
- env.halted = halted_lambda.call(target, result_lambda)
204
- if env.halted
205
- target.send :halted_callback_hook, filter, name
206
- end
207
- end
186
+ env
187
+ end
208
188
 
209
- env
210
- end
189
+ def apply(callback_sequence)
190
+ callback_sequence.before(self)
211
191
  end
212
- private_class_method :halting
213
192
  end
214
193
 
215
194
  class After
216
- def self.build(callback_sequence, user_callback, user_conditions, chain_config)
217
- if chain_config[:skip_after_callbacks_if_terminated]
218
- if user_conditions.any?
219
- halting_and_conditional(callback_sequence, user_callback, user_conditions)
220
- else
221
- halting(callback_sequence, user_callback)
222
- end
223
- else
224
- if user_conditions.any?
225
- conditional callback_sequence, user_callback, user_conditions
226
- else
227
- simple callback_sequence, user_callback
228
- end
229
- end
195
+ attr_reader :user_callback, :user_conditions, :halting
196
+ def initialize(user_callback, user_conditions, chain_config)
197
+ halting = chain_config[:skip_after_callbacks_if_terminated]
198
+ @user_callback, @user_conditions, @halting = user_callback, user_conditions, halting
199
+ freeze
230
200
  end
231
201
 
232
- def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
233
- callback_sequence.after do |env|
234
- target = env.target
235
- value = env.value
236
- halted = env.halted
237
-
238
- if !halted && user_conditions.all? { |c| c.call(target, value) }
239
- user_callback.call target, value
240
- end
202
+ def call(env)
203
+ target = env.target
204
+ value = env.value
205
+ halted = env.halted
241
206
 
242
- env
207
+ if (!halted || !@halting) && user_conditions.all? { |c| c.call(target, value) }
208
+ user_callback.call target, value
243
209
  end
244
- end
245
- private_class_method :halting_and_conditional
246
-
247
- def self.halting(callback_sequence, user_callback)
248
- callback_sequence.after do |env|
249
- unless env.halted
250
- user_callback.call env.target, env.value
251
- end
252
210
 
253
- env
254
- end
211
+ env
255
212
  end
256
- private_class_method :halting
257
-
258
- def self.conditional(callback_sequence, user_callback, user_conditions)
259
- callback_sequence.after do |env|
260
- target = env.target
261
- value = env.value
262
213
 
263
- if user_conditions.all? { |c| c.call(target, value) }
264
- user_callback.call target, value
265
- end
266
-
267
- env
268
- end
214
+ def apply(callback_sequence)
215
+ callback_sequence.after(self)
269
216
  end
270
- private_class_method :conditional
217
+ end
271
218
 
272
- def self.simple(callback_sequence, user_callback)
273
- callback_sequence.after do |env|
274
- user_callback.call env.target, env.value
219
+ class Around
220
+ def initialize(user_callback, user_conditions)
221
+ @user_callback, @user_conditions = user_callback, user_conditions
222
+ freeze
223
+ end
275
224
 
276
- env
277
- end
225
+ def apply(callback_sequence)
226
+ callback_sequence.around(@user_callback, @user_conditions)
278
227
  end
279
- private_class_method :simple
280
228
  end
281
229
  end
282
230
 
283
- class Callback # :nodoc:#
231
+ class Callback # :nodoc:
284
232
  def self.build(chain, filter, kind, options)
285
233
  if filter.is_a?(String)
286
234
  raise ArgumentError, <<-MSG.squish
@@ -302,6 +250,8 @@ module ActiveSupport
302
250
  @filter = filter
303
251
  @if = check_conditionals(options[:if])
304
252
  @unless = check_conditionals(options[:unless])
253
+
254
+ compiled
305
255
  end
306
256
 
307
257
  def merge_conditional_options(chain, if_option:, unless_option:)
@@ -329,19 +279,26 @@ module ActiveSupport
329
279
  end
330
280
  end
331
281
 
282
+ def compiled
283
+ @compiled ||=
284
+ begin
285
+ user_conditions = conditions_lambdas
286
+ user_callback = CallTemplate.build(@filter, self)
287
+
288
+ case kind
289
+ when :before
290
+ Filters::Before.new(user_callback.make_lambda, user_conditions, chain_config, @filter, name)
291
+ when :after
292
+ Filters::After.new(user_callback.make_lambda, user_conditions, chain_config)
293
+ when :around
294
+ Filters::Around.new(user_callback, user_conditions)
295
+ end
296
+ end
297
+ end
298
+
332
299
  # Wraps code with filter
333
300
  def apply(callback_sequence)
334
- user_conditions = conditions_lambdas
335
- user_callback = CallTemplate.build(@filter, self)
336
-
337
- case kind
338
- when :before
339
- Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter, name)
340
- when :after
341
- Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
342
- when :around
343
- callback_sequence.around(user_callback, user_conditions)
344
- end
301
+ compiled.apply(callback_sequence)
345
302
  end
346
303
 
347
304
  def current_scopes
@@ -368,14 +325,16 @@ module ActiveSupport
368
325
  end
369
326
 
370
327
  def conditions_lambdas
371
- @if.map { |c| CallTemplate.build(c, self).make_lambda } +
328
+ conditions =
329
+ @if.map { |c| CallTemplate.build(c, self).make_lambda } +
372
330
  @unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
331
+ conditions.empty? ? EMPTY_ARRAY : conditions
373
332
  end
374
333
  end
375
334
 
376
335
  # A future invocation of user-supplied code (either as a callback,
377
336
  # or a condition filter).
378
- module CallTemplate # :nodoc:
337
+ module CallTemplate # :nodoc: all
379
338
  class MethodCall
380
339
  def initialize(method)
381
340
  @method_name = method
@@ -562,16 +521,18 @@ module ActiveSupport
562
521
  @call_template = call_template
563
522
  @user_conditions = user_conditions
564
523
 
565
- @before = []
566
- @after = []
524
+ @before = nil
525
+ @after = nil
567
526
  end
568
527
 
569
- def before(&before)
528
+ def before(before)
529
+ @before ||= []
570
530
  @before.unshift(before)
571
531
  self
572
532
  end
573
533
 
574
- def after(&after)
534
+ def after(after)
535
+ @after ||= []
575
536
  @after.push(after)
576
537
  self
577
538
  end
@@ -595,11 +556,11 @@ module ActiveSupport
595
556
  end
596
557
 
597
558
  def invoke_before(arg)
598
- @before.each { |b| b.call(arg) }
559
+ @before&.each { |b| b.call(arg) }
599
560
  end
600
561
 
601
562
  def invoke_after(arg)
602
- @after.each { |a| a.call(arg) }
563
+ @after&.each { |a| a.call(arg) }
603
564
  end
604
565
  end
605
566
 
@@ -9,19 +9,16 @@ module ActiveSupport
9
9
  @cache = METHOD_CACHES[namespace]
10
10
  @sources = []
11
11
  @methods = {}
12
- @canonical_methods = {}
13
12
  end
14
13
 
15
- def define_cached_method(canonical_name, as: nil)
16
- canonical_name = canonical_name.to_sym
17
- as = (as || canonical_name).to_sym
18
-
19
- @methods.fetch(as) do
20
- unless @cache.method_defined?(canonical_name) || @canonical_methods[canonical_name]
14
+ def define_cached_method(name, as: name)
15
+ name = name.to_sym
16
+ as = as.to_sym
17
+ @methods.fetch(name) do
18
+ unless @cache.method_defined?(as)
21
19
  yield @sources
22
20
  end
23
- @canonical_methods[canonical_name] = true
24
- @methods[as] = canonical_name
21
+ @methods[name] = as
25
22
  end
26
23
  end
27
24
 
@@ -29,10 +26,8 @@ module ActiveSupport
29
26
  unless @sources.empty?
30
27
  @cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
31
28
  end
32
- @canonical_methods.clear
33
-
34
- @methods.each do |as, canonical_name|
35
- owner.define_method(as, @cache.instance_method(canonical_name))
29
+ @methods.each do |name, as|
30
+ owner.define_method(name, @cache.instance_method(as))
36
31
  end
37
32
  end
38
33
  end
@@ -57,8 +52,8 @@ module ActiveSupport
57
52
  @namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
58
53
  end
59
54
 
60
- def define_cached_method(canonical_name, namespace:, as: nil, &block)
61
- @namespaces[namespace].define_cached_method(canonical_name, as: as, &block)
55
+ def define_cached_method(name, namespace:, as: name, &block)
56
+ @namespaces[namespace].define_cached_method(name, as: as, &block)
62
57
  end
63
58
 
64
59
  def execute
@@ -104,8 +104,6 @@ class Array
104
104
  end
105
105
  end
106
106
  alias_method :to_formatted_s, :to_fs
107
- alias_method :to_default_s, :to_s
108
- deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
109
107
 
110
108
  # Returns a string that represents the array in XML by invoking +to_xml+
111
109
  # on each element. Active Record collections delegate their representation
@@ -1,43 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/ruby_features"
4
3
  require "active_support/descendants_tracker"
5
4
 
6
5
  class Class
7
- if ActiveSupport::RubyFeatures::CLASS_SUBCLASSES
8
- # Returns an array with all classes that are < than its receiver.
9
- #
10
- # class C; end
11
- # C.descendants # => []
12
- #
13
- # class B < C; end
14
- # C.descendants # => [B]
15
- #
16
- # class A < B; end
17
- # C.descendants # => [B, A]
18
- #
19
- # class D < C; end
20
- # C.descendants # => [B, A, D]
21
- def descendants
22
- subclasses.concat(subclasses.flat_map(&:descendants))
23
- end
24
- else
25
- def descendants
26
- ObjectSpace.each_object(singleton_class).reject do |k|
27
- k.singleton_class? || k == self
28
- end
29
- end
30
-
31
- # Returns an array with the direct children of +self+.
32
- #
33
- # class Foo; end
34
- # class Bar < Foo; end
35
- # class Baz < Bar; end
36
- #
37
- # Foo.subclasses # => [Bar]
38
- def subclasses
39
- descendants.select { |descendant| descendant.superclass == self }
40
- end
6
+ # Returns an array with all classes that are < than its receiver.
7
+ #
8
+ # class C; end
9
+ # C.descendants # => []
10
+ #
11
+ # class B < C; end
12
+ # C.descendants # => [B]
13
+ #
14
+ # class A < B; end
15
+ # C.descendants # => [B, A]
16
+ #
17
+ # class D < C; end
18
+ # C.descendants # => [B, A, D]
19
+ def descendants
20
+ subclasses.concat(subclasses.flat_map(&:descendants))
41
21
  end
42
22
 
43
23
  prepend ActiveSupport::DescendantsTracker::ReloadedClassesFiltering
@@ -11,4 +11,8 @@ class Date # :nodoc:
11
11
  def blank?
12
12
  false
13
13
  end
14
+
15
+ def present?
16
+ true
17
+ end
14
18
  end
@@ -56,8 +56,6 @@ class Date
56
56
  end
57
57
  end
58
58
  alias_method :to_formatted_s, :to_fs
59
- alias_method :to_default_s, :to_s
60
- deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
61
59
 
62
60
  # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
63
61
  def readable_inspect
@@ -4,15 +4,6 @@ require "active_support/core_ext/module/attribute_accessors"
4
4
 
5
5
  module DateAndTime
6
6
  module Compatibility
7
- # If true, +to_time+ preserves the timezone offset of receiver.
8
- #
9
- # NOTE: With Ruby 2.4+ the default for +to_time+ changed from
10
- # converting to the local system time, to preserving the offset
11
- # of the receiver. For backwards compatibility we're overriding
12
- # this behavior, but new apps will have an initializer that sets
13
- # this to true, because the new behavior is preferred.
14
- mattr_accessor :preserve_timezone, instance_writer: false, default: false
15
-
16
7
  # Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
17
8
  #
18
9
  # When +true+, it returns local times with a UTC offset, with +false+ local
@@ -27,5 +18,17 @@ module DateAndTime
27
18
  # # With `utc_to_local_returns_utc_offset_times = true`, local time is returned with UTC offset:
28
19
  # zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 -0500
29
20
  mattr_accessor :utc_to_local_returns_utc_offset_times, instance_writer: false, default: false
21
+
22
+ def self.preserve_timezone
23
+ ActiveSupport.deprecator.warn(
24
+ "`DateAndTime::Compatibility.preserve_timezone` has been deprecated and will be removed in Rails 7.3."
25
+ )
26
+ end
27
+
28
+ def self.preserve_timezone=(value)
29
+ ActiveSupport.deprecator.warn(
30
+ "`DateAndTime::Compatibility.preserve_timezone=` has been deprecated and will be removed in Rails 7.3."
31
+ )
32
+ end
30
33
  end
31
34
  end
@@ -11,4 +11,8 @@ class DateTime # :nodoc:
11
11
  def blank?
12
12
  false
13
13
  end
14
+
15
+ def present?
16
+ true
17
+ end
14
18
  end
@@ -8,11 +8,9 @@ class DateTime
8
8
 
9
9
  silence_redefinition_of_method :to_time
10
10
 
11
- # Either return an instance of +Time+ with the same UTC offset
12
- # as +self+ or an instance of +Time+ representing the same time
13
- # in the local system timezone depending on the setting of
14
- # on the setting of +ActiveSupport.to_time_preserves_timezone+.
11
+ # Return an instance of +Time+ with the same UTC offset
12
+ # as +self+.
15
13
  def to_time
16
- preserve_timezone ? getlocal(utc_offset) : getlocal
14
+ getlocal(utc_offset)
17
15
  end
18
16
  end
@@ -40,10 +40,6 @@ class DateTime
40
40
  end
41
41
  end
42
42
  alias_method :to_formatted_s, :to_fs
43
- if instance_methods(false).include?(:to_s)
44
- alias_method :to_default_s, :to_s
45
- deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
46
- end
47
43
 
48
44
 
49
45
  # Returns a formatted string of the offset from UTC, or an alternative
@@ -188,6 +188,11 @@ class ERB
188
188
  else
189
189
  raise NotImplementedError, source.matched
190
190
  end
191
+
192
+ unless source.eos? || source.exist?(start_re) || source.exist?(finish_re)
193
+ tokens << [:TEXT, source.rest]
194
+ source.terminate
195
+ end
191
196
  end
192
197
 
193
198
  tokens
@@ -8,13 +8,13 @@ class Hash
8
8
  # hash.stringify_keys
9
9
  # # => {"name"=>"Rob", "age"=>"28"}
10
10
  def stringify_keys
11
- transform_keys(&:to_s)
11
+ transform_keys { |k| Symbol === k ? k.name : k.to_s }
12
12
  end
13
13
 
14
14
  # Destructively converts all keys to strings. Same as
15
15
  # +stringify_keys+, but modifies +self+.
16
16
  def stringify_keys!
17
- transform_keys!(&:to_s)
17
+ transform_keys! { |k| Symbol === k ? k.name : k.to_s }
18
18
  end
19
19
 
20
20
  # Returns a new hash with all keys converted to symbols, as long as
@@ -82,14 +82,14 @@ class Hash
82
82
  # hash.deep_stringify_keys
83
83
  # # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
84
84
  def deep_stringify_keys
85
- deep_transform_keys(&:to_s)
85
+ deep_transform_keys { |k| Symbol === k ? k.name : k.to_s }
86
86
  end
87
87
 
88
88
  # Destructively converts all keys to strings.
89
89
  # This includes the keys from the root hash and from all
90
90
  # nested hashes and arrays.
91
91
  def deep_stringify_keys!
92
- deep_transform_keys!(&:to_s)
92
+ deep_transform_keys! { |k| Symbol === k ? k.name : k.to_s }
93
93
  end
94
94
 
95
95
  # Returns a new hash with all keys converted to symbols, as long as
@@ -19,16 +19,27 @@ class Module
19
19
  end
20
20
  alias_method :attr_internal, :attr_internal_accessor
21
21
 
22
- class << self; attr_accessor :attr_internal_naming_format end
23
- self.attr_internal_naming_format = "@_%s"
22
+ class << self
23
+ attr_reader :attr_internal_naming_format
24
24
 
25
- private
26
- def attr_internal_ivar_name(attr)
27
- Module.attr_internal_naming_format % attr
25
+ def attr_internal_naming_format=(format)
26
+ if format.start_with?("@")
27
+ ActiveSupport.deprecator.warn <<~MESSAGE
28
+ Setting `attr_internal_naming_format` with a `@` prefix is deprecated and will be removed in Rails 7.3.
29
+
30
+ You can simply replace #{format.inspect} by #{format.delete_prefix("@").inspect}.
31
+ MESSAGE
32
+
33
+ format = format.delete_prefix("@")
34
+ end
35
+ @attr_internal_naming_format = format
28
36
  end
37
+ end
38
+ self.attr_internal_naming_format = "_%s"
29
39
 
40
+ private
30
41
  def attr_internal_define(attr_name, type)
31
- internal_name = attr_internal_ivar_name(attr_name).delete_prefix("@")
42
+ internal_name = Module.attr_internal_naming_format % attr_name
32
43
  # use native attr_* methods as they are faster on some Ruby implementations
33
44
  public_send("attr_#{type}", internal_name)
34
45
  attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer