activesupport 7.1.4.1 → 7.2.2.1

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -1129
  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 -18
  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 +60 -68
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  14. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  15. data/lib/active_support/core_ext/date/blank.rb +4 -0
  16. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  17. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  18. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  19. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  20. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  21. data/lib/active_support/core_ext/erb/util.rb +5 -0
  22. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  23. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  24. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  25. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  26. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  27. data/lib/active_support/core_ext/object/blank.rb +45 -1
  28. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  29. data/lib/active_support/core_ext/object/json.rb +6 -4
  30. data/lib/active_support/core_ext/object/with.rb +5 -3
  31. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  32. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  33. data/lib/active_support/core_ext/securerandom.rb +8 -24
  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/multibyte.rb +1 -1
  37. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  38. data/lib/active_support/core_ext/time/calculations.rb +18 -28
  39. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  40. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  41. data/lib/active_support/core_ext/time/zones.rb +1 -1
  42. data/lib/active_support/core_ext.rb +0 -1
  43. data/lib/active_support/current_attributes.rb +38 -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 +9 -4
  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/encrypted_file.rb +1 -1
  55. data/lib/active_support/error_reporter.rb +41 -3
  56. data/lib/active_support/evented_file_update_checker.rb +0 -1
  57. data/lib/active_support/execution_wrapper.rb +0 -1
  58. data/lib/active_support/file_update_checker.rb +1 -1
  59. data/lib/active_support/fork_tracker.rb +2 -38
  60. data/lib/active_support/gem_version.rb +2 -2
  61. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  62. data/lib/active_support/html_safe_translation.rb +3 -0
  63. data/lib/active_support/log_subscriber.rb +0 -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/multibyte/chars.rb +2 -2
  69. data/lib/active_support/notifications/fanout.rb +4 -7
  70. data/lib/active_support/notifications/instrumenter.rb +21 -18
  71. data/lib/active_support/notifications.rb +28 -27
  72. data/lib/active_support/number_helper/number_converter.rb +2 -2
  73. data/lib/active_support/option_merger.rb +2 -2
  74. data/lib/active_support/ordered_options.rb +53 -15
  75. data/lib/active_support/proxy_object.rb +8 -5
  76. data/lib/active_support/railtie.rb +4 -11
  77. data/lib/active_support/string_inquirer.rb +1 -1
  78. data/lib/active_support/subscriber.rb +1 -0
  79. data/lib/active_support/tagged_logging.rb +0 -1
  80. data/lib/active_support/test_case.rb +3 -1
  81. data/lib/active_support/testing/assertions.rb +4 -4
  82. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  83. data/lib/active_support/testing/deprecation.rb +5 -12
  84. data/lib/active_support/testing/isolation.rb +20 -8
  85. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  86. data/lib/active_support/testing/parallelization/server.rb +3 -0
  87. data/lib/active_support/testing/strict_warnings.rb +8 -4
  88. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  89. data/lib/active_support/testing/time_helpers.rb +3 -3
  90. data/lib/active_support/time_with_zone.rb +8 -4
  91. data/lib/active_support/values/time_zone.rb +7 -7
  92. data/lib/active_support/xml_mini.rb +11 -2
  93. data/lib/active_support.rb +2 -1
  94. metadata +49 -15
  95. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  96. data/lib/active_support/ruby_features.rb +0 -7
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/module/attribute_accessors"
4
+ require "active_support/core_ext/module/redefine_method"
4
5
 
5
6
  module DateAndTime
6
7
  module Compatibility
@@ -11,7 +12,33 @@ module DateAndTime
11
12
  # of the receiver. For backwards compatibility we're overriding
12
13
  # this behavior, but new apps will have an initializer that sets
13
14
  # this to true, because the new behavior is preferred.
