activesupport 7.2.2.1 → 8.1.3

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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +422 -145
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +73 -2
  5. data/lib/active_support/benchmark.rb +21 -0
  6. data/lib/active_support/benchmarkable.rb +3 -2
  7. data/lib/active_support/broadcast_logger.rb +61 -74
  8. data/lib/active_support/cache/file_store.rb +14 -4
  9. data/lib/active_support/cache/mem_cache_store.rb +30 -29
  10. data/lib/active_support/cache/memory_store.rb +11 -5
  11. data/lib/active_support/cache/null_store.rb +2 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +43 -34
  13. data/lib/active_support/cache/strategy/local_cache.rb +72 -27
  14. data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
  15. data/lib/active_support/cache.rb +88 -20
  16. data/lib/active_support/callbacks.rb +28 -13
  17. data/lib/active_support/class_attribute.rb +33 -0
  18. data/lib/active_support/code_generator.rb +9 -0
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
  20. data/lib/active_support/concurrency/share_lock.rb +0 -1
  21. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  22. data/lib/active_support/configurable.rb +34 -0
  23. data/lib/active_support/configuration_file.rb +15 -6
  24. data/lib/active_support/continuous_integration.rb +145 -0
  25. data/lib/active_support/core_ext/array/conversions.rb +3 -3
  26. data/lib/active_support/core_ext/array.rb +7 -7
  27. data/lib/active_support/core_ext/benchmark.rb +0 -15
  28. data/lib/active_support/core_ext/big_decimal.rb +1 -1
  29. data/lib/active_support/core_ext/class/attribute.rb +26 -20
  30. data/lib/active_support/core_ext/class.rb +2 -2
  31. data/lib/active_support/core_ext/date/conversions.rb +2 -0
  32. data/lib/active_support/core_ext/date.rb +5 -5
  33. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
  34. data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
  35. data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
  36. data/lib/active_support/core_ext/date_time.rb +5 -5
  37. data/lib/active_support/core_ext/digest.rb +1 -1
  38. data/lib/active_support/core_ext/enumerable.rb +25 -8
  39. data/lib/active_support/core_ext/erb/util.rb +5 -5
  40. data/lib/active_support/core_ext/file.rb +1 -1
  41. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
  42. data/lib/active_support/core_ext/hash/except.rb +0 -12
  43. data/lib/active_support/core_ext/hash.rb +8 -8
  44. data/lib/active_support/core_ext/integer.rb +3 -3
  45. data/lib/active_support/core_ext/kernel.rb +3 -3
  46. data/lib/active_support/core_ext/module/attr_internal.rb +3 -4
  47. data/lib/active_support/core_ext/module/introspection.rb +3 -0
  48. data/lib/active_support/core_ext/module.rb +11 -11
  49. data/lib/active_support/core_ext/numeric.rb +3 -3
  50. data/lib/active_support/core_ext/object/json.rb +24 -11
  51. data/lib/active_support/core_ext/object/to_query.rb +7 -1
  52. data/lib/active_support/core_ext/object/try.rb +2 -2
  53. data/lib/active_support/core_ext/object.rb +13 -13
  54. data/lib/active_support/core_ext/pathname.rb +2 -2
  55. data/lib/active_support/core_ext/range/overlap.rb +3 -3
  56. data/lib/active_support/core_ext/range/sole.rb +17 -0
  57. data/lib/active_support/core_ext/range.rb +4 -4
  58. data/lib/active_support/core_ext/securerandom.rb +24 -8
  59. data/lib/active_support/core_ext/string/filters.rb +3 -3
  60. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  61. data/lib/active_support/core_ext/string/multibyte.rb +12 -3
  62. data/lib/active_support/core_ext/string/output_safety.rb +29 -13
  63. data/lib/active_support/core_ext/string.rb +13 -13
  64. data/lib/active_support/core_ext/symbol.rb +1 -1
  65. data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
  66. data/lib/active_support/core_ext/time/calculations.rb +7 -2
  67. data/lib/active_support/core_ext/time/compatibility.rb +2 -19
  68. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  69. data/lib/active_support/core_ext/time.rb +5 -5
  70. data/lib/active_support/current_attributes/test_helper.rb +2 -2
  71. data/lib/active_support/current_attributes.rb +27 -17
  72. data/lib/active_support/delegation.rb +25 -44
  73. data/lib/active_support/dependencies/interlock.rb +11 -5
  74. data/lib/active_support/dependencies.rb +6 -2
  75. data/lib/active_support/deprecation/reporting.rb +4 -21
  76. data/lib/active_support/deprecation.rb +1 -1
  77. data/lib/active_support/duration.rb +14 -10
  78. data/lib/active_support/editor.rb +70 -0
  79. data/lib/active_support/encrypted_configuration.rb +20 -2
  80. data/lib/active_support/error_reporter.rb +81 -4
  81. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  82. data/lib/active_support/event_reporter.rb +592 -0
  83. data/lib/active_support/evented_file_update_checker.rb +5 -2
  84. data/lib/active_support/execution_context.rb +75 -7
  85. data/lib/active_support/execution_wrapper.rb +1 -1
  86. data/lib/active_support/file_update_checker.rb +8 -6
  87. data/lib/active_support/gem_version.rb +4 -4
  88. data/lib/active_support/gzip.rb +1 -0
  89. data/lib/active_support/hash_with_indifferent_access.rb +61 -38
  90. data/lib/active_support/i18n_railtie.rb +19 -11
  91. data/lib/active_support/inflector/inflections.rb +34 -16
  92. data/lib/active_support/inflector/methods.rb +3 -3
  93. data/lib/active_support/inflector/transliterate.rb +6 -8
  94. data/lib/active_support/isolated_execution_state.rb +17 -17
  95. data/lib/active_support/json/decoding.rb +6 -4
  96. data/lib/active_support/json/encoding.rb +159 -21
  97. data/lib/active_support/lazy_load_hooks.rb +1 -1
  98. data/lib/active_support/log_subscriber.rb +2 -6
  99. data/lib/active_support/logger_thread_safe_level.rb +6 -3
  100. data/lib/active_support/message_encryptors.rb +54 -2
  101. data/lib/active_support/message_pack/extensions.rb +6 -1
  102. data/lib/active_support/message_verifier.rb +9 -0
  103. data/lib/active_support/message_verifiers.rb +57 -3
  104. data/lib/active_support/messages/rotation_coordinator.rb +9 -0
  105. data/lib/active_support/messages/rotator.rb +10 -0
  106. data/lib/active_support/multibyte/chars.rb +12 -2
  107. data/lib/active_support/multibyte.rb +4 -0
  108. data/lib/active_support/notifications/fanout.rb +64 -43
  109. data/lib/active_support/notifications/instrumenter.rb +1 -1
  110. data/lib/active_support/number_helper/number_converter.rb +1 -1
  111. data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
  112. data/lib/active_support/number_helper.rb +22 -0
  113. data/lib/active_support/railtie.rb +32 -9
  114. data/lib/active_support/structured_event_subscriber.rb +99 -0
  115. data/lib/active_support/subscriber.rb +0 -5
  116. data/lib/active_support/syntax_error_proxy.rb +7 -0
  117. data/lib/active_support/tagged_logging.rb +5 -0
  118. data/lib/active_support/test_case.rb +67 -6
  119. data/lib/active_support/testing/assertions.rb +118 -27
  120. data/lib/active_support/testing/autorun.rb +5 -0
  121. data/lib/active_support/testing/error_reporter_assertions.rb +17 -0
  122. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  123. data/lib/active_support/testing/isolation.rb +0 -2
  124. data/lib/active_support/testing/notification_assertions.rb +92 -0
  125. data/lib/active_support/testing/parallelization/server.rb +15 -2
  126. data/lib/active_support/testing/parallelization/worker.rb +9 -3
  127. data/lib/active_support/testing/parallelization.rb +25 -1
  128. data/lib/active_support/testing/tests_without_assertions.rb +1 -1
  129. data/lib/active_support/testing/time_helpers.rb +9 -4
  130. data/lib/active_support/time_with_zone.rb +36 -23
  131. data/lib/active_support/values/time_zone.rb +19 -10
  132. data/lib/active_support/xml_mini.rb +3 -2
  133. data/lib/active_support.rb +21 -9
  134. metadata +35 -16
  135. data/lib/active_support/core_ext/range/each.rb +0 -24
  136. data/lib/active_support/proxy_object.rb +0 -20
  137. data/lib/active_support/testing/strict_warnings.rb +0 -43
