Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade the lowest Ruby version to 3.1 #1241

Merged
merged 10 commits into from
Feb 4, 2025
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu, macos, windows ]
ruby: [ 3.0.6, 3.1.4, 3.2.2, 3.3.0, 3.4.1 ]
ruby: [ 3.1.6, 3.2.6, 3.3.7, 3.4.1 ]
rubyopt: [""]
include:
- os: ubuntu
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ ruby/spec is known to be tested in these implementations for every commit:
* [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)

ruby/spec describes the behavior of Ruby 3.0 and more recent Ruby versions.
More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.0.x, 3.1.x, 3.2.x, etc), and those are tested in CI.
ruby/spec describes the behavior of Ruby 3.1 and more recent Ruby versions.
More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.1.x, 3.2.x, etc), and those are tested in CI.

### Synchronization with Ruby Implementations

Expand Down Expand Up @@ -62,6 +62,7 @@ For older specs try these commits:
* Ruby 2.5.9 - [Suite](https://github.com/ruby/spec/commit/c503335d3d9f6ec6ef24de60a0716c34af69b64f) using [MSpec](https://github.com/ruby/mspec/commit/0091e8a62e954717cd54641f935eaf1403692041)
* Ruby 2.6.10 - [Suite](https://github.com/ruby/spec/commit/aaf998fb8c92c4e63ad423a2e7ca6e6921818c6e) using [MSpec](https://github.com/ruby/mspec/commit/5e36c684e9e2b92b1187589bba1df22c640a8661)
* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
* Ruby 3.0.7 - [Suite](https://github.com/ruby/spec/commit/affef93d9940f615e4836f64b011da211f570913) using [MSpec](https://github.com/ruby/mspec/commit/0aabb3e548eb5ea6cad0125f8f46cee34542b6b7)

### Running the specs

Expand Down
92 changes: 45 additions & 47 deletions core/array/intersect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,63 @@
require_relative 'fixtures/classes'

describe 'Array#intersect?' do
ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/15198
describe 'when at least one element in two Arrays is the same' do
it 'returns true' do
[1, 2].intersect?([2, 3, 4]).should == true
[2, 3, 4].intersect?([1, 2]).should == true
end
describe 'when at least one element in two Arrays is the same' do
it 'returns true' do
[1, 2].intersect?([2, 3, 4]).should == true
[2, 3, 4].intersect?([1, 2]).should == true
end
end

describe 'when there are no elements in common between two Arrays' do
it 'returns false' do
[0, 1, 2].intersect?([3, 4]).should == false
[3, 4].intersect?([0, 1, 2]).should == false
[3, 4].intersect?([]).should == false
[].intersect?([0, 1, 2]).should == false
end
describe 'when there are no elements in common between two Arrays' do
it 'returns false' do
[0, 1, 2].intersect?([3, 4]).should == false
[3, 4].intersect?([0, 1, 2]).should == false
[3, 4].intersect?([]).should == false
[].intersect?([0, 1, 2]).should == false
end
end

it "tries to convert the passed argument to an Array using #to_ary" do
obj = mock('[1,2,3]')
obj.should_receive(:to_ary).and_return([1, 2, 3])
it "tries to convert the passed argument to an Array using #to_ary" do
obj = mock('[1,2,3]')
obj.should_receive(:to_ary).and_return([1, 2, 3])

[1, 2].intersect?(obj).should == true
end
[1, 2].intersect?(obj).should == true
end

it "determines equivalence between elements in the sense of eql?" do
obj1 = mock('1')
obj2 = mock('2')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(true)
obj2.stub!(:eql?).and_return(true)
it "determines equivalence between elements in the sense of eql?" do
obj1 = mock('1')
obj2 = mock('2')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(true)
obj2.stub!(:eql?).and_return(true)

[obj1].intersect?([obj2]).should == true
[obj1].intersect?([obj2]).should == true

obj1 = mock('3')
obj2 = mock('4')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(false)
obj2.stub!(:eql?).and_return(false)
obj1 = mock('3')
obj2 = mock('4')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.stub!(:eql?).and_return(false)
obj2.stub!(:eql?).and_return(false)

[obj1].intersect?([obj2]).should == false
end
[obj1].intersect?([obj2]).should == false
end

it "does not call to_ary on array subclasses" do
[5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
end
it "does not call to_ary on array subclasses" do
[5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
end

it "properly handles an identical item even when its #eql? isn't reflexive" do
x = mock('x')
x.stub!(:hash).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
it "properly handles an identical item even when its #eql? isn't reflexive" do
x = mock('x')
x.stub!(:hash).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.

[x].intersect?([x]).should == true
end
[x].intersect?([x]).should == true
end

it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end
it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end
end
19 changes: 4 additions & 15 deletions core/basicobject/instance_eval_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,22 +141,11 @@ class B; end
caller.get_constant_with_string(receiver).should == :singleton_class
end

ruby_version_is ""..."3.1" do
it "looks in the caller scope next" do
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
it "looks in the receiver class next" do
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new

caller.get_constant_with_string(receiver).should == :Caller
end
end

ruby_version_is "3.1" do
it "looks in the receiver class next" do
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new

caller.get_constant_with_string(receiver).should == :Receiver
end
caller.get_constant_with_string(receiver).should == :Receiver
end

it "looks in the caller class next" do
Expand Down
126 changes: 62 additions & 64 deletions core/class/subclasses_spec.rb
Original file line number Diff line number Diff line change
@@ -1,87 +1,85 @@
require_relative '../../spec_helper'
require_relative '../module/fixtures/classes'

ruby_version_is '3.1' do
describe "Class#subclasses" do
it "returns a list of classes directly inheriting from self" do
assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
end
describe "Class#subclasses" do
it "returns a list of classes directly inheriting from self" do
assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
end

it "does not return included modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)
it "does not return included modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)

assert_subclasses(parent, [child])
end

it "does not return included modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)
assert_subclasses(parent, [child])
end

assert_subclasses(parent, [child])
end
it "does not return included modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.include(mod)

it "does not return prepended modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.prepend(mod)
assert_subclasses(parent, [child])
end

assert_subclasses(parent, [child])
end
it "does not return prepended modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
parent.prepend(mod)

it "does not return prepended modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
child.prepend(mod)
assert_subclasses(parent, [child])
end

assert_subclasses(parent, [child])
end
it "does not return prepended modules from the child" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
child.prepend(mod)

it "does not return singleton classes" do
a = Class.new
assert_subclasses(parent, [child])
end

a_obj = a.new
def a_obj.force_singleton_class
42
end
it "does not return singleton classes" do
a = Class.new

a.subclasses.should_not include(a_obj.singleton_class)
a_obj = a.new
def a_obj.force_singleton_class
42
end

it "has 1 entry per module or class" do
ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
end
a.subclasses.should_not include(a_obj.singleton_class)
end

it "has 1 entry per module or class" do
ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
end

it "works when creating subclasses concurrently" do
t = 16
n = 1000
go = false
superclass = Class.new

threads = t.times.map do
Thread.new do
Thread.pass until go
n.times.map do
Class.new(superclass)
end
it "works when creating subclasses concurrently" do
t = 16
n = 1000
go = false
superclass = Class.new

threads = t.times.map do
Thread.new do
Thread.pass until go
n.times.map do
Class.new(superclass)
end
end
end

go = true
classes = threads.map(&:value)
go = true
classes = threads.map(&:value)

superclass.subclasses.size.should == t * n
superclass.subclasses.each { |c| c.should be_kind_of(Class) }
end
superclass.subclasses.size.should == t * n
superclass.subclasses.each { |c| c.should be_kind_of(Class) }
end

def assert_subclasses(mod,subclasses)
mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
end
def assert_subclasses(mod,subclasses)
mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
end
end
Loading