Remove all code to work with Ruby < 3.1

This commit is contained in:
Rafael Mendonça França 2024-01-03 17:43:25 +00:00
parent dc581c0cc7
commit 9d18dc8505
No known key found for this signature in database
GPG Key ID: FC23B6D0F1EEE948
22 changed files with 143 additions and 399 deletions

@ -193,6 +193,6 @@ gem "wdm", ">= 0.1.0", platforms: [:windows]
# The error_highlight gem only works on CRuby 3.1 or later.
# Also, Rails depends on a new API available since error_highlight 0.4.0.
# (Note that Ruby 3.1 bundles error_highlight 0.3.0.)
if RUBY_VERSION >= "3.1" && RUBY_VERSION < "3.2"
if RUBY_VERSION < "3.2"
gem "error_highlight", ">= 0.4.0", platforms: [:ruby]
end

@ -152,18 +152,15 @@ def setup
assert_match %r|url=artifact://.+?tmp/screenshots/1_x\.png|, display_image_actual
end
# minitest doesn't support metadata in the version locked on Ruby 2.7
if RUBY_VERSION > "3.0"
test "take_failed_screenshot persists the image path in the test metadata" do
Rails.stub :root, Pathname.getwd do
@new_test.stub :passed?, false do
Capybara::Session.stub :instance_created?, true do
@new_test.stub :save_image, nil do
@new_test.stub :show, -> (_) { } do
@new_test.take_failed_screenshot
test "take_failed_screenshot persists the image path in the test metadata" do
Rails.stub :root, Pathname.getwd do
@new_test.stub :passed?, false do
Capybara::Session.stub :instance_created?, true do
@new_test.stub :save_image, nil do
@new_test.stub :show, -> (_) { } do
@new_test.take_failed_screenshot
assert_equal @new_test.send(:relative_image_path), @new_test.metadata[:failure_screenshot_path]
end
assert_equal @new_test.send(:relative_image_path), @new_test.metadata[:failure_screenshot_path]
end
end
end

@ -40,9 +40,43 @@ def assert_response_code_range(range, predicate)
assert_equal("Content", response.parsed_body.at_xpath("/html/body/div").text)
end
if RUBY_VERSION >= "3.1"
require_relative "./test_response_test/pattern_matching_test_cases"
test "JSON response Hash pattern matching" do
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '{ "foo": "fighters" }')
include PatternMatchingTestCases
# rubocop:disable Lint/Syntax
assert_pattern { response.parsed_body => { foo: /fighter/ } }
# rubocop:enable Lint/Syntax
end
test "JSON response Array pattern matching" do
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '[{ "foo": "fighters" }, { "nir": "vana" }]')
# rubocop:disable Lint/Syntax
assert_pattern { response.parsed_body => [{ foo: /fighter/ }, { nir: /vana/ }] }
# rubocop:enable Lint/Syntax
end
test "HTML response pattern matching" do
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "text/html" }, <<~HTML)
<html>
<head></head>
<body>
<main><h1>Some main content</h1></main>
</body>
</html>
HTML
html = response.parsed_body
# rubocop:disable Lint/Syntax
html.at("main") => {name:, content:}
# rubocop:enable Lint/Syntax
assert_equal "main", name
assert_equal "Some main content", content
# rubocop:disable Lint/Syntax
assert_pattern { html.at("main") => { content: "Some main content" } }
assert_pattern { html.at("main") => { content: /content/ } }
assert_pattern { html.at("main") => { children: [{ name: "h1", content: /content/ }] } }
# rubocop:enable Lint/Syntax
end
end

