activesupport 7.1.3.4 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -1136
  3. data/lib/active_support/array_inquirer.rb +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +15 -3
  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 +19 -18
  8. data/lib/active_support/cache/file_store.rb +27 -12
  9. data/lib/active_support/cache/mem_cache_store.rb +16 -74
  10. data/lib/active_support/cache/memory_store.rb +8 -3
  11. data/lib/active_support/cache/redis_cache_store.rb +21 -15
  12. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  13. data/lib/active_support/cache.rb +76 -78
  14. data/lib/active_support/callbacks.rb +79 -116
  15. data/lib/active_support/class_attribute.rb +33 -0
  16. data/lib/active_support/code_generator.rb +24 -10
  17. data/lib/active_support/concurrency/share_lock.rb +0 -1
  18. data/lib/active_support/configuration_file.rb +15 -6
  19. data/lib/active_support/core_ext/array/conversions.rb +3 -5
  20. data/lib/active_support/core_ext/benchmark.rb +6 -9
  21. data/lib/active_support/core_ext/class/attribute.rb +24 -20
  22. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  23. data/lib/active_support/core_ext/date/blank.rb +4 -0
  24. data/lib/active_support/core_ext/date/conversions.rb +2 -2
  25. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  26. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  27. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  28. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  29. data/lib/active_support/core_ext/enumerable.rb +8 -3
  30. data/lib/active_support/core_ext/erb/util.rb +7 -2
  31. data/lib/active_support/core_ext/hash/except.rb +0 -12
  32. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  33. data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
  34. data/lib/active_support/core_ext/module/delegation.rb +20 -148
  35. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  36. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  37. data/lib/active_support/core_ext/object/blank.rb +45 -1
  38. data/lib/active_support/core_ext/object/duplicable.rb +24 -15
  39. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  40. data/lib/active_support/core_ext/object/json.rb +21 -13
  41. data/lib/active_support/core_ext/object/with.rb +5 -3
  42. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  43. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  44. data/lib/active_support/core_ext/securerandom.rb +4 -4
  45. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  46. data/lib/active_support/core_ext/string/filters.rb +1 -1
  47. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  48. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  49. data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
  50. data/lib/active_support/core_ext/time/calculations.rb +32 -30
  51. data/lib/active_support/core_ext/time/compatibility.rb +24 -0
  52. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  53. data/lib/active_support/core_ext/time/zones.rb +1 -1
  54. data/lib/active_support/core_ext.rb +0 -1
  55. data/lib/active_support/current_attributes.rb +38 -40
  56. data/lib/active_support/delegation.rb +200 -0
  57. data/lib/active_support/dependencies/autoload.rb +0 -12
  58. data/lib/active_support/dependencies.rb +0 -1
  59. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  60. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  61. data/lib/active_support/deprecation/reporting.rb +3 -17
  62. data/lib/active_support/deprecation.rb +8 -5
  63. data/lib/active_support/descendants_tracker.rb +9 -87
  64. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  65. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  66. data/lib/active_support/duration.rb +25 -16
  67. data/lib/active_support/encrypted_configuration.rb +20 -2
  68. data/lib/active_support/encrypted_file.rb +1 -1
  69. data/lib/active_support/error_reporter.rb +65 -3
  70. data/lib/active_support/evented_file_update_checker.rb +0 -2
  71. data/lib/active_support/execution_wrapper.rb +0 -1
  72. data/lib/active_support/file_update_checker.rb +1 -1
  73. data/lib/active_support/fork_tracker.rb +2 -38
  74. data/lib/active_support/gem_version.rb +4 -4
  75. data/lib/active_support/hash_with_indifferent_access.rb +21 -23
  76. data/lib/active_support/html_safe_translation.rb +7 -4
  77. data/lib/active_support/i18n_railtie.rb +19 -11
  78. data/lib/active_support/isolated_execution_state.rb +0 -2
  79. data/lib/active_support/json/encoding.rb +3 -3
  80. data/lib/active_support/log_subscriber.rb +1 -12
  81. data/lib/active_support/logger.rb +15 -2
  82. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  83. data/lib/active_support/message_pack/extensions.rb +15 -2
  84. data/lib/active_support/message_verifier.rb +12 -0
  85. data/lib/active_support/messages/codec.rb +1 -1
  86. data/lib/active_support/multibyte/chars.rb +2 -2
  87. data/lib/active_support/notifications/fanout.rb +4 -8
  88. data/lib/active_support/notifications/instrumenter.rb +32 -21
  89. data/lib/active_support/notifications.rb +28 -27
  90. data/lib/active_support/number_helper/number_converter.rb +2 -2
  91. data/lib/active_support/number_helper.rb +22 -0
  92. data/lib/active_support/option_merger.rb +2 -2
  93. data/lib/active_support/ordered_options.rb +53 -15
  94. data/lib/active_support/railtie.rb +8 -11
  95. data/lib/active_support/string_inquirer.rb +1 -1
  96. data/lib/active_support/subscriber.rb +1 -0
  97. data/lib/active_support/syntax_error_proxy.rb +1 -11
  98. data/lib/active_support/tagged_logging.rb +9 -1
  99. data/lib/active_support/test_case.rb +3 -1
  100. data/lib/active_support/testing/assertions.rb +79 -21
  101. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  102. data/lib/active_support/testing/deprecation.rb +5 -12
  103. data/lib/active_support/testing/isolation.rb +19 -9
  104. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  105. data/lib/active_support/testing/parallelization/server.rb +3 -0
  106. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  107. data/lib/active_support/testing/strict_warnings.rb +8 -4
  108. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  109. data/lib/active_support/testing/time_helpers.rb +4 -3
  110. data/lib/active_support/time_with_zone.rb +30 -17
  111. data/lib/active_support/values/time_zone.rb +25 -14
  112. data/lib/active_support/xml_mini.rb +11 -2
  113. data/lib/active_support.rb +12 -4
  114. metadata +68 -19
  115. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  116. data/lib/active_support/proxy_object.rb +0 -17
  117. data/lib/active_support/ruby_features.rb +0 -7