@@ -12,12 +12,12 @@ class String
12
12
  # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
13
13
  #
14
14
  # >> "lj".mb_chars.upcase.to_s
15
- # => "LJ"
15
+ # # => "LJ"
16
16
  #
17
17
  # NOTE: Ruby 2.4 and later support native Unicode case mappings:
18
18
  #
19
19
  # >> "lj".upcase
20
- # => "LJ"
20
+ # # => "LJ"
21
21
  #
22
22
  # == \Method chaining
23
23
  #
@@ -35,7 +35,16 @@ class String
35
35
  # For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
36
36
  # information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
37
37
  def mb_chars
38
- ActiveSupport::Multibyte.proxy_class.new(self)
38
+ ActiveSupport.deprecator.warn(
39
+ "String#mb_chars is deprecated and will be removed in Rails 8.2. " \
40
+ "Use normal string methods instead."
41
+ )
42
+
43
+ if ActiveSupport::Multibyte.proxy_class == ActiveSupport::Multibyte::Chars
44
+ ActiveSupport::Multibyte::Chars.new(self, deprecation: false)
45
+ else
46
+ ActiveSupport::Multibyte.proxy_class.new(self)
47
+ end
39
48
  end
40
49
 
41
50
  # Returns +true+ if string has utf_8 encoding.