@ -1,47 +0,0 @@
# frozen_string_literal: true
module TestResponseTest::PatternMatchingTestCases
extend ActiveSupport::Concern
included do
test "JSON response Hash pattern matching" do
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '{ "foo": "fighters" }')
# rubocop:disable Lint/Syntax
assert_pattern { response.parsed_body => { foo: /fighter/ } }
# rubocop:enable Lint/Syntax
end
test "JSON response Array pattern matching" do
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '[{ "foo": "fighters" }, { "nir": "vana" }]')
# rubocop:disable Lint/Syntax
assert_pattern { response.parsed_body => [{ foo: /fighter/ }, { nir: /vana/ }] }
# rubocop:enable Lint/Syntax
end
test "HTML response pattern matching" do
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "text/html" }, <<~HTML)
<html>
<head></head>
<body>
<main><h1>Some main content</h1></main>
</body>
</html>
HTML
html = response.parsed_body
# rubocop:disable Lint/Syntax
html.at("main") => {name:, content:}
# rubocop:enable Lint/Syntax
assert_equal "main", name
assert_equal "Some main content", content
# rubocop:disable Lint/Syntax
assert_pattern { html.at("main") => { content: "Some main content" } }
assert_pattern { html.at("main") => { content: /content/ } }
assert_pattern { html.at("main") => { children: [{ name: "h1", content: /content/ }] } }
# rubocop:enable Lint/Syntax
end
end
end

@ -194,6 +194,20 @@ class ActionText::ContentTest < ActiveSupport::TestCase
assert_equal expected_html.strip, replaced_fragment.to_html
end
test "delegates pattern matching to Nokogiri" do
content = ActionText::Content.new <<~HTML
<h1 id="hello-world">Hello, world</h1>
<div>The body</div>
HTML
content => [h1, div]
assert_pattern { h1 => { name: "h1", content: "Hello, world", attributes: [{ name: "id", value: "hello-world" }] } }
refute_pattern { h1 => { name: "h1", content: "Goodbye, world" } }
assert_pattern { div => { content: "The body" } }
end
private
def content_from_html(html)
ActionText::Content.new(html).tap do |content|
@ -210,7 +224,3 @@ def with_attachment_tag_name(tag_name)
ActionText::Attachment.tag_name = previous_tag_name
end
end
if RUBY_VERSION >= "3.1"
require_relative "./content_test/pattern_matching_test_cases"
end

@ -1,19 +0,0 @@
# frozen_string_literal: true
class ActionText::PatternMatchingTestCases < ActiveSupport::TestCase
test "delegates pattern matching to Nokogiri" do
content = ActionText::Content.new <<~HTML
<h1 id="hello-world">Hello, world</h1>
<div>The body</div>
HTML
# rubocop:disable Lint/Syntax
content => [h1, div]
assert_pattern { h1 => { name: "h1", content: "Hello, world", attributes: [{ name: "id", value: "hello-world" }] } }
refute_pattern { h1 => { name: "h1", content: "Goodbye, world" } }
assert_pattern { div => { content: "The body" } }
# rubocop:enable Lint/Syntax
end
end

@ -574,19 +574,6 @@ def current_page?(options = nil, check_parameters: false, **options_as_kwargs)
url_string == request_uri
end
if RUBY_VERSION.start_with?("2.7")
using Module.new {
refine UrlHelper do
alias :_current_page? :current_page?
end
}
def current_page?(*args) # :nodoc:
options = args.pop
options.is_a?(Hash) ? _current_page?(*args, **options) : _current_page?(*args, options)
end
end
# Creates an SMS anchor link tag to the specified +phone_number+. When the
# link is clicked, the default SMS messaging app is opened ready to send a
# message to the linked phone number. If the +body+ option is specified,

@ -453,8 +453,38 @@ class AHelperWithInitializeTest < ActionView::TestCase
assert @called_initialize
end
end
end
if RUBY_VERSION >= "3.1"
require_relative "./test_case_test/pattern_matching_test_cases"
class PatternMatchingTestCases < ActionView::TestCase
test "document_root_element integrates with pattern matching" do
developer = DeveloperStruct.new("Eloy")
render "developers/developer_with_h1", developer: developer
# rubocop:disable Lint/Syntax
assert_pattern { document_root_element.at("h1") => { content: "Eloy", attributes: [{ name: "id", value: "name" }] } }
refute_pattern { document_root_element.at("h1") => { content: "Not Eloy" } }
end
test "rendered.html integrates with pattern matching" do
developer = DeveloperStruct.new("Eloy")
render "developers/developer", developer: developer
# rubocop:disable Lint/Syntax
assert_pattern { rendered.html => { content: "Eloy" } }
refute_pattern { rendered.html => { content: "Not Eloy" } }
# rubocop:enable Lint/Syntax
end
test "rendered.json integrates with pattern matching" do
developer = DeveloperStruct.new("Eloy")
render formats: :json, partial: "developers/developer", locals: { developer: developer }
# rubocop:disable Lint/Syntax
assert_pattern { rendered.json => { name: "Eloy" } }
refute_pattern { rendered.json => { name: "Not Eloy" } }
# rubocop:enable Lint/Syntax
end
end
end