@@ -1,19 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
-
5
3
  class Module
6
- # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
7
- # option is not used.
8
- class DelegationError < NoMethodError; end
9
-
10
- RUBY_RESERVED_KEYWORDS = %w(__ENCODING__ __LINE__ __FILE__ alias and BEGIN begin break
11
- case class def defined? do else elsif END end ensure false for if in module next nil
12
- not or redo rescue retry return self super then true undef unless until when while yield)
13
- DELEGATION_RESERVED_KEYWORDS = %w(_ arg args block)
14
- DELEGATION_RESERVED_METHOD_NAMES = Set.new(
15
- RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS
16
- ).freeze
4
+ require "active_support/delegation"
5
+ DelegationError = ActiveSupport::DelegationError # :nodoc:
17
6
 
18
7
  # Provides a +delegate+ class method to easily expose contained objects'
19
8
  # public methods as your own.
@@ -21,7 +10,7 @@ class Module
21
10
  # ==== Options
22
11
  # * <tt>:to</tt> - Specifies the target object name as a symbol or string
23
12
  # * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
24
- # * <tt>:allow_nil</tt> - If set to true, prevents a +Module::DelegationError+
13
+ # * <tt>:allow_nil</tt> - If set to true, prevents a +ActiveSupport::DelegationError+
25
14
  # from being raised
26
15
  # * <tt>:private</tt> - If set to true, changes method visibility to private
27
16
  #
@@ -132,7 +121,7 @@ class Module
132
121
  # User.new.age # => 2
133
122
  #
134
123
  # If the target is +nil+ and does not respond to the delegated method a
135
- # +Module::DelegationError+ is raised. If you wish to instead return +nil+,
124
+ # +ActiveSupport::DelegationError+ is raised. If you wish to instead return +nil+,
136
125
  # use the <tt>:allow_nil</tt> option.