@@ -67,14 +67,13 @@ module ActiveSupport # :nodoc:
67
67
  original_concat(value)
68
68
  end
69
69
 
70
- def initialize(str = "")
71
- @html_safe = true
70
+ def initialize(_str = "")
72
71
  super
73
72
  end
74
73
 
75
74
  def initialize_copy(other)
76
75
  super
77
- @html_safe = other.html_safe?
76
+ @html_unsafe = true unless other.html_safe?
78
77
  end
79
78
 
80
79
  def concat(value)
@@ -116,7 +115,9 @@ module ActiveSupport # :nodoc:
116
115
  def *(_)
117
116
  new_string = super
118
117
  new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
119
- new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
118
+ if @html_unsafe
119
+ new_safe_buffer.mark_unsafe!
120
+ end
120
121
  new_safe_buffer
121
122
  end
122
123
 
@@ -128,17 +129,25 @@ module ActiveSupport # :nodoc:
128
129
  escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
129
130
  end
130
131
 
131
- self.class.new(super(escaped_args))
132
+ new_safe_buffer = self.class.new(super(escaped_args))
133
+ if @html_unsafe
134
+ new_safe_buffer.mark_unsafe!
135
+ end
136
+ new_safe_buffer
132
137
  end
133
138
 
134
- attr_reader :html_safe
135
- alias_method :html_safe?, :html_safe
136
- remove_method :html_safe
139
+ def html_safe?
140
+ @html_unsafe.nil?
141
+ end
137
142
 
138
143
  def to_s
139
144
  self
140
145
  end
141
146
 
147
+ def as_json(*)
148
+ to_str
149
+ end
150
+
142
151
  def to_param
143
152
  to_str
144
153
  end
@@ -155,7 +164,7 @@ module ActiveSupport # :nodoc:
155
164
  end # end
156
165
 
157
166
  def #{unsafe_method}!(*args) # def capitalize!(*args)
158
- @html_safe = false # @html_safe = false
167
+ @html_unsafe = true # @html_unsafe = true
159
168
  super # super