@ -1,36 +0,0 @@
# frozen_string_literal: true
class ActionView::PatternMatchingTestCases < ActionView::TestCase
test "document_root_element integrates with pattern matching" do
developer = DeveloperStruct.new("Eloy")
render "developers/developer_with_h1", developer: developer
# rubocop:disable Lint/Syntax
assert_pattern { document_root_element.at("h1") => { content: "Eloy", attributes: [{ name: "id", value: "name" }] } }
refute_pattern { document_root_element.at("h1") => { content: "Not Eloy" } }
# rubocop:enable Lint/Syntax
end
test "rendered.html integrates with pattern matching" do
developer = DeveloperStruct.new("Eloy")
render "developers/developer", developer: developer
# rubocop:disable Lint/Syntax
assert_pattern { rendered.html => { content: "Eloy" } }
refute_pattern { rendered.html => { content: "Not Eloy" } }
# rubocop:enable Lint/Syntax
end
test "rendered.json integrates with pattern matching" do
developer = DeveloperStruct.new("Eloy")
render formats: :json, partial: "developers/developer", locals: { developer: developer }
# rubocop:disable Lint/Syntax
assert_pattern { rendered.json => { name: "Eloy" } }
refute_pattern { rendered.json => { name: "Not Eloy" } }
# rubocop:enable Lint/Syntax
end
end

@ -99,17 +99,10 @@ def test_invert_change_table
end
end
if RUBY_VERSION >= "2.8"
assert_equal [
[:rename_column, [:fruits, :cultivar, :kind]],
[:remove_column, [:fruits, :name, :string], nil],
], @recorder.commands
else
assert_equal [
[:rename_column, [:fruits, :cultivar, :kind]],
[:remove_column, [:fruits, :name, :string, {}], nil],
], @recorder.commands
end
assert_equal [
[:rename_column, [:fruits, :cultivar, :kind]],
[:remove_column, [:fruits, :name, :string], nil],
], @recorder.commands
assert_raises(ActiveRecord::IrreversibleMigration) do
@recorder.revert do

@ -15,11 +15,10 @@ module DelegationTests
:map, :none?, :one?, :partition, :reject, :reverse, :rotate,
:sample, :second, :sort, :sort_by, :slice, :third, :index, :rindex,
:to_ary, :to_set, :to_xml, :to_yaml, :join,
:in_groups, :in_groups_of, :to_sentence, :to_formatted_s, :to_fs, :as_json
:in_groups, :in_groups_of, :to_sentence, :to_formatted_s, :to_fs, :as_json,
:intersect?
]
ARRAY_DELEGATES << :intersect? if RUBY_VERSION >= "3.1.0"
ARRAY_DELEGATES.each do |method|
define_method "test_delegates_#{method}_to_Array" do
assert_respond_to target, method

@ -1,43 +1,23 @@
# frozen_string_literal: true
require "active_support/ruby_features"
require "active_support/descendants_tracker"
class Class
if ActiveSupport::RubyFeatures::CLASS_SUBCLASSES
# Returns an array with all classes that are < than its receiver.
#
# class C; end
# C.descendants # => []
#
# class B < C; end
# C.descendants # => [B]
#
# class A < B; end
# C.descendants # => [B, A]
#
# class D < C; end
# C.descendants # => [B, A, D]
def descendants
subclasses.concat(subclasses.flat_map(&:descendants))
end
else
def descendants
ObjectSpace.each_object(singleton_class).reject do |k|
k.singleton_class? || k == self
end
end
# Returns an array with the direct children of +self+.
#
# class Foo; end
# class Bar < Foo; end
# class Baz < Bar; end
#
# Foo.subclasses # => [Bar]
def subclasses
descendants.select { |descendant| descendant.superclass == self }
end
# Returns an array with all classes that are < than its receiver.
#
# class C; end
# C.descendants # => []
#
# class B < C; end
# C.descendants # => [B]
#
# class A < B; end
# C.descendants # => [B, A]
#
# class D < C; end
# C.descendants # => [B, A, D]
def descendants
subclasses.concat(subclasses.flat_map(&:descendants))
end
prepend ActiveSupport::DescendantsTracker::ReloadedClassesFiltering