137
126
  #
138
127
  # class User < ActiveRecord::Base
@@ -141,7 +130,7 @@ class Module
141
130
  # end
142
131
  #
143
132
  # User.new.age
144
- # # => Module::DelegationError: User#age delegated to profile.age, but profile is nil
133
+ # # => ActiveSupport::DelegationError: User#age delegated to profile.age, but profile is nil
145
134
  #
146
135
  # But if not having a profile yet is fine and should not be an error
147
136
  # condition:
@@ -169,104 +158,15 @@ class Module
169
158
  #
170
159
  # The target method must be public, otherwise it will raise +NoMethodError+.
171
160
  def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
172
- unless to
173
- raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
174
- end
175
-
176
- if prefix == true && /^[^a-z_]/.match?(to)
177
- raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
178
- end
179
-
180
- method_prefix = \
181
- if prefix
182
- "#{prefix == true ? to : prefix}_"
183
- else
184
- ""
185
- end
186
-
187
- location = caller_locations(1, 1).first
188
- file, line = location.path, location.lineno
189
-
190
- receiver = to.to_s
191
- receiver = "self.#{receiver}" if DELEGATION_RESERVED_METHOD_NAMES.include?(receiver)
192
-
193
- method_def = []
194
- method_names = []
195
-
196
- method_def << "self.private" if private
197
-
198
- methods.each do |method|
199
- method_name = prefix ? "#{method_prefix}#{method}" : method
200
- method_names << method_name.to_sym
201
-
202
- # Attribute writer methods only accept one argument. Makes sure []=
203
- # methods still accept two arguments.
204
- definition = \
205
- if /[^\]]=\z/.match?(method)
206
- "arg"
207
- else
208
- method_object =
209
- begin
210
- if to.is_a?(Module)
211
- to.method(method)
212
- elsif receiver == "self.class"
213
- method(method)
214
- end
215
- rescue NameError
216
- # Do nothing. Fall back to `"..."`
217
- end
218
-
219
- if method_object
220
- parameters = method_object.parameters
221
-
222
- if (parameters.map(&:first) & [:opt, :rest, :keyreq, :key, :keyrest]).any?
223
- "..."
224
- else
225
- defn = parameters.filter_map { |type, arg| arg if type == :req }
226
- defn << "&block"
227
- defn.join(", ")
228
- end
229
- else
230
- "..."
231
- end
232
- end
233
-
234
- # The following generated method calls the target exactly once, storing
235
- # the returned value in a dummy variable.
236
- #
237
- # Reason is twofold: On one hand doing less calls is in general better.
238
- # On the other hand it could be that the target has side-effects,
239
- # whereas conceptually, from the user point of view, the delegator should
240
- # be doing one call.
241
- if allow_nil
242
- method = method.to_s
243
-
244
- method_def <<
245
- "def #{method_name}(#{definition})" <<
246
- " _ = #{receiver}" <<
247
- " if !_.nil? || nil.respond_to?(:#{method})" <<
248
- " _.#{method}(#{definition})" <<
249
- " end" <<
250
- "end"
251
- else
252
- method = method.to_s
253
- method_name = method_name.to_s
254
-
255
- method_def <<
256
- "def #{method_name}(#{definition})" <<
257
- " _ = #{receiver}" <<
258
- " _.#{method}(#{definition})" <<
259
- "rescue NoMethodError => e" <<
260
- " if _.nil? && e.name == :#{method}" <<
261
- %( raise DelegationError, "#{self}##{method_name} delegated to #{receiver}.#{method}, but #{receiver} is nil: \#{self.inspect}") <<
262
- " else" <<
263
- " raise" <<
264
- " end" <<
265
- "end"
266
- end
267
- end
268
- module_eval(method_def.join(";"), file, line)
269
- method_names
161
+ ::ActiveSupport::Delegation.generate(
162
+ self,
163
+ methods,
164
+ location: caller_locations(1, 1).first,
165
+ to: to,
166
+ prefix: prefix,
167
+ allow_nil: allow_nil,
168
+ private: private,
169
+ )
270
170
  end
