activesupport 7.1.3.4 → 7.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +123 -1084
  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/broadcast_logger.rb +5 -4
  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 +61 -68
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/code_generator.rb +15 -10
  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 +28 -1
  19. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  20. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  21. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  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 -148
  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/duplicable.rb +24 -15
  30. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  31. data/lib/active_support/core_ext/object/json.rb +1 -1
  32. data/lib/active_support/core_ext/object/with.rb +5 -3
  33. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  34. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  35. data/lib/active_support/core_ext/securerandom.rb +8 -24
  36. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  37. data/lib/active_support/core_ext/string/filters.rb +1 -1
  38. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  39. data/lib/active_support/core_ext/time/calculations.rb +18 -28
  40. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  41. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  42. data/lib/active_support/core_ext.rb +0 -1
  43. data/lib/active_support/current_attributes.rb +34 -40
  44. data/lib/active_support/delegation.rb +202 -0
  45. data/lib/active_support/dependencies/autoload.rb +0 -12
  46. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  47. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  48. data/lib/active_support/deprecation/reporting.rb +7 -2
  49. data/lib/active_support/deprecation.rb +8 -5
  50. data/lib/active_support/descendants_tracker.rb +9 -87
  51. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  52. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  53. data/lib/active_support/duration.rb +11 -6
  54. data/lib/active_support/error_reporter.rb +41 -3
  55. data/lib/active_support/evented_file_update_checker.rb +0 -1
  56. data/lib/active_support/execution_wrapper.rb +0 -1
  57. data/lib/active_support/file_update_checker.rb +1 -1
  58. data/lib/active_support/fork_tracker.rb +2 -38
  59. data/lib/active_support/gem_version.rb +3 -3
  60. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  61. data/lib/active_support/html_safe_translation.rb +7 -4
  62. data/lib/active_support/json/encoding.rb +1 -1
  63. data/lib/active_support/log_subscriber.rb +1 -12
  64. data/lib/active_support/logger.rb +15 -2
  65. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  66. data/lib/active_support/message_pack/extensions.rb +15 -2
  67. data/lib/active_support/message_verifier.rb +12 -0
  68. data/lib/active_support/messages/codec.rb +1 -1
  69. data/lib/active_support/multibyte/chars.rb +2 -2
  70. data/lib/active_support/notifications/fanout.rb +4 -7
  71. data/lib/active_support/notifications/instrumenter.rb +32 -21
  72. data/lib/active_support/notifications.rb +28 -27
  73. data/lib/active_support/number_helper/number_converter.rb +2 -2
  74. data/lib/active_support/option_merger.rb +2 -2
  75. data/lib/active_support/ordered_options.rb +53 -15
  76. data/lib/active_support/proxy_object.rb +8 -5
  77. data/lib/active_support/railtie.rb +4 -11
  78. data/lib/active_support/string_inquirer.rb +1 -1
  79. data/lib/active_support/subscriber.rb +1 -0
  80. data/lib/active_support/syntax_error_proxy.rb +1 -11
  81. data/lib/active_support/tagged_logging.rb +4 -1
  82. data/lib/active_support/test_case.rb +3 -1
  83. data/lib/active_support/testing/assertions.rb +4 -4
  84. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  85. data/lib/active_support/testing/deprecation.rb +5 -12
  86. data/lib/active_support/testing/isolation.rb +18 -8
  87. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  88. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  89. data/lib/active_support/testing/strict_warnings.rb +5 -4
  90. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  91. data/lib/active_support/testing/time_helpers.rb +3 -3
  92. data/lib/active_support/time_with_zone.rb +7 -3
  93. data/lib/active_support/values/time_zone.rb +10 -1
  94. data/lib/active_support/xml_mini.rb +11 -2
  95. data/lib/active_support.rb +3 -2
  96. metadata +35 -15
  97. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  98. 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
@@ -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,18 +16,8 @@ module SecureRandom
16
16
  #
17
17
  # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
18
18
  # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
19
- if RUBY_VERSION >= "3.3"
20
- def self.base58(n = 16)
21
- SecureRandom.alphanumeric(n, chars: BASE58_ALPHABET)
22
- end
23
- else
24
- def self.base58(n = 16)
25
- SecureRandom.random_bytes(n).unpack("C*").map do |byte|
26
- idx = byte % 64
27
- idx = SecureRandom.random_number(58) if idx >= 58
28
- BASE58_ALPHABET[idx]
29
- end.join
30
- end
19
+ def self.base58(n = 16)
20
+ SecureRandom.alphanumeric(n, chars: BASE58_ALPHABET)
31
21
  end
32
22
 
33
23
  # SecureRandom.base36 generates a random base36 string in lowercase.
@@ -41,17 +31,11 @@ module SecureRandom
41
31
  #