@ -17,24 +17,17 @@ def instance_values
end
end
if Symbol.method_defined?(:name) # RUBY_VERSION >= "3.0"
# Returns an array of instance variable names as strings including "@".
#
# class C
# def initialize(x, y)
# @x, @y = x, y
# end
# end
#
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
def instance_variable_names
instance_variables.map(&:name)
end
else
def instance_variable_names
variables = instance_variables
variables.map! { |s| s.to_s.freeze }
variables
end
# Returns an array of instance variable names as strings including "@".
#
# class C
# def initialize(x, y)
# @x, @y = x, y
# end
# end
#
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
def instance_variable_names
instance_variables.map(&:name)
end
end
end

@ -114,15 +114,6 @@ def floor(precision = 0)
end
end
# Restricted Ruby version due to a bug in `Time#ceil`
# See https://bugs.ruby-lang.org/issues/17025 for more details
if RUBY_VERSION <= "2.8"
remove_possible_method :ceil
def ceil(precision = 0)
change(nsec: 0) + subsec.ceil(precision)
end
end
# Returns a new Time where one or more of the elements have been changed according
# to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
# <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only

@ -27,18 +27,6 @@ module ActiveSupport
#
# MyLib.eager_load!
module Autoload
def self.extended(base) # :nodoc:
if RUBY_VERSION < "3"
base.class_eval do
@_autoloads = nil
@_under_path = nil
@_at_path = nil
@_eager_autoload = false
@_eagerloaded_constants = nil
end
end
end
def autoload(const_name, path = @_at_path)
unless path
full = [name, @_under_path, const_name.to_s].compact.join("::")

@ -1,7 +1,6 @@
# frozen_string_literal: true
require "weakref"
require "active_support/ruby_features"
module ActiveSupport
# = Active Support Descendants Tracker
@ -95,96 +94,19 @@ def reject!(classes) # :nodoc:
end
end
if RubyFeatures::CLASS_SUBCLASSES
class << self
def subclasses(klass)
klass.subclasses
end
def descendants(klass)
klass.descendants
end
class << self
def subclasses(klass)
klass.subclasses
end
def descendants
subclasses = DescendantsTracker.reject!(self.subclasses)
subclasses.concat(subclasses.flat_map(&:descendants))
def descendants(klass)
klass.descendants
end
else
# DescendantsArray is an array that contains weak references to classes.
# Note: DescendantsArray is redundant with WeakSet, however WeakSet when used
# on Ruby 2.7 or 3.0 can trigger a Ruby crash: https://bugs.ruby-lang.org/issues/18928
class DescendantsArray # :nodoc:
include Enumerable
end
def initialize
@refs = []
end
def <<(klass)
@refs << WeakRef.new(klass)
end
def each
@refs.reject! do |ref|
yield ref.__getobj__
false
rescue WeakRef::RefError
true
end
self
end
def refs_size
@refs.size
end
def cleanup!
@refs.delete_if { |ref| !ref.weakref_alive? }
end
def reject!
@refs.reject! do |ref|
yield ref.__getobj__
rescue WeakRef::RefError
true
end
end
end
@direct_descendants = {}
class << self
def subclasses(klass)
descendants = @direct_descendants[klass]
descendants ? DescendantsTracker.reject!(descendants.to_a) : []
end
def descendants(klass)
subclasses = self.subclasses(klass)
subclasses.concat(subclasses.flat_map { |k| descendants(k) })
end
# This is the only method that is not thread safe, but is only ever called
# during the eager loading phase.
def store_inherited(klass, descendant) # :nodoc:
(@direct_descendants[klass] ||= DescendantsArray.new) << descendant
end
end
def subclasses
DescendantsTracker.subclasses(self)
end
def descendants
DescendantsTracker.descendants(self)
end
private
def inherited(base) # :nodoc:
DescendantsTracker.store_inherited(self, base)
super
end
def descendants
subclasses = DescendantsTracker.reject!(self.subclasses)
subclasses.concat(subclasses.flat_map(&:descendants))
end
end
end