271
171
 
272
172
  # When building decorators, a common pattern may emerge:
@@ -308,7 +208,7 @@ class Module
308
208
  # variables, methods, constants, etc.
309
209
  #
310
210
  # The delegated method must be public on the target, otherwise it will
311
- # raise +DelegationError+. If you wish to instead return +nil+,
211
+ # raise +ActiveSupport::DelegationError+. If you wish to instead return +nil+,
312
212
  # use the <tt>:allow_nil</tt> option.
313
213
  #
314
214
  # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
@@ -316,38 +216,10 @@ class Module
316
216
  # <tt>Marshal.dump(object)</tt>, should the delegation target method
317
217
  # of <tt>object</tt> add or remove instance variables.
318
218
  def delegate_missing_to(target, allow_nil: nil)
319
- target = target.to_s
320
- target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
321
-
322
- module_eval <<-RUBY, __FILE__, __LINE__ + 1
323
- def respond_to_missing?(name, include_private = false)
324
- # It may look like an oversight, but we deliberately do not pass
325
- # +include_private+, because they do not get delegated.
326
-
327
- return false if name == :marshal_dump || name == :_dump
328
- #{target}.respond_to?(name) || super
329
- end
330
-
331
- def method_missing(method, *args, &block)
332
- if #{target}.respond_to?(method)
333
- #{target}.public_send(method, *args, &block)
334
- else
335
- begin
336
- super
337
- rescue NoMethodError
338
- if #{target}.nil?
339
- if #{allow_nil == true}
340
- nil
341
- else
342
- raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
343
- end
344
- else
345
- raise
346
- end
347
- end
348
- end
349
- end
350
- ruby2_keywords(:method_missing)
351
- RUBY
219
+ ::ActiveSupport::Delegation.generate_method_missing(
220
+ self,
221
+ target,
222
+ allow_nil: allow_nil,
223
+ )
352
224
  end
353
225
  end
@@ -14,15 +14,12 @@ class Module
14
14
  # Kernel.warn message
15
15
  # end
16
16
  # end
17
- def deprecate(*method_names, deprecator: nil, **options)
17
+ def deprecate(*method_names, deprecator:, **options)
18
18
  if deprecator.is_a?(ActiveSupport::Deprecation)
19
19
  deprecator.deprecate_methods(self, *method_names, **options)
20
20
  elsif deprecator
21
21
  # we just need any instance to call deprecate_methods, but the deprecation will be emitted by deprecator
22
22
  ActiveSupport.deprecator.deprecate_methods(self, *method_names, **options, deprecator: deprecator)
23
- else
24
- ActiveSupport.deprecator.warn("Module.deprecate without a deprecator is deprecated")
25
- ActiveSupport::Deprecation._instance.deprecate_methods(self, *method_names, **options)
26
23
  end
27
24
  end
28
25
  end
@@ -140,6 +140,6 @@ module ActiveSupport
140
140
  end
141
141
  end
142
142
 
143
- Integer.prepend ActiveSupport::NumericWithFormat
144
- Float.prepend ActiveSupport::NumericWithFormat
145
- BigDecimal.prepend ActiveSupport::NumericWithFormat
143
+ Integer.include ActiveSupport::NumericWithFormat
144
+ Float.include ActiveSupport::NumericWithFormat
145
+ BigDecimal.include ActiveSupport::NumericWithFormat
@@ -16,7 +16,7 @@ class Object
16
16
  #
17
17
  # @return [true, false]
18
18
  def blank?
19
- respond_to?(:empty?) ? !!empty? : !self
19
+ respond_to?(:empty?) ? !!empty? : false
20
20
  end
21
21
 
22
22
  # An object is present if it's not blank.