14
- mattr_accessor :preserve_timezone, instance_writer: false, default: false
15
+ mattr_accessor :preserve_timezone, instance_accessor: false, default: nil
16
+
17
+ singleton_class.silence_redefinition_of_method :preserve_timezone
18
+
19
+ #--
20
+ # This re-implements the behaviour of the mattr_reader, instead
21
+ # of prepending on to it, to avoid overcomplicating a module that
22
+ # is in turn included in several places. This will all go away in
23
+ # Rails 8.0 anyway.
24
+ def self.preserve_timezone # :nodoc:
25
+ if @@preserve_timezone.nil?
26
+ # Only warn once, the first time the value is used (which should
27
+ # be the first time #to_time is called).
28
+ ActiveSupport.deprecator.warn(
29
+ "to_time will always preserve the timezone offset of the receiver in Rails 8.0. " \
30
+ "To opt in to the new behavior, set `ActiveSupport.to_time_preserves_timezone = true`."
31
+ )
32
+
33
+ @@preserve_timezone = false
34
+ end
35
+
36
+ @@preserve_timezone
37
+ end
38
+
39
+ def preserve_timezone # :nodoc:
40
+ Compatibility.preserve_timezone
41
+ end
15
42
 
16
43
  # Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
17
44
  #
@@ -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
@@ -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
@@ -53,6 +53,12 @@ module Digest
53
53
  SecureRandom.uuid
54
54
  end
55
55
 
56
+ # Returns the nil UUID. This is a special form of UUID that is specified to
57
+ # have all 128 bits set to zero.
58
+ def self.nil_uuid
59
+ "00000000-0000-0000-0000-000000000000"
60
+ end
61
+
56
62
  def self.pack_uuid_namespace(namespace)
57
63
  if [DNS_NAMESPACE, OID_NAMESPACE, URL_NAMESPACE, X500_NAMESPACE].include?(namespace)
58
64
  namespace
@@ -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 8.0.
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
@@ -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,53 +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) || target == "__target"
321
-
322
- if allow_nil
323
- module_eval <<~RUBY, __FILE__, __LINE__ + 1
324
- def respond_to_missing?(name, include_private = false)
325
- # It may look like an oversight, but we deliberately do not pass
326
- # +include_private+, because they do not get delegated.
327
-
328
- return false if name == :marshal_dump || name == :_dump
329
- #{target}.respond_to?(name) || super
330
- end
331
-
332
- def method_missing(method, *args, &block)
333
- __target = #{target}
334
- if __target.nil? && !nil.respond_to?(method)
335
- nil
336
- elsif __target.respond_to?(method)
337
- __target.public_send(method, *args, &block)
338
- else
339
- super
340
- end
341
- end
342
- ruby2_keywords(:method_missing)
343
- RUBY
344
- else
345
- module_eval <<~RUBY, __FILE__, __LINE__ + 1
346
- def respond_to_missing?(name, include_private = false)
347
- # It may look like an oversight, but we deliberately do not pass
348
- # +include_private+, because they do not get delegated.
349
-
350
- return false if name == :marshal_dump || name == :_dump
351
- #{target}.respond_to?(name) || super
352
- end
353
-
354
- def method_missing(method, *args, &block)
355
- __target = #{target}
356
- if __target.nil? && !nil.respond_to?(method)
357
- raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
358
- elsif __target.respond_to?(method)
359
- __target.public_send(method, *args, &block)
360
- else
361
- super
362
- end
363
- end
364
- ruby2_keywords(:method_missing)
365
- RUBY
366
- end
219
+ ::ActiveSupport::Delegation.generate_method_missing(
220
+ self,
221
+ target,
222
+ allow_nil: allow_nil,
223
+ )
367
224
  end
368
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
@@ -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
@@ -233,9 +233,11 @@ class Pathname # :nodoc:
233
233
  end
234
234
  end
235
235
 
236
- class IPAddr # :nodoc:
237
- def as_json(options = nil)
238
- to_s
236
+ unless IPAddr.method_defined?(:as_json, false)
237
+ class IPAddr # :nodoc:
238
+ def as_json(options = nil)
239
+ to_s
240
+ end
239
241
  end
240
242
  end
241
243
 
@@ -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(