@ -2,7 +2,7 @@
module ActiveSupport
module ForkTracker # :nodoc:
module ModernCoreExt
module CoreExt
def _fork
pid = super
if pid == 0
@ -12,27 +12,6 @@ def _fork
end
end
module CoreExt
def fork(...)
if block_given?
super do
ForkTracker.check!
yield
end
else
unless pid = super
ForkTracker.check!
end
pid
end
end
end
module CoreExtPrivate
include CoreExt
private :fork
end
@pid = Process.pid
@callbacks = []
@ -54,14 +33,7 @@ def check!
end
def hook!
if Process.respond_to?(:_fork) # Ruby 3.1+
::Process.singleton_class.prepend(ModernCoreExt)
elsif Process.respond_to?(:fork)
::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
::Kernel.prepend(CoreExtPrivate)
::Kernel.singleton_class.prepend(CoreExt)
::Process.singleton_class.prepend(CoreExt)
end
::Process.singleton_class.prepend(CoreExt)
end
def after_fork(&block)

@ -1,7 +0,0 @@
# frozen_string_literal: true
module ActiveSupport
module RubyFeatures # :nodoc:
CLASS_SUBCLASSES = Class.method_defined?(:subclasses) # RUBY_VERSION >= "3.1"
end
end

@ -452,14 +452,8 @@ def test_indifferent_transform_keys
assert_equal(["A", "bbb"], hash.keys) # asserting that order of keys is unchanged
assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash
if RUBY_VERSION < "3"
assert_raise ArgumentError do
hash.transform_keys(nil)
end
else
assert_raise TypeError do
hash.transform_keys(nil)
end
assert_raise TypeError do
hash.transform_keys(nil)
end
end
@ -512,14 +506,8 @@ def test_indifferent_transform_keys_bang
assert_equal(["A", "bbb"], hash.keys) # asserting that order of keys is unchanged
assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash
if RUBY_VERSION < "3"
assert_raise ArgumentError do
hash.transform_keys(nil)
end
else
assert_raise TypeError do
hash.transform_keys(nil)
end
assert_raise TypeError do
hash.transform_keys(nil)
end
end

@ -579,24 +579,7 @@ def dockerfile_build_packages
if using_node?
packages << "node-gyp" # pkg-config already listed above
# module build process depends on Python, and debian changed
# how python is installed with the bullseye release. Below
# is based on debian release included with the Ruby images on
# Dockerhub.
case Gem.ruby_version.to_s
when /^2\.7/
bullseye = Gem.ruby_version >= Gem::Version.new("2.7.4")
when /^3\.0/
bullseye = Gem.ruby_version >= Gem::Version.new("3.0.2")
else
bullseye = true
end
if bullseye
packages << "python-is-python3"
else
packages << "python"
end
packages << "python-is-python3"
end
packages.compact.sort

@ -60,7 +60,7 @@ group :development do
<%- end -%>
# Speed up commands on slow machines / big apps [https://github.com/rails/spring]
# gem "spring"
<%- if RUBY_VERSION >= "3.1" && RUBY_VERSION < "3.2" -%>
<%- if RUBY_VERSION < "3.2" -%>
# Highlight the fine-grained location where an error occurred [https://github.com/ruby/error_highlight]
gem "error_highlight", ">= 0.4.0", platforms: [:ruby]
@ -72,8 +72,5 @@ group :test do
# Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
gem "capybara"
gem "selenium-webdriver"
<%- if RUBY_VERSION < "3.0" -%>
gem "webdrivers"
<%- end -%>
end
<%- end -%>

@ -1184,17 +1184,6 @@ def test_dockerfile
end
end
def test_old_rubies_do_not_use_bullseye_python
Gem.stub(:ruby_version, Gem::Version.new("2.7.0")) do
run_generator [destination_root, "--js=esbuild"]
end
assert_file "Dockerfile" do |content|
assert_match(/python/, content)
assert_no_match(/python-is-python3/, content)
end
end
def test_skip_docker
run_generator [destination_root, "--skip-docker"]