activesupport 7.2.0.beta2 → 7.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64a68e8272dc370b1b26c76cfc52990f1d55b0356e177baa1f6b913bf0064945
4
- data.tar.gz: 57262080af9d7a9727fb2ac430f2fdeefd98714c0c47c899af1ea3a3f5ac445e
3
+ metadata.gz: 2aaa473f08555b8cff31f1badf96b6db12166e0d598ce8b686ed9eb47c25ff16
4
+ data.tar.gz: f184db8c521f40286828664b6aadf74823179b793a4f02edb447e181810a71f9
5
5
  SHA512:
6
- metadata.gz: 145d66aa10855ae55249f6c29e8680406835c79bc1f1f8dc8d1ec6c254f2c985c7de7369760c336df537120de83d05ef20dc9c7b6426110b19a3eb717d2d9415
7
- data.tar.gz: ad780c985f5f24a1aba645ae0b9c5c425ee0dd872ddc7cc44646e6febabba0505d1f18a841fc95e1db894a7069fc884e32a7883607085c7b0a77560799ed0bb5
6
+ metadata.gz: fcd73b0e3c374fd484e6cf12240ce61910b889ebfcf8715db0307f30db54778aa9cbf309411a4246b1c092ea41935f8c3c93f5b597b36375441f9ecf9d497efc
7
+ data.tar.gz: 6206ed420d950a2051a7c60a3c98b30813f6fd85c1a63c85f2cd4432b8a8bed9473ee85468f0ebe580f3ec4d4aae08a4cee6dde571ba04638735ca604af9f5f4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## Rails 7.2.0.rc1 (August 06, 2024) ##
2
+
3
+ * Fix `delegate_missing_to allow_nil: true` when called with implict self
4
+
5
+ ```ruby
6
+ class Person
7
+ delegate_missing_to :address, allow_nil: true
8
+
9
+ def address
10
+ nil
11
+ end
12
+
13
+ def berliner?
14
+ city == "Berlin"
15
+ end
16
+ end
17
+
18
+ Person.new.city # => nil
19
+ Person.new.berliner? # undefined local variable or method `city' for an instance of Person (NameError)
20
+ ```
21
+
22
+ *Jean Boussier*
23
+
24
+ ## Rails 7.2.0.beta3 (July 11, 2024) ##
25
+
26
+ * Add `logger` as a dependency since it is a bundled gem candidate for Ruby 3.5
27
+
28
+ *Earlopain*
29
+
1
30
  ## Rails 7.2.0.beta2 (June 04, 2024) ##
2
31
 
3
32
  * Define `Digest::UUID.nil_uuid`, which returns the so-called nil UUID.
@@ -9,16 +9,19 @@ module ActiveSupport
9
9
  @cache = METHOD_CACHES[namespace]
10
10
  @sources = []
11
11
  @methods = {}
12
+ @canonical_methods = {}
12
13
  end
13
14
 
14
- def define_cached_method(name, as: name)
15
- name = name.to_sym
16
- as = as.to_sym
17
- @methods.fetch(name) do
18
- unless @cache.method_defined?(as)
15
+ def define_cached_method(canonical_name, as: nil)
16
+ canonical_name = canonical_name.to_sym
17
+ as = (as || canonical_name).to_sym
18
+
19
+ @methods.fetch(as) do
20
+ unless @cache.method_defined?(canonical_name) || @canonical_methods[canonical_name]
19
21
  yield @sources
20
22
  end
21
- @methods[name] = as
23
+ @canonical_methods[canonical_name] = true
24
+ @methods[as] = canonical_name
22
25
  end
23
26
  end
24
27
 
@@ -26,8 +29,10 @@ module ActiveSupport
26
29
  unless @sources.empty?
27
30
  @cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
28
31
  end
29
- @methods.each do |name, as|
30
- owner.define_method(name, @cache.instance_method(as))
32
+ @canonical_methods.clear
33
+
34
+ @methods.each do |as, canonical_name|
35
+ owner.define_method(as, @cache.instance_method(canonical_name))
31
36
  end
32
37
  end
33
38
  end
@@ -52,8 +57,8 @@ module ActiveSupport
52
57
  @namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
53
58
  end
54
59
 
55
- def define_cached_method(name, namespace:, as: name, &block)
56
- @namespaces[namespace].define_cached_method(name, as: as, &block)
60
+ def define_cached_method(canonical_name, namespace:, as: nil, &block)
61
+ @namespaces[namespace].define_cached_method(canonical_name, as: as, &block)
57
62
  end
58
63
 
59
64
  def execute
@@ -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
@@ -319,7 +319,12 @@ class Time
319
319
  if other.class == Time
320
320
  compare_without_coercion(other)
321
321
  elsif other.is_a?(Time)
322
- 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
323
328
  else
324
329
  to_datetime <=> other
325
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
@@ -151,37 +151,51 @@ module ActiveSupport
151
151
 
152
152
  def generate_method_missing(owner, target, allow_nil: nil)
153
153
  target = target.to_s
154
- target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target)
154
+ target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target) || target == "__target"
155
155
 
156
- owner.module_eval <<-RUBY, __FILE__, __LINE__ + 1
157
- def respond_to_missing?(name, include_private = false)
158
- # It may look like an oversight, but we deliberately do not pass
159
- # +include_private+, because they do not get delegated.
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.
160
161
 
161
- return false if name == :marshal_dump || name == :_dump
162
- #{target}.respond_to?(name) || super
163
- end
162
+ return false if name == :marshal_dump || name == :_dump
163
+ #{target}.respond_to?(name) || super
164
+ end
164
165
 
165
- def method_missing(method, ...)
166
- if #{target}.respond_to?(method)
167
- #{target}.public_send(method, ...)
168
- else
169
- begin
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
170
173
  super
171
- rescue NoMethodError
172
- if #{target}.nil?
173
- if #{allow_nil == true}
174
- nil
175
- else
176
- raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')
177
- end
178
- else
179
- raise
180
- end
181
174
  end
182
175
  end
183
- end
184
- RUBY
176
+ RUBY
177
+ 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.
182
+
183
+ return false if name == :marshal_dump || name == :_dump
184
+ #{target}.respond_to?(name) || super
185
+ end
186
+
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
196
+ end
197
+ RUBY
198
+ end
185
199
  end
186
200
  end
187
201
  end
@@ -2,28 +2,6 @@
2
2
 
3
3
  module ActiveSupport
4
4
  class Deprecation
5
- # DeprecatedConstantAccessor transforms a constant into a deprecated one by
6
- # hooking +const_missing+.
7
- #
8
- # It takes the names of an old (deprecated) constant and of a new constant
9
- # (both in string form) and a deprecator.
10
- #
11
- # The deprecated constant now returns the same object as the new one rather
12
- # than a proxy object, so it can be used transparently in +rescue+ blocks
13
- # etc.
14
- #
15
- # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto)
16
- #
17
- # # (In a later update, the original implementation of `PLANETS` has been removed.)
18
- #
19
- # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
20
- # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
21
- # deprecate_constant 'PLANETS', 'PLANETS_POST_2006', deprecator: ActiveSupport::Deprecation.new
22
- #
23
- # PLANETS.map { |planet| planet.capitalize }
24
- # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
25
- # (Backtrace information…)
26
- # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
27
5
  module DeprecatedConstantAccessor
28
6
  def self.included(base)
29
7
  require "active_support/inflector/methods"
@@ -39,9 +17,54 @@ module ActiveSupport
39
17
  super
40
18
  end
41
19
 
42
- def deprecate_constant(const_name, new_constant, deprecator:, message: nil)
20
+ # Provides a way to rename constants with a deprecation cycle in which
21
+ # both the old and new names work, but using the old one prints a
22
+ # deprecation message.
23
+ #
24
+ # In order to rename <tt>A::B</tt> to <tt>C::D</tt>, you need to delete the
25
+ # definition of <tt>A::B</tt> and declare the deprecation in +A+:
26
+ #
27
+ # require "active_support/deprecation"
28
+ #
29
+ # module A
30
+ # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
31
+ #
32
+ # deprecate_constant "B", "C::D", deprecator: ActiveSupport::Deprecation.new
33
+ # end
34
+ #
35
+ # The first argument is a constant name (no colons). It is the name of
36
+ # the constant you want to deprecate in the enclosing class or module.
37
+ #
38
+ # The second argument is the constant path of the replacement. That
39
+ # has to be a full path even if the replacement is defined in the same
40
+ # namespace as the deprecated one was.
41
+ #
42
+ # In both cases, strings and symbols are supported.
43
+ #
44
+ # The +deprecator+ keyword argument is the object that will print the
45
+ # deprecation message, an instance of ActiveSupport::Deprecation.
46
+ #
47
+ # With that in place, references to <tt>A::B</tt> still work, they
48
+ # evaluate to <tt>C::D</tt> now, and trigger a deprecation warning:
49
+ #
50
+ # DEPRECATION WARNING: A::B is deprecated! Use C::D instead.
51
+ # (called from ...)
52
+ #
53
+ # The message can be customized with the optional +message+ keyword
54
+ # argument.
55
+ #
56
+ # For this to work, a +const_missing+ hook is installed. When client
57
+ # code references the deprecated constant, the callback prints the
58
+ # message and constantizes the replacement.
59
+ #
60
+ # Caveat: If the deprecated constant name is reachable in a different
61
+ # namespace and Ruby constant lookup finds it, the hook won't be
62
+ # called and the deprecation won't work as intended. This may happen,
63
+ # for example, if an ancestor of the enclosing namespace has a
64
+ # constant with the same name. This is an unsupported edge case.
65
+ def deprecate_constant(old_constant_name, new_constant_path, deprecator:, message: nil)
43
66
  class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
44
- class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
67
+ class_variable_get(:@@_deprecated_constants)[old_constant_name.to_s] = { new: new_constant_path, message: message, deprecator: deprecator }
45
68
  end
46
69
  end
47
70
  base.singleton_class.prepend extension
@@ -10,7 +10,7 @@ module ActiveSupport
10
10
  MAJOR = 7
11
11
  MINOR = 2
12
12
  TINY = 0
13
- PRE = "beta2"
13
+ PRE = "rc1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -7,14 +7,6 @@ module ActiveSupport
7
7
  module LoggerThreadSafeLevel # :nodoc:
8
8
  extend ActiveSupport::Concern
9
9
 
10
- Logger::Severity.constants.each do |severity|
11
- class_eval(<<-EOT, __FILE__, __LINE__ + 1)
12
- def #{severity.downcase}? # def debug?
13
- Logger::#{severity} >= level # DEBUG >= level
14
- end # end
15
- EOT
16
- end
17
-
18
10
  def local_level
19
11
  IsolatedExecutionState[local_level_key]
20
12
  end
@@ -30,6 +30,18 @@ module ActiveSupport
30
30
  # self.current_user = User.find(id)
31
31
  # end
32
32
  #
33
+ # === Signing is not encryption
34
+ #
35
+ # The signed messages are not encrypted. The payload is merely encoded (Base64 by default) and can be decoded by
36
+ # anyone. The signature is just assuring that the message wasn't tampered with. For example:
37
+ #
38
+ # message = Rails.application.message_verifier('my_purpose').generate('never put secrets here')
39
+ # # => "BAhJIhtuZXZlciBwdXQgc2VjcmV0cyBoZXJlBjoGRVQ=--a0c1c0827919da5e949e989c971249355735e140"
40
+ # Base64.decode64(message.split("--").first) # no key needed
41
+ # # => 'never put secrets here'
42
+ #
43
+ # If you also need to encrypt the contents, you must use ActiveSupport::MessageEncryptor instead.
44
+ #
33
45
  # === Confine messages to a specific purpose
34
46
  #
35
47
  # It's not recommended to use the same verifier for different purposes in your application.
@@ -45,7 +45,7 @@ module ActiveSupport
45
45
 
46
46
  private
47
47
  def parse_message_for_trace
48
- if source_location_eval?
48
+ if __getobj__.to_s.start_with?("(eval")
49
49
  # If the exception is coming from a call to eval, we need to keep
50
50
  # the path of the file in which eval was called to ensure we can
51
51
  # return the right source fragment to show the location of the
@@ -56,15 +56,5 @@ module ActiveSupport
56
56
  __getobj__.to_s.split("\n")
57
57
  end
58
58
  end
59
-
60
- if SyntaxError.method_defined?(:path) # Ruby 3.3+
61
- def source_location_eval?
62
- __getobj__.path.start_with?("(eval")
63
- end
64
- else # 3.2 and older versions of Ruby
65
- def source_location_eval?
66
- __getobj__.to_s.start_with?("(eval")
67
- end
68
- end
69
59
  end
70
60
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "active_support/core_ext/module/delegation"
4
4
  require "active_support/core_ext/object/blank"
5
- require "logger"
6
5
  require "active_support/logger"
7
6
 
8
7
  module ActiveSupport
@@ -163,10 +163,10 @@ module ActiveSupport
163
163
  now = date_or_time.midnight.to_time
164
164
  elsif date_or_time.is_a?(String)
165
165
  now = Time.zone.parse(date_or_time)
166
- elsif with_usec
167
- now = date_or_time.to_time
168
166
  else
169
- now = date_or_time.to_time.change(usec: 0)
167
+ now = date_or_time
168
+ now = now.to_time unless now.is_a?(Time)
169
+ now = now.change(usec: 0) unless with_usec
170
170
  end
171
171
 
172
172
  # +now+ must be in local system timezone, because +Time.at(now)+
@@ -332,7 +332,7 @@ module ActiveSupport
332
332
  #
333
333
  def -(other)
334
334
  if other.acts_like?(:time)
335
- to_time - other.to_time
335
+ getutc - other.getutc
336
336
  elsif duration_of_variable_length?(other)
337
337
  method_missing(:-, other)
338
338
  else
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activesupport
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0.beta2
4
+ version: 7.2.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-04 00:00:00.000000000 Z
11
+ date: 2024-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -140,6 +140,34 @@ dependencies:
140
140
  - - ">="
141
141
  - !ruby/object:Gem::Version
142
142
  version: '0'
143
+ - !ruby/object:Gem::Dependency
144
+ name: logger
145
+ requirement: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: 1.4.2
150
+ type: :runtime
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: 1.4.2
157
+ - !ruby/object:Gem::Dependency
158
+ name: securerandom
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0.3'
164
+ type: :runtime
165
+ prerelease: false
166
+ version_requirements: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0.3'
143
171
  description: A toolkit of support libraries and Ruby core extensions extracted from
144
172
  the Rails framework. Rich support for multibyte strings, internationalization, time
145
173
  zones, and testing.
@@ -438,10 +466,10 @@ licenses:
438
466
  - MIT
439
467
  metadata:
440
468
  bug_tracker_uri: https://github.com/rails/rails/issues
441
- changelog_uri: https://github.com/rails/rails/blob/v7.2.0.beta2/activesupport/CHANGELOG.md
442
- documentation_uri: https://api.rubyonrails.org/v7.2.0.beta2/
469
+ changelog_uri: https://github.com/rails/rails/blob/v7.2.0.rc1/activesupport/CHANGELOG.md
470
+ documentation_uri: https://api.rubyonrails.org/v7.2.0.rc1/
443
471
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
444
- source_code_uri: https://github.com/rails/rails/tree/v7.2.0.beta2/activesupport
472
+ source_code_uri: https://github.com/rails/rails/tree/v7.2.0.rc1/activesupport
445
473
  rubygems_mfa_required: 'true'
446
474
  post_install_message:
447
475
  rdoc_options:
@@ -456,11 +484,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
456
484
  version: 3.1.0
457
485
  required_rubygems_version: !ruby/object:Gem::Requirement
458
486
  requirements:
459
- - - ">"
487
+ - - ">="
460
488
  - !ruby/object:Gem::Version
461
- version: 1.3.1
489
+ version: '0'
462
490
  requirements: []
463
- rubygems_version: 3.3.27
491
+ rubygems_version: 3.5.11
464
492
  signing_key:
465
493
  specification_version: 4
466
494
  summary: A toolkit of support libraries and Ruby core extensions extracted from the