@@ -56,6 +56,10 @@ class NilClass
56
56
  def blank?
57
57
  true
58
58
  end
59
+
60
+ def present? # :nodoc:
61
+ false
62
+ end
59
63
  end
60
64
 
61
65
  class FalseClass
@@ -67,6 +71,10 @@ class FalseClass
67
71
  def blank?
68
72
  true
69
73
  end
74
+
75
+ def present? # :nodoc:
76
+ false
77
+ end
70
78
  end
71
79
 
72
80
  class TrueClass
@@ -78,6 +86,10 @@ class TrueClass
78
86
  def blank?
79
87
  false
80
88
  end
89
+
90
+ def present? # :nodoc:
91
+ true
92
+ end
81
93
  end
82
94
 
83
95
  class Array
@@ -88,6 +100,10 @@ class Array
88
100
  #
89
101
  # @return [true, false]
90
102
  alias_method :blank?, :empty?
103
+
104
+ def present? # :nodoc:
105
+ !empty?
106
+ end
91
107
  end
92
108
 
93
109
  class Hash
@@ -98,6 +114,22 @@ class Hash
98
114
  #
99
115
  # @return [true, false]
100
116
  alias_method :blank?, :empty?
117
+
118
+ def present? # :nodoc:
119
+ !empty?
120
+ end
121
+ end
122
+
123
+ class Symbol
124
+ # A Symbol is blank if it's empty:
125
+ #
126
+ # :''.blank? # => true
127
+ # :symbol.blank? # => false
128
+ alias_method :blank?, :empty?
129
+
130
+ def present? # :nodoc:
131
+ !empty?
132
+ end
101
133
  end
102
134
 
103
135
  class String
@@ -129,6 +161,10 @@ class String
129
161
  ENCODED_BLANKS[self.encoding].match?(self)
130
162
  end
131
163
  end
164
+
165
+ def present? # :nodoc:
166
+ !blank?
167
+ end
132
168
  end
133
169
 
134
170
  class Numeric # :nodoc:
@@ -141,6 +177,10 @@ class Numeric # :nodoc:
141
177
  def blank?
142
178
  false
143
179
  end
180
+
181
+ def present?
182
+ true
183
+ end
144
184
  end
145
185
 
146
186
  class Time # :nodoc:
@@ -152,4 +192,8 @@ class Time # :nodoc:
152
192
  def blank?
153
193
  false
154
194
  end
195
+
196
+ def present?
197
+ true
198
+ end
155
199
  end
@@ -28,23 +28,32 @@ class Object
28
28
  end
29
29
  end
30
30
 
31
- class Method
32
- # Methods are not duplicable:
33
- #
34
- # method(:puts).duplicable? # => false
35
- # method(:puts).dup # => TypeError: allocator undefined for Method
36
- def duplicable?
37
- false
38
- end
31
+ methods_are_duplicable = begin
32
+ Object.instance_method(:duplicable?).dup
33
+ true
34
+ rescue TypeError
35
+ false
39
36
  end
40
37
 
41
- class UnboundMethod
42
- # Unbound methods are not duplicable:
43
- #
44
- # method(:puts).unbind.duplicable? # => false
45
- # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
46
- def duplicable?
47
- false
38
+ unless methods_are_duplicable
39
+ class Method
40
+ # Methods are not duplicable:
41
+ #
42
+ # method(:puts).duplicable? # => false
43
+ # method(:puts).dup # => TypeError: allocator undefined for Method
44
+ def duplicable?
45
+ false
46
+ end
47
+ end
48
+
49
+ class UnboundMethod
50
+ # Unbound methods are not duplicable:
51
+ #
52
+ # method(:puts).unbind.duplicable? # => false
53
+ # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
54
+ def duplicable?
55
+ false
56
+ end
48
57
  end
49
58
  end
50
59
 
@@ -17,24 +17,16 @@ class Object
17
17
  end
18
18
  end
19
19
 