160
169
  end # end
161
170
  EOT
@@ -176,7 +185,7 @@ module ActiveSupport # :nodoc:
176
185
  end # end
177
186
 
178
187
  def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
179
- @html_safe = false # @html_safe = false
188
+ @html_unsafe = true # @html_unsafe = true
180
189
  if block # if block
181
190
  super(*args) { |*params| # super(*args) { |*params|
182
191
  set_block_back_references(block, $~) # set_block_back_references(block, $~)
@@ -189,16 +198,21 @@ module ActiveSupport # :nodoc:
189
198
  EOT
190
199
  end
191
200
 
201
+ protected
202
+ def mark_unsafe!
203
+ @html_unsafe = true
204
+ end
205
+
192
206
  private
193
207
  def explicit_html_escape_interpolated_argument(arg)
194
- (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
208
+ (!html_safe? || arg.html_safe?) ? arg : ERB::Util.unwrapped_html_escape(arg)
195
209
  end
196
210
 
197
211
  def implicit_html_escape_interpolated_argument(arg)
198
212
  if !html_safe? || arg.html_safe?
199
213
  arg
200
214
  else
201
- CGI.escapeHTML(arg.to_str)
215
+ ERB::Util.unwrapped_html_escape(arg.to_str)
202
216
  end
203
217
  end
204
218
 
@@ -210,7 +224,9 @@ module ActiveSupport # :nodoc:
210
224
 
211
225
  def string_into_safe_buffer(new_string, is_html_safe)
212
226
  new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
213
- new_safe_buffer.instance_variable_set :@html_safe, is_html_safe
227
+ unless is_html_safe
228
+ new_safe_buffer.instance_variable_set :@html_unsafe, true
229
+ end
214
230
  new_safe_buffer
215
231
  end
216
232
  end
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/string/conversions"
4
- require "active_support/core_ext/string/filters"
5
- require "active_support/core_ext/string/multibyte"
6
- require "active_support/core_ext/string/starts_ends_with"
7
- require "active_support/core_ext/string/inflections"
8
- require "active_support/core_ext/string/access"
9
- require "active_support/core_ext/string/behavior"
10
- require "active_support/core_ext/string/output_safety"
11
- require "active_support/core_ext/string/exclude"
12
- require "active_support/core_ext/string/strip"
13
- require "active_support/core_ext/string/inquiry"
14
- require "active_support/core_ext/string/indent"
15
- require "active_support/core_ext/string/zones"
3
+ require_relative "string/conversions"
4
+ require_relative "string/filters"
5
+ require_relative "string/multibyte"
6
+ require_relative "string/starts_ends_with"
7
+ require_relative "string/inflections"
8
+ require_relative "string/access"
9
+ require_relative "string/behavior"
10
+ require_relative "string/output_safety"
11
+ require_relative "string/exclude"
12
+ require_relative "string/strip"
13
+ require_relative "string/inquiry"
14
+ require_relative "string/indent"
15
+ require_relative "string/zones"
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/symbol/starts_ends_with"
3
+ require_relative "symbol/starts_ends_with"
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Thread::Backtrace::Location # :nodoc:
4
- if defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
5
- def spot(ex)
6
- ErrorHighlight.spot(ex, backtrace_location: self)
7
- end
8
- else
9
- def spot(ex)
10
- end
4
+ def spot(ex)
5
+ ErrorHighlight.spot(ex, backtrace_location: self)
11
6
  end
12
7
  end
@@ -147,6 +147,13 @@ class Time
147
147
  elsif zone.respond_to?(:utc_to_local)
148
148
  new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
149
149
 
150
+ # Some versions of Ruby have a bug where Time.new with a zone object and
151
+ # fractional seconds will end up with a broken utc_offset.
152
+ # This is fixed in Ruby 3.3.1 and 3.2.4
153
+ unless new_time.utc_offset.integer?
154
+ new_time += 0
155
+ end
156
+
150
157
  # When there are two occurrences of a nominal time due to DST ending,
151
158
  # `Time.new` chooses the first chronological occurrence (the one with a
152
159
  # larger UTC offset). However, for `change`, we want to choose the
@@ -217,8 +224,6 @@ class Time
217
224
  # Returns a new Time representing the time a number of seconds since the instance time
218
225
  def since(seconds)
219
226
  self + seconds
220
- rescue
221
- to_datetime.since(seconds)
222
227
  end
223
228
  alias :in :since
224
229
 
@@ -8,25 +8,8 @@ class Time
8
8
 
9
9
  silence_redefinition_of_method :to_time
10
10
 
11
- # Either return +self+ or the time in the local system timezone depending
12
- # on the setting of +ActiveSupport.to_time_preserves_timezone+.
11
+ # Return +self+.
13
12
  def to_time
14
- preserve_timezone ? self : getlocal
13
+ self
15
14
  end
16
-
17
- def preserve_timezone # :nodoc:
18
- active_support_local_zone == zone || super
19
- end
20
-
21
- private
22
- @@active_support_local_tz = nil
23
-
24
- def active_support_local_zone
25
- @@active_support_local_zone = nil if @@active_support_local_tz != ENV["TZ"]
26
- @@active_support_local_zone ||=
27
- begin
28
- @@active_support_local_tz = ENV["TZ"]
29
- Time.new.zone
30
- end
31
- end
32
15
  end
@@ -22,6 +22,7 @@ class Time
22
22
  offset_format = time.formatted_offset(false)
23
23
  time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}")
24
24
  },