42
32
  # p SecureRandom.base36 # => "4kugl2pdqmscqtje"
43
33
  # p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
44
- if RUBY_VERSION >= "3.3"
45
- def self.base36(n = 16)
46
- SecureRandom.alphanumeric(n, chars: BASE36_ALPHABET)
47
- end
48
- else
49
- def self.base36(n = 16)
50
- SecureRandom.random_bytes(n).unpack("C*").map do |byte|
51
- idx = byte % 64
52
- idx = SecureRandom.random_number(36) if idx >= 36
53
- BASE36_ALPHABET[idx]
54
- end.join
55
- end
34
+ def self.base36(n = 16)
35
+ SecureRandom.random_bytes(n).unpack("C*").map do |byte|
36
+ idx = byte % 64
37
+ idx = SecureRandom.random_number(36) if idx >= 36
38
+ BASE36_ALPHABET[idx]
39
+ end.join
56
40
  end
57
41
  end
@@ -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|
@@ -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))
@@ -42,20 +42,20 @@ class Time
42
42
 
43
43
  # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
44
44
  # instances can be used when called with a single argument
45
- def at_with_coercion(*args, **kwargs)
46
- return at_without_coercion(*args, **kwargs) if args.size != 1 || !kwargs.empty?
47
-
48
- # Time.at can be called with a time or numerical value
49
- time_or_number = args.first
50
-
51
- if time_or_number.is_a?(ActiveSupport::TimeWithZone)
52
- at_without_coercion(time_or_number.to_r).getlocal
53
- elsif time_or_number.is_a?(DateTime)
54
- at_without_coercion(time_or_number.to_f).getlocal
45
+ def at_with_coercion(time_or_number, *args)
46
+ if args.empty?
47
+ if time_or_number.is_a?(ActiveSupport::TimeWithZone)
48
+ at_without_coercion(time_or_number.to_r).getlocal
49
+ elsif time_or_number.is_a?(DateTime)
50
+ at_without_coercion(time_or_number.to_f).getlocal
51
+ else
52
+ at_without_coercion(time_or_number)
53
+ end
55
54
  else
56
- at_without_coercion(time_or_number)
55
+ at_without_coercion(time_or_number, *args)
57
56
  end
58
57
  end
58
+ ruby2_keywords :at_with_coercion
59
59
  alias_method :at_without_coercion, :at
60
60
  alias_method :at, :at_with_coercion
61
61
 
@@ -108,21 +108,6 @@ class Time
108
108
  subsec
109
109
  end
110
110
 
111
- unless Time.method_defined?(:floor)
112
- def floor(precision = 0)
113
- change(nsec: 0) + subsec.floor(precision)
114
- end
115
- end
116
-
117
- # Restricted Ruby version due to a bug in `Time#ceil`
118
- # See https://bugs.ruby-lang.org/issues/17025 for more details
119
- if RUBY_VERSION <= "2.8"
120
- remove_possible_method :ceil
121
- def ceil(precision = 0)
122
- change(nsec: 0) + subsec.ceil(precision)
123
- end
124
- end
125
-
126
111
  # Returns a new Time where one or more of the elements have been changed according
127
112
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
128
113
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
@@ -159,7 +144,7 @@ class Time
159
144
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
160
145
  elsif utc?
161
146
  ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
162
- elsif zone&.respond_to?(:utc_to_local)
147
+ elsif zone.respond_to?(:utc_to_local)
163
148
  new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
164
149
 
165
150
  # When there are two occurrences of a nominal time due to DST ending,
@@ -334,7 +319,12 @@ class Time
334
319
  if other.class == Time
335
320
  compare_without_coercion(other)
336
321
  elsif other.is_a?(Time)
337
- compare_without_coercion(other.to_time)
322
+ # also avoid ActiveSupport::TimeWithZone#to_time before Rails 8.0
323
+ if other.respond_to?(:comparable_time)
324
+ compare_without_coercion(other.comparable_time)
325
+ else
326
+ compare_without_coercion(other.to_time)
327
+ end
338
328
  else
339
329
  to_datetime <=> other
340
330
  end
@@ -13,4 +13,20 @@ class Time
13
13
  def to_time
14
14
  preserve_timezone ? self : getlocal
15
15
  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
16
32
  end
@@ -58,8 +58,6 @@ class Time
58
58
  end
59
59
  end
60
60
  alias_method :to_formatted_s, :to_fs
61
- alias_method :to_default_s, :to_s
62
- deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
63
61
 
64
62
  # Returns a formatted string of the offset from UTC, or an alternative
65
63
  # string if the time zone is already UTC.
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).sort.each do |path|
4
- next if path.end_with?("core_ext/uri.rb")
5
4
  require path
6
5
  end