20
- if Symbol.method_defined?(:name) # RUBY_VERSION >= "3.0"
21
- # Returns an array of instance variable names as strings including "@".
22
- #
23
- # class C
24
- # def initialize(x, y)
25
- # @x, @y = x, y
26
- # end
27
- # end
28
- #
29
- # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
30
- def instance_variable_names
31
- instance_variables.map(&:name)
32
- end
33
- else
34
- def instance_variable_names
35
- variables = instance_variables
36
- variables.map! { |s| s.to_s.freeze }
37
- variables
38
- end
20
+ # Returns an array of instance variable names as strings including "@".
21
+ #
22
+ # class C
23
+ # def initialize(x, y)
24
+ # @x, @y = x, y
25
+ # end
26
+ # end
27
+ #
28
+ # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
29
+ def instance_variable_names
30
+ instance_variables.map(&:name)
39
31
  end
40
32
  end
@@ -46,7 +46,7 @@ module ActiveSupport
46
46
  end
47
47
 
48
48
  [Enumerable, Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].reverse_each do |klass|
49
- klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
49
+ klass.include(ActiveSupport::ToJsonWithActiveSupportEncoder)
50
50
  end
51
51
 
52
52
  class Module
@@ -65,11 +65,9 @@ class Object
65
65
  end
66
66
  end
67
67
 
68
- if RUBY_VERSION >= "3.2"
69
- class Data # :nodoc:
70
- def as_json(options = nil)
71
- to_h.as_json(options)
72
- end
68
+ class Data # :nodoc:
69
+ def as_json(options = nil)
70
+ to_h.as_json(options)
73
71
  end
74
72
  end
75
73
 
@@ -105,7 +103,7 @@ end
105
103
 
106
104
  class Symbol
107
105
  def as_json(options = nil) # :nodoc:
108
- to_s
106
+ name
109
107
  end
110
108
  end
111
109
 
@@ -164,7 +162,12 @@ end
164
162
 
165
163
  class Array
166
164
  def as_json(options = nil) # :nodoc:
167
- map { |v| options ? v.as_json(options.dup) : v.as_json }
165
+ if options
166
+ options = options.dup.freeze unless options.frozen?
167
+ map { |v| v.as_json(options) }
168
+ else
169
+ map { |v| v.as_json }
170
+ end
168
171
  end
169
172
  end
170
173
 
@@ -184,8 +187,11 @@ class Hash
184
187
  end
185
188
 
186
189
  result = {}
187
- subset.each do |k, v|
188
- result[k.to_s] = options ? v.as_json(options.dup) : v.as_json
190
+ if options
191
+ options = options.dup.freeze unless options.frozen?
192
+ subset.each { |k, v| result[k.to_s] = v.as_json(options) }
193
+ else
194
+ subset.each { |k, v| result[k.to_s] = v.as_json }
189
195
  end
190
196
  result
191
197
  end
@@ -233,9 +239,11 @@ class Pathname # :nodoc:
233
239
  end
234
240
  end
235
241
 
236
- class IPAddr # :nodoc:
237
- def as_json(options = nil)
238
- to_s
242
+ unless IPAddr.method_defined?(:as_json, false)
243
+ class IPAddr # :nodoc:
244
+ def as_json(options = nil)
245
+ to_s
246
+ end
239
247
  end
240
248
  end
241
249
 
@@ -4,11 +4,13 @@ class Object
4
4
  # Set and restore public attributes around a block.
5
5
  #
6
6
  # client.timeout # => 5
7
- # client.with(timeout: 1) do
8
- # client.timeout # => 1
7
+ # client.with(timeout: 1) do |c|
8
+ # c.timeout # => 1
9
9
  # end
10
10
  # client.timeout # => 5
11
11
  #
12
+ # The receiver is yielded to the provided block.
13
+ #
12
14
  # This method is a shorthand for the common begin/ensure pattern:
13
15
  #
14
16
  # old_value = object.attribute