25
+ rfc2822: lambda { |time| time.rfc2822 },
25
26
  iso8601: lambda { |time| time.iso8601 }
26
27
  }
27
28
 
@@ -40,6 +41,7 @@ class Time
40
41
  # time.to_fs(:long) # => "January 18, 2007 06:10"
41
42
  # time.to_fs(:long_ordinal) # => "January 18th, 2007 06:10"
42
43
  # time.to_fs(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
44
+ # time.to_fs(:rfc2822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
43
45
  # time.to_fs(:iso8601) # => "2007-01-18T06:10:17-06:00"
44
46
  #
45
47
  # == Adding your own time formats to +to_fs+
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/time/acts_like"
4
- require "active_support/core_ext/time/calculations"
5
- require "active_support/core_ext/time/compatibility"
6
- require "active_support/core_ext/time/conversions"
7
- require "active_support/core_ext/time/zones"
3
+ require_relative "time/acts_like"
4
+ require_relative "time/calculations"
5
+ require_relative "time/compatibility"
6
+ require_relative "time/conversions"
7
+ require_relative "time/zones"
@@ -2,12 +2,12 @@
2
2
 
3
3
  module ActiveSupport::CurrentAttributes::TestHelper # :nodoc:
4
4
  def before_setup
5
- ActiveSupport::CurrentAttributes.reset_all
5
+ ActiveSupport::CurrentAttributes.clear_all
6
6
  super
7
7
  end
8
8
 
9
9
  def after_teardown
10
10
  super
11
- ActiveSupport::CurrentAttributes.reset_all
11
+ ActiveSupport::CurrentAttributes.clear_all
12
12
  end
13
13
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/callbacks"
4
+ require "active_support/execution_context"
4
5
  require "active_support/core_ext/object/with"
5
6
  require "active_support/core_ext/enumerable"
6
7
  require "active_support/core_ext/module/delegation"
@@ -108,35 +109,35 @@ module ActiveSupport
108
109
  # ==== Options
109
110
  #
110
111
  # * <tt>:default</tt> - The default value for the attributes. If the value
111
- # is a proc or lambda, it will be called whenever an instance is
112
- # constructed. Otherwise, the value will be duplicated with +#dup+.
113
- # Default values are re-assigned when the attributes are reset.
112
+ # is a proc or lambda, it will be called whenever an instance is
113
+ # constructed. Otherwise, the value will be duplicated with +#dup+.
114
+ # Default values are re-assigned when the attributes are reset.
114
115
  def attribute(*names, default: NOT_SET)
115
116
  invalid_attribute_names = names.map(&:to_sym) & INVALID_ATTRIBUTE_NAMES
116
117
  if invalid_attribute_names.any?
117
118
  raise ArgumentError, "Restricted attribute names: #{invalid_attribute_names.join(", ")}"
118
119
  end
119
120
 
121
+ Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
122
+ Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
123
+
120
124
  ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
121
125
  names.each do |name|
122
126
  owner.define_cached_method(name, namespace: :current_attributes) do |batch|
123
127
  batch <<
124
128
  "def #{name}" <<
125
- "attributes[:#{name}]" <<
129
+ "@attributes[:#{name}]" <<
126
130
  "end"
127
131
  end
128
132
  owner.define_cached_method("#{name}=", namespace: :current_attributes) do |batch|
129
133
  batch <<
130
134
  "def #{name}=(value)" <<
131
- "attributes[:#{name}] = value" <<
135
+ "@attributes[:#{name}] = value" <<
132
136
  "end"
133
137
  end
134
138
  end
135
139
  end
136
140
 
137
- Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
138
- Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
139
-
140
141
  self.defaults = defaults.merge(names.index_with { default })
141
142
  end
142
143
 
@@ -153,13 +154,11 @@ module ActiveSupport
153
154
 
154
155
  delegate :set, :reset, to: :instance
155
156
 
156
- def reset_all # :nodoc:
157
- current_instances.each_value(&:reset)
158
- end
159
-
160
157
  def clear_all # :nodoc:
161
- reset_all
162
- current_instances.clear
158
+ if instances = current_instances
159
+ instances.values.each(&:reset)
160
+ instances.clear
161
+ end
163
162
  end
164
163
 
165
164
  private
@@ -168,7 +167,7 @@ module ActiveSupport
168
167
  end
169
168
 
170
169
  def current_instances
171
- IsolatedExecutionState[:current_attributes_instances] ||= {}
170
+ ExecutionContext.current_attributes_instances
172
171
  end
173
172
 
174
173
  def current_instances_key
@@ -185,21 +184,32 @@ module ActiveSupport
185
184
 
186
185
  def method_added(name)
187
186
  super
187
+
188
+ # We try to generate instance delegators early to not rely on method_missing.
188
189
  return if name == :initialize
190
+
191
+ # If the added method isn't public, we don't delegate it.
189
192
  return unless public_method_defined?(name)
190
- return if respond_to?(name, true)
193
+
194
+ # If we already have a class method by that name, we don't override it.
195
+ return if singleton_class.method_defined?(name) || singleton_class.private_method_defined?(name)
196
+
191
197
  Delegation.generate(singleton_class, [name], to: :instance, as: self, nilable: false)
192
198
  end
193
199
  end
194
200
 
195
201
  class_attribute :defaults, instance_writer: false, default: {}.freeze
196
202
 
197
- attr_accessor :attributes
203
+ attr_writer :attributes
198
204
 
199
205
  def initialize
200
206
  @attributes = resolve_defaults
201
207
  end
202
208
 
209
+ def attributes
210
+ @attributes.dup
211
+ end
212
+
203
213
  # Expose one or more attributes within a block. Old values are returned after the block concludes.
204
214
  # Example demonstrating the common use of needing to set Current attributes outside the request-cycle:
205
215
  #
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
-
5
3
  module ActiveSupport
6
4
  # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
7
5
  # option is not used.
@@ -136,11 +134,11 @@ module ActiveSupport
136
134
  "def #{method_name}(#{definition})" <<
137
135
  " _ = #{receiver}" <<
138
136
  " _.#{method}(#{definition})" <<
139
- "rescue NoMethodError => e" <<
137
+ "rescue ::NoMethodError => e" <<
140
138
  " if _.nil? && e.name == :#{method}" <<
141
- " raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
139
+ " ::Kernel.raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
142
140
  " else" <<
143
- " raise" <<
141
+ " ::Kernel.raise" <<
144
142
  " end" <<