@@ -28,7 +30,7 @@ class Object
28
30
  old_values[key] = public_send(key)
29
31
  public_send("#{key}=", value)
30
32
  end
31
- yield
33
+ yield self
32
34
  ensure
33
35
  old_values.each do |key, old_value|
34
36
  public_send("#{key}=", old_value)
@@ -13,4 +13,8 @@ class Pathname
13
13
  def blank?
14
14
  to_s.empty?
15
15
  end
16
+
17
+ def present? # :nodoc:
18
+ !to_s.empty?
19
+ end
16
20
  end
@@ -4,7 +4,7 @@ class Range
4
4
  # Compare two ranges and see if they overlap each other
5
5
  # (1..5).overlap?(4..6) # => true
6
6
  # (1..5).overlap?(7..9) # => false
7
- unless Range.method_defined?(:overlap?)
7
+ unless Range.method_defined?(:overlap?) # Ruby 3.3+
8
8
  def overlap?(other)
9
9
  raise TypeError unless other.is_a? Range
10
10
 
@@ -16,9 +16,9 @@ module SecureRandom
16
16
  #
17
17
  # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
18
18
  # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
19
- if RUBY_VERSION >= "3.3"
19
+ if SecureRandom.method(:alphanumeric).parameters.size == 2 # Remove check when Ruby 3.3 is the minimum supported version
20
20
  def self.base58(n = 16)
21
- SecureRandom.alphanumeric(n, chars: BASE58_ALPHABET)
21
+ alphanumeric(n, chars: BASE58_ALPHABET)
22
22
  end
23
23
  else
24
24
  def self.base58(n = 16)
@@ -41,9 +41,9 @@ module SecureRandom
41
41
  #
42
42
  # p SecureRandom.base36 # => "4kugl2pdqmscqtje"
43
43
  # p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
44
- if RUBY_VERSION >= "3.3"
44
+ if SecureRandom.method(:alphanumeric).parameters.size == 2 # Remove check when Ruby 3.3 is the minimum supported version
45
45
  def self.base36(n = 16)
46
- SecureRandom.alphanumeric(n, chars: BASE36_ALPHABET)
46
+ alphanumeric(n, chars: BASE36_ALPHABET)
47
47
  end
48
48
  else
49
49
  def self.base36(n = 16)
@@ -22,7 +22,7 @@ class String
22
22
  def to_time(form = :local)
23
23
  parts = Date._parse(self, false)
24
24
  used_keys = %i(year mon mday hour min sec sec_fraction offset)
25
- return if (parts.keys & used_keys).empty?
25
+ return if !parts.keys.intersect?(used_keys)
26
26
 
27
27
  now = Time.now
28
28
  time = Time.new(
@@ -109,7 +109,7 @@ class String
109
109
  when omission.bytesize == truncate_to
110
110
  omission.dup
111
111
  else
112
- self.class.new.tap do |cut|
112
+ self.class.new.force_encoding(encoding).tap do |cut|
113
113
  cut_at = truncate_to - omission.bytesize
114
114
 
115
115
  each_grapheme_cluster do |grapheme|
@@ -19,7 +19,7 @@ class String
19
19
  # >> "lj".upcase
20
20
  # => "LJ"
21
21
  #
22
- # == Method chaining
22
+ # == \Method chaining
23
23
  #
24
24
  # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
25
25
  # method chaining on the result of any of these methods.
@@ -77,13 +77,6 @@ module ActiveSupport # :nodoc:
77
77
  @html_safe = other.html_safe?
78
78
  end
79
79
 
80
- def clone_empty # :nodoc:
81
- ActiveSupport.deprecator.warn <<~EOM
82
- ActiveSupport::SafeBuffer#clone_empty is deprecated and will be removed in Rails 7.2.
83
- EOM
84
- self[0, 0]
85
- end
86
-
87
80
  def concat(value)
88
81
  unless value.nil?
89
82
  super(implicit_html_escape_interpolated_argument(value))
@@ -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