145
143
  "end"
146
144
  end
@@ -153,49 +151,32 @@ module ActiveSupport
153
151
  target = target.to_s
154
152
  target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target) || target == "__target"
155
153
 
156
- if allow_nil
157
- owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
158
- def respond_to_missing?(name, include_private = false)
159
- # It may look like an oversight, but we deliberately do not pass
160
- # +include_private+, because they do not get delegated.
161
-
162
- return false if name == :marshal_dump || name == :_dump
163
- #{target}.respond_to?(name) || super
164
- end
165
-
166
- def method_missing(method, ...)
167
- __target = #{target}
168
- if __target.nil? && !nil.respond_to?(method)
169
- nil
170
- elsif __target.respond_to?(method)
171
- __target.public_send(method, ...)
172
- else
173
- super
174
- end
175
- end
176
- RUBY
154
+ nil_behavior = if allow_nil
155
+ "nil"
177
156
  else
178
- owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
179
- def respond_to_missing?(name, include_private = false)
180
- # It may look like an oversight, but we deliberately do not pass
181
- # +include_private+, because they do not get delegated.
157
+ "::Kernel.raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')"
158
+ end
182
159
 
183
- return false if name == :marshal_dump || name == :_dump
184
- #{target}.respond_to?(name) || super
185
- end
160
+ owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
161
+ def respond_to_missing?(name, include_private = false)
162
+ # It may look like an oversight, but we deliberately do not pass
163
+ # +include_private+, because they do not get delegated.
186
164
 
187
- def method_missing(method, ...)
188
- __target = #{target}
189
- if __target.nil? && !nil.respond_to?(method)
190
- raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')
191
- elsif __target.respond_to?(method)
192
- __target.public_send(method, ...)
193
- else
194
- super
195
- end
165
+ return false if name == :marshal_dump || name == :_dump
166
+ #{target}.respond_to?(name) || super
167
+ end
168
+
169
+ def method_missing(method, ...)
170
+ __target = #{target}
171
+ if __target.nil? && !nil.respond_to?(method)
172
+ #{nil_behavior}
173
+ elsif __target.respond_to?(method)
174
+ __target.public_send(method, ...)
175
+ else
176
+ super
196
177
  end
197
- RUBY
198
- end
178
+ end
179
+ RUBY
199
180
  end
200
181
  end
201
182
  end
@@ -10,19 +10,24 @@ module ActiveSupport # :nodoc:
10
10
  end
11
11
 
12
12
  def loading(&block)
13
- @lock.exclusive(purpose: :load, compatible: [:load], after_compatible: [:load], &block)
13
+ ActiveSupport.deprecator.warn(
14
+ "ActiveSupport::Dependencies::Interlock#loading is deprecated and " \
15
+ "will be removed in Rails 9.0. The loading interlock is no longer " \
16
+ "used since Rails switched to Zeitwerk for autoloading."
17
+ )
18
+ yield if block
14
19
  end
15
20
 
16
21
  def unloading(&block)
17
- @lock.exclusive(purpose: :unload, compatible: [:load, :unload], after_compatible: [:load, :unload], &block)
22
+ @lock.exclusive(purpose: :unload, compatible: [:unload], after_compatible: [:unload], &block)
18
23
  end
19
24
 
20
25
  def start_unloading
21
- @lock.start_exclusive(purpose: :unload, compatible: [:load, :unload])
26
+ @lock.start_exclusive(purpose: :unload, compatible: [:unload])
22
27
  end
23
28
 
24
29
  def done_unloading
25
- @lock.stop_exclusive(compatible: [:load, :unload])
30
+ @lock.stop_exclusive(compatible: [:unload])
26
31
  end
27
32
 
28
33
  def start_running
@@ -38,7 +43,8 @@ module ActiveSupport # :nodoc:
38
43
  end
39
44
 
40
45
  def permit_concurrent_loads(&block)
41
- @lock.yield_shares(compatible: [:load], &block)
46
+ # Soft deprecated: no deprecation warning for now, but this is a no-op.
47
+ yield if block
42
48
  end
43
49
 
44
50
  def raw_state(&block) # :nodoc:
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
3
  require "active_support/dependencies/interlock"
5
4
 
6
5
  module ActiveSupport # :nodoc:
@@ -22,7 +21,12 @@ module ActiveSupport # :nodoc:
22
21
  # preventing any other thread from being inside a #run_interlock
23
22
  # block at the same time.
24
23
  def self.load_interlock(&block)
25
- interlock.loading(&block)
24
+ ActiveSupport.deprecator.warn(
25
+ "ActiveSupport::Dependencies.load_interlock is deprecated and " \
26
+ "will be removed in Rails 9.0. The loading interlock is no longer " \
27
+ "used since Rails switched to Zeitwerk for autoloading."
28
+ )
29
+ yield if block
26
30
  end
27
31
 
28
32
  # Execute the supplied block while holding an exclusive lock,
@@ -139,7 +139,6 @@ module ActiveSupport
139
139
 
140
140
  def extract_callstack(callstack)
141
141
  return [] if callstack.empty?
142
- return _extract_callstack(callstack) if callstack.first.is_a? String
143
142
 
144
143
  offending_line = callstack.find { |frame|
145
144
  # Code generated with `eval` doesn't have an `absolute_path`, e.g. templates.
@@ -150,26 +149,10 @@ module ActiveSupport
150
149
  [offending_line.path, offending_line.lineno, offending_line.label]
151
150
  end
152
151
 
153
- def _extract_callstack(callstack)
154
- ActiveSupport.deprecator.warn(<<~MESSAGE)
155
- Passing the result of `caller` to ActiveSupport::Deprecation#warn is deprecated and will be removed in Rails 8.0.
156
-
157
- Please pass the result of `caller_locations` instead.
158
- MESSAGE
159
-
160
- offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first
161
-
162
- if offending_line
163
- if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
164
- md.captures
165
- else
166
- offending_line
167
- end
168
- end
169
- end
170
-
171
- RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/" # :nodoc:
172
- LIB_DIR = RbConfig::CONFIG["libdir"] # :nodoc:
152
+ RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
153
+ private_constant :RAILS_GEM_ROOT
154
+ LIB_DIR = RbConfig::CONFIG["libdir"]
155
+ private_constant :LIB_DIR
173
156
 
174
157
  def ignored_callstack?(path)
175
158
  path.start_with?(RAILS_GEM_ROOT, LIB_DIR) || path.include?("<internal:")
@@ -68,7 +68,7 @@ module ActiveSupport
68
68
  # and the second is a library name.
69
69
  #
70
70
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
71
- def initialize(deprecation_horizon = "8.0", gem_name = "Rails")
71
+ def initialize(deprecation_horizon = "8.2", gem_name = "Rails")
72
72
  self.gem_name = gem_name
73
73
  self.deprecation_horizon = deprecation_horizon
74
74
  # By default, warnings are not silenced and debugging is off.
@@ -491,17 +491,21 @@ module ActiveSupport
491
491
  if @parts.empty?
492
492
  time.since(sign * value)
493
493
  else
494
- @parts.inject(time) do |t, (type, number)|
495
- if type == :seconds
496
- t.since(sign * number)
497
- elsif type == :minutes
498
- t.since(sign * number * 60)
499
- elsif type == :hours
500
- t.since(sign * number * 3600)
501
- else
502
- t.advance(type => sign * number)
503
- end
494
+ @parts.each do |type, number|
495
+ t = time
496
+ time =
497
+ if type == :seconds
498
+ t.since(sign * number)
499
+ elsif type == :minutes
500
+ t.since(sign * number * 60)
501
+ elsif type == :hours
502
+ t.since(sign * number * 3600)
503
+ else
504
+ t.advance(type => sign * number)
505
+ end
504
506
  end
507
+
508
+ time
505
509
  end
506
510
  end
507
511