This commit is contained in:
Andrew Konchin 2025-03-26 19:56:40 +02:00 committed by Benoit Daloze
parent 53a930f157
commit bac22c985e
Notes: git 2025-03-27 10:09:42 +00:00
242 changed files with 4763 additions and 3269 deletions

View File

@ -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
@ -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

View File

@ -2,7 +2,6 @@ require_relative '../../spec_helper'
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
@ -62,5 +61,4 @@ describe 'Array#intersect?' do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end
end
end

View File

@ -141,23 +141,12 @@ describe "BasicObject#instance_eval" do
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
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
end
it "looks in the caller class next" do
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::ReceiverScope::Receiver.new

View File

@ -96,6 +96,8 @@ describe "BasicObject#singleton_method_added" do
end
}.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/)
end
ensure
BasicObjectSpecs.send(:remove_const, :NoSingletonMethodAdded)
end
it "raises NoMethodError for a singleton instance" do

View File

@ -59,6 +59,8 @@ describe "Class#dup" do
it "stores the new name if assigned to a constant" do
CoreClassSpecs::RecordCopy = CoreClassSpecs::Record.dup
CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy"
ensure
CoreClassSpecs.send(:remove_const, :RecordCopy)
end
it "raises TypeError if called on BasicObject" do

View File

@ -83,6 +83,8 @@ describe "Class.new" do
a = Class.new
MyClass::NestedClass = a
MyClass::NestedClass.name.should == "MyClass::NestedClass"
ensure
Object.send(:remove_const, :MyClass)
end
it "sets the new class' superclass to the given class" do

View File

@ -1,8 +1,7 @@
require_relative '../../spec_helper'
require_relative '../module/fixtures/classes'
ruby_version_is '3.1' do
describe "Class#subclasses" 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
@ -83,5 +82,4 @@ ruby_version_is '3.1' do
def assert_subclasses(mod,subclasses)
mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
end
end
end

View File

@ -0,0 +1,107 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#deconstruct" do
it "returns a hash of attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
end
it "requires one argument" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
-> {
d.deconstruct_keys
}.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
end
it "returns only specified keys" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
d.deconstruct_keys([:x] ).should == {x: 1}
d.deconstruct_keys([] ).should == {}
end
it "accepts string attribute names" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
end
it "accepts argument position number as well but returns them as keys" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2}
d.deconstruct_keys([0] ).should == {0 => 1}
d.deconstruct_keys([-1] ).should == {-1 => 2}
end
it "ignores incorrect position numbers" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([0, 3]).should == {0 => 1}
end
it "support mixing attribute names and argument position numbers" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1}
end
it "returns an empty hash when there are more keys than attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:x, :y, :x]).should == {}
end
it "returns at first not existing attribute name" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([:a, :x]).should == {}
d.deconstruct_keys([:x, :a]).should == {x: 1}
end
it "returns at first not existing argument position number" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys([3, 0]).should == {}
d.deconstruct_keys([0, 3]).should == {0 => 1}
end
it "accepts nil argument and return all the attributes" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
d.deconstruct_keys(nil).should == {x: 1, y: 2}
end
it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
-> {
d.deconstruct_keys([0, []])
}.should raise_error(TypeError, "no implicit conversion of Array into Integer")
end
it "raise TypeError if passed anything except nil or array" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
-> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
-> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
-> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
-> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
end
end
end

View File

@ -0,0 +1,10 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#deconstruct" do
it "returns an array of attribute values" do
DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"]
end
end
end

View File

@ -0,0 +1,65 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#eql?" do
it "returns true if the other is the same object" do
a = DataSpecs::Measure.new(42, "km")
a.should.eql?(a)
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "km")
a.should.eql?(b)
end
it "returns false if the other is a different object or has different fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "mi")
a.should_not.eql?(b)
end
it "returns false if other is of a different class" do
a = DataSpecs::Measure.new(42, "km")
klass = Data.define(*DataSpecs::Measure.members)
b = klass.new(42, "km")
a.should_not.eql?(b)
end
it "returns false if any corresponding elements are not equal with #eql?" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42.0, "mi")
a.should_not.eql?(b)
end
context "recursive structure" do
it "returns true the other is the same object" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
a.should.eql?(a)
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: 42, unit: b)
a.should.eql?(b)
end
it "returns false if any corresponding elements are not equal with #eql?" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: a, unit: "km")
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: b, unit: "mi")
a.should_not.eql?(b)
end
end
end
end

View File

@ -0,0 +1,65 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#==" do
it "returns true if the other is the same object" do
a = DataSpecs::Measure.new(42, "km")
a.should == a
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "km")
a.should == b
end
it "returns false if the other is a different object or has different fields" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "mi")
a.should_not == b
end
it "returns false if other is of a different class" do
a = DataSpecs::Measure.new(42, "km")
klass = Data.define(*DataSpecs::Measure.members)
b = klass.new(42, "km")
a.should_not == b
end
it "returns false if any corresponding elements are not equal with #==" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42.0, "mi")
a.should_not == b
end
context "recursive structure" do
it "returns true the other is the same object" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
a.should == a
end
it "returns true if the other has all the same fields" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: 42, unit: b)
a.should == b
end
it "returns false if any corresponding elements are not equal with #==" do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: a, unit: "km")
b = DataSpecs::Measure.allocate
b.send(:initialize, amount: b, unit: "mi")
a.should_not == b
end
end
end
end

View File

@ -1,5 +1,13 @@
module DataSpecs
guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
Measure = Data.define(:amount, :unit)
class MeasureWithOverriddenName < Measure
def self.name
"A"
end
end
class DataSubclass < Data; end
end
end

View File

@ -0,0 +1,27 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#hash" do
it "returns the same integer for objects with the same content" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "km")
a.hash.should == b.hash
a.hash.should be_an_instance_of(Integer)
end
it "returns different hashes for objects with different values" do
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(42, "ml")
a.hash.should_not == b.hash
a = DataSpecs::Measure.new(42, "km")
b = DataSpecs::Measure.new(13, "km")
a.hash.should_not == b.hash
end
it "returns different hashes for different classes" do
Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash
end
end
end

View File

@ -0,0 +1,8 @@
require_relative '../../spec_helper'
require_relative 'shared/inspect'
ruby_version_is "3.2" do
describe "Data#inspect" do
it_behaves_like :data_inspect, :inspect
end
end

View File

@ -0,0 +1,23 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.2" do
describe "Data#members" do
it "returns an array of attribute names" do
measure = DataSpecs::Measure.new(amount: 42, unit: 'km')
measure.members.should == [:amount, :unit]
end
end
describe "DataClass#members" do
it "returns an array of attribute names" do
DataSpecs::Measure.members.should == [:amount, :unit]
end
context "class inheriting Data" do
it "isn't available in a subclass" do
DataSpecs::DataSubclass.should_not.respond_to?(:members)
end
end
end
end

View File

@ -0,0 +1,54 @@
require_relative '../fixtures/classes'
describe :data_inspect, shared: true do
it "returns a string representation showing members and values" do
a = DataSpecs::Measure.new(42, "km")
a.send(@method).should == '#<data DataSpecs::Measure amount=42, unit="km">'
end
it "returns a string representation without the class name for anonymous structs" do
Data.define(:a).new("").send(@method).should == '#<data a="">'
end
it "returns a string representation without the class name for structs nested in anonymous classes" do
c = Class.new
c.class_eval <<~DOC
Foo = Data.define(:a)
DOC
c::Foo.new("").send(@method).should == '#<data a="">'
end
it "returns a string representation without the class name for structs nested in anonymous modules" do
m = Module.new
m.class_eval <<~DOC
Foo = Data.define(:a)
DOC
m::Foo.new("").send(@method).should == '#<data a="">'
end
it "does not call #name method" do
struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
struct.send(@method).should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
end
it "does not call #name method when struct is anonymous" do
klass = Class.new(DataSpecs::Measure) do
def self.name
"A"
end
end
struct = klass.new(42, "km")
struct.send(@method).should == '#<data amount=42, unit="km">'
end
context "recursive structure" do
it "returns string representation with recursive attribute replaced with ..." do
a = DataSpecs::Measure.allocate
a.send(:initialize, amount: 42, unit: a)
a.send(@method).should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
end
end
end

View File

@ -0,0 +1,8 @@
require_relative '../../spec_helper'
require_relative 'shared/inspect'
ruby_version_is "3.2" do
describe "Data#to_s" do
it_behaves_like :data_inspect, :to_s
end
end

View File

@ -177,7 +177,7 @@ ruby_version_is '3.3' do
dir.close
end
platform_is_not :windows do
guard -> { Dir.respond_to? :fchdir } do
it "does not raise an Errno::ENOENT if the original directory no longer exists" do
dir_name1 = tmp('testdir1')
dir_name2 = tmp('testdir2')

View File

@ -89,21 +89,6 @@ describe "Dir.glob" do
Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected
end
ruby_version_is ''...'3.1' do
it "recursively matches files and directories in nested dot subdirectory with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
nested/.
nested/.dotsubir
nested/.dotsubir/.
nested/.dotsubir/.dotfile
nested/.dotsubir/nondotfile
]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
end
ruby_version_is '3.1' do
it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
nested/.
@ -114,7 +99,6 @@ describe "Dir.glob" do
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
end
# This is a separate case to check **/ coming after a constant
# directory as well.
@ -260,8 +244,6 @@ describe "Dir.glob" do
Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
end
# < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
ruby_version_is '3.1' do
it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
expected = %w[
.
@ -288,7 +270,6 @@ describe "Dir.glob" do
Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end
end
it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do
expected = %w[

View File

@ -42,26 +42,11 @@ describe :dir_glob, shared: true do
result.sort.should == Dir.send(@method, '*').sort
end
ruby_version_is ""..."3.1" do
it "result is sorted with any non false value of sort:" do
result = Dir.send(@method, '*', sort: 0)
result.should == result.sort
result = Dir.send(@method, '*', sort: nil)
result.should == result.sort
result = Dir.send(@method, '*', sort: 'false')
result.should == result.sort
end
end
ruby_version_is "3.1" do
it "raises an ArgumentError if sort: is not true or false" do
-> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
end
end
it "matches non-dotfiles with '*'" do
expected = %w[
@ -151,17 +136,9 @@ describe :dir_glob, shared: true do
Dir.send(@method, 'special/test\{1\}/*').should == ['special/test{1}/file[1]']
end
ruby_version_is ''...'3.1' do
it "matches dotfiles with '.*'" do
Dir.send(@method, '.*').sort.should == %w|. .. .dotfile .dotsubdir|.sort
end
end
ruby_version_is '3.1' do
it "matches dotfiles except .. with '.*'" do
Dir.send(@method, '.*').sort.should == %w|. .dotfile .dotsubdir|.sort
end
end
it "matches non-dotfiles with '*<non-special characters>'" do
Dir.send(@method, '*file').sort.should == %w|nondotfile|.sort
@ -205,17 +182,9 @@ describe :dir_glob, shared: true do
Dir.send(@method, '**').sort.should == expected
end
ruby_version_is ''...'3.1' do
it "matches dotfiles in the current directory with '.**'" do
Dir.send(@method, '.**').sort.should == %w|. .. .dotsubdir .dotfile|.sort
end
end
ruby_version_is '3.1' do
it "matches dotfiles in the current directory except .. with '.**'" do
Dir.send(@method, '.**').sort.should == %w|. .dotsubdir .dotfile|.sort
end
end
it "recursively matches any nondot subdirectories with '**/'" do
expected = %w[
@ -245,21 +214,11 @@ describe :dir_glob, shared: true do
Dir.send(@method, '**/*ory', base: 'deeply').sort.should == expected
end
ruby_version_is ''...'3.1' do
it "recursively matches any subdirectories including ./ and ../ with '.**/'" do
Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
Dir.send(@method, '.**/').sort.should == %w|./ ../|.sort
end
end
end
ruby_version_is '3.1' do
it "recursively matches any subdirectories including ./ with '.**/'" do
Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
Dir.send(@method, '.**/').should == ['./']
end
end
end
it "matches a single character except leading '.' with '?'" do
Dir.send(@method, '?ubdir_one').sort.should == %w|subdir_one|.sort

View File

@ -1,11 +1,9 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is '3.1' do
describe "Enumerable#compact" do
describe "Enumerable#compact" do
it 'returns array without nil elements' do
arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true)
arr.compact.should == [1, 2, true]
end
end
end

View File

@ -56,11 +56,9 @@ describe "Enumerable#each_cons" do
multi.each_cons(2).to_a.should == [[[1, 2], [3, 4, 5]], [[3, 4, 5], [6, 7, 8, 9]]]
end
ruby_version_is "3.1" do
it "returns self when a block is given" do
@enum.each_cons(3){}.should == @enum
end
end
describe "when no block is given" do
it "returns an enumerator" do

View File

@ -57,11 +57,9 @@ describe "Enumerable#each_slice" do
e.to_a.should == @sliced
end
ruby_version_is "3.1" do
it "returns self when a block is given" do
@enum.each_slice(3){}.should == @enum
end
end
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMulti.new

View File

@ -32,8 +32,7 @@ describe "Enumerable#tally" do
end
end
ruby_version_is "3.1" do
describe "Enumerable#tally with a hash" do
describe "Enumerable#tally with a hash" do
before :each do
ScratchPad.record []
end
@ -89,5 +88,4 @@ ruby_version_is "3.1" do
enum = EnumerableSpecs::Numerous.new('foo')
-> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
end
end
end

View File

@ -1,8 +1,7 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is '3.1' do
describe "Enumerator::Lazy#compact" do
describe "Enumerator::Lazy#compact" do
it 'returns array without nil elements' do
arr = [1, nil, 3, false, 5].to_enum.lazy.compact
arr.should be_an_instance_of(Enumerator::Lazy)
@ -12,5 +11,4 @@ ruby_version_is '3.1' do
it "sets #size to nil" do
Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
end
end
end

View File

@ -9,16 +9,11 @@ describe "Enumerator::Lazy" do
it "defines lazy versions of a whitelist of Enumerator methods" do
lazy_methods = [
:chunk, :collect, :collect_concat, :drop, :drop_while, :enum_for,
:chunk, :chunk_while, :collect, :collect_concat, :compact, :drop, :drop_while, :enum_for,
:find_all, :flat_map, :force, :grep, :grep_v, :lazy, :map, :reject,
:select, :slice_after, :slice_before, :slice_when, :take, :take_while,
:to_enum, :zip
:to_enum, :uniq, :zip
]
lazy_methods += [:chunk_while, :uniq]
ruby_version_is '3.1' do
lazy_methods += [:compact]
end
Enumerator::Lazy.instance_methods(false).should include(*lazy_methods)
end

View File

@ -1,11 +1,9 @@
require_relative '../../spec_helper'
describe "ENV#dup" do
ruby_version_is "3.1" do
it "raises TypeError" do
-> {
ENV.dup
}.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end
end

View File

@ -29,6 +29,8 @@ describe "Errno::EMFILE" do
ExceptionSpecs::EMFILESub = Class.new(Errno::EMFILE)
exc = ExceptionSpecs::EMFILESub.new
exc.should be_an_instance_of(ExceptionSpecs::EMFILESub)
ensure
ExceptionSpecs.send(:remove_const, :EMFILESub)
end
end

View File

@ -16,6 +16,8 @@ describe "SystemCallError" do
exc = ExceptionSpecs::SCESub.new
ScratchPad.recorded.should equal(:initialize)
exc.should be_an_instance_of(ExceptionSpecs::SCESub)
ensure
ExceptionSpecs.send(:remove_const, :SCESub)
end
end

View File

@ -1,7 +1,5 @@
require_relative '../../spec_helper'
require 'fiber'
describe "Fiber#alive?" do
it "returns true for a Fiber that hasn't had #resume called" do
fiber = Fiber.new { true }

View File

@ -1,8 +1,6 @@
require_relative '../../spec_helper'
require_relative 'shared/blocking'
require "fiber"
describe "Fiber.blocking?" do
it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? }

View File

@ -1,14 +1,6 @@
require_relative '../../spec_helper'
require 'fiber'
describe "Fiber.current" do
ruby_version_is "3.1" do
it "is available without an extra require" do
ruby_exe("print Fiber.current.class", options: '--disable-gems --disable-did-you-mean').should == "Fiber"
end
end
it "returns the root Fiber when called outside of a Fiber" do
root = Fiber.current
root.should be_an_instance_of(Fiber)

View File

@ -1,5 +1,4 @@
require_relative '../../spec_helper'
require 'fiber'
describe "Fiber#inspect" do
describe "status" do

View File

@ -130,7 +130,6 @@ end
describe "Fiber#raise" do
it "transfers and raises on a transferring fiber" do
require "fiber"
root = Fiber.current
fiber = Fiber.new { root.transfer }
fiber.transfer

View File

@ -1,5 +1,5 @@
require_relative '../../spec_helper'
require_relative '../../shared/fiber/resume'
require_relative 'shared/resume'
describe "Fiber#resume" do
it_behaves_like :fiber_resume, :resume
@ -67,4 +67,17 @@ describe "Fiber#resume" do
ruby_exe(code).should == "ensure executed\n"
end
it "can work with Fiber#transfer" do
fiber1 = Fiber.new { true }
fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise }
fiber2.resume.should == 10
fiber2.resume.should == 20
end
it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
root_fiber = Fiber.current
fiber1 = Fiber.new { root_fiber.resume }
-> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
end
end

View File

@ -1,7 +1,5 @@
require_relative '../../spec_helper'
require_relative '../../shared/fiber/resume'
require 'fiber'
require_relative 'shared/resume'
describe "Fiber#transfer" do
it_behaves_like :fiber_resume, :transfer

View File

@ -11,7 +11,6 @@ describe "File.dirname" do
File.dirname('/foo/foo').should == '/foo'
end
ruby_version_is '3.1' do
context "when level is passed" do
it "returns all the components of filename except the last parts by the level" do
File.dirname('/home/jason', 2).should == '/'
@ -40,7 +39,6 @@ describe "File.dirname" do
File.dirname("/a/b/c/d", object).should == '/a/b'
end
end
end
it "returns a String" do
File.dirname("foo").should be_kind_of(String)

View File

@ -77,18 +77,6 @@ describe :file_path, shared: true do
after :each do
rm_r @dir
end
ruby_version_is ""..."3.1" do
it "raises IOError if file was opened with File::TMPFILE" do
begin
File.open(@dir, File::RDWR | File::TMPFILE) do |f|
-> { f.send(@method) }.should raise_error(IOError)
end
rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR
skip "no support from the filesystem"
end
end
end
end
end
end

View File

@ -30,6 +30,11 @@ describe "Float#round" do
12.345678.round(3.999).should == 12.346
end
it "correctly rounds exact floats with a numerous digits in a fraction part" do
0.8241000000000004.round(10).should == 0.8241
0.8241000000000002.round(10).should == 0.8241
end
it "returns zero when passed a negative argument with magnitude greater than magnitude of the whole number portion of the Float" do
0.8346268.round(-1).should eql(0)
end
@ -68,6 +73,10 @@ describe "Float#round" do
0.42.round(2.0**30).should == 0.42
end
it "returns rounded values for not so big argument" do
0.42.round(2.0**23).should == 0.42
end
it "returns big values rounded to nearest" do
+2.5e20.round(-20).should eql( +3 * 10 ** 20 )
-2.5e20.round(-20).should eql( -3 * 10 ** 20 )

View File

@ -1,7 +1,6 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "GC.measure_total_time" do
describe "GC.measure_total_time" do
before :each do
@default = GC.measure_total_time
end
@ -15,5 +14,4 @@ ruby_version_is "3.1" do
GC.measure_total_time = !original
GC.measure_total_time.should == !original
end
end
end

View File

@ -1,7 +1,6 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "GC.total_time" do
describe "GC.total_time" do
it "returns an Integer" do
GC.total_time.should be_kind_of(Integer)
end
@ -11,5 +10,4 @@ ruby_version_is "3.1" do
GC.start
GC.total_time.should >= time_before
end
end
end

View File

@ -42,12 +42,10 @@ describe "Hash#hash" do
# Like above, because h.eql?(x: [h])
end
ruby_version_is "3.1" do
it "allows omitting values" do
a = 1
b = 2
eval('{a:, b:}.should == { a: 1, b: 2 }')
end
{a:, b:}.should == { a: 1, b: 2 }
end
end

View File

@ -76,17 +76,6 @@ describe "Hash#transform_keys!" do
@hash.should == { b: 1, c: 2, d: 3, e: 4 }
end
ruby_version_is ""..."3.0.2" do # https://bugs.ruby-lang.org/issues/17735
it "returns the processed keys if we break from the block" do
@hash.transform_keys! do |v|
break if v == :c
v.succ
end
@hash.should == { b: 1, c: 2 }
end
end
ruby_version_is "3.0.2" do
it "returns the processed keys and non evaluated keys if we break from the block" do
@hash.transform_keys! do |v|
break if v == :c
@ -94,7 +83,6 @@ describe "Hash#transform_keys!" do
end
@hash.should == { b: 1, c: 2, d: 4 }
end
end
it "keeps later pair if new keys conflict" do
@hash.transform_keys! { |_| :a }.should == { a: 4 }

View File

@ -1,8 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.1" do
describe "Integer.try_convert" do
describe "Integer.try_convert" do
it "returns the argument if it's an Integer" do
x = 42
Integer.try_convert(x).should equal(x)
@ -46,5 +45,4 @@ ruby_version_is "3.1" do
obj.should_receive(:to_int).and_raise(RuntimeError)
-> { Integer.try_convert obj }.should raise_error(RuntimeError)
end
end
end

View File

@ -94,13 +94,11 @@ describe "IO#external_encoding" do
rm_r @name
end
ruby_version_is '3.1' do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
io.external_encoding.should equal(Encoding.default_external)
end
end
describe "with 'r' mode" do
describe "when Encoding.default_internal is nil" do

View File

@ -113,13 +113,11 @@ describe "IO#internal_encoding" do
Encoding.default_internal = @internal
end
ruby_version_is '3.1' do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
io.internal_encoding.should equal(Encoding.default_internal)
end
end
describe "with 'r' mode" do
it_behaves_like :io_internal_encoding, nil, "r"

View File

@ -93,13 +93,11 @@ describe "IO#readpartial" do
@rd.readpartial(0).should == ""
end
ruby_bug "#18421", ""..."3.0.4" do
it "clears and returns the given buffer if the length argument is 0" do
buffer = +"existing content"
@rd.readpartial(0, buffer).should == buffer
buffer.should == ""
end
end
it "preserves the encoding of the given buffer" do
buffer = ''.encode(Encoding::ISO_8859_1)

View File

@ -5,15 +5,20 @@ describe :kernel_block_given, shared: true do
it "returns true if and only if a block is supplied" do
@object.accept_block {}.should == true
@object.accept_block_as_argument {}.should == true
@object.accept_block_inside_block {}.should == true
@object.accept_block_as_argument_inside_block {}.should == true
@object.accept_block.should == false
@object.accept_block_as_argument.should == false
@object.accept_block_inside_block.should == false
@object.accept_block_as_argument_inside_block.should == false
end
# Clarify: Based on http://www.ruby-forum.com/topic/137822 it appears
# that Matz wanted this to be true in 1.9.
it "returns false when a method defined by define_method is called with a block" do
@object.defined_block {}.should == false
@object.defined_block_inside_block {}.should == false
end
end

View File

@ -313,6 +313,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"")
EvalSpecs::.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπ)
end
it "allows an emacs-style magic comment encoding" do
@ -326,6 +328,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπemacs")
EvalSpecs::Vπemacs.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπemacs)
end
it "allows spaces before the magic encoding comment" do
@ -339,6 +343,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπspaces")
EvalSpecs::Vπspaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπspaces)
end
it "allows a shebang line before the magic encoding comment" do
@ -353,6 +359,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπshebang")
EvalSpecs::Vπshebang.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang)
end
it "allows a shebang line and some spaces before the magic encoding comment" do
@ -367,6 +375,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"Vπshebang_spaces")
EvalSpecs::Vπshebang_spaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang_spaces)
end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
@ -385,6 +395,8 @@ CODE
EvalSpecs::Vπstring.should == "frozen"
EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
ensure
EvalSpecs.send(:remove_const, :Vπstring)
end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
@ -400,6 +412,8 @@ CODE
EvalSpecs::Vπsame_line.should == "frozen"
EvalSpecs::Vπsame_line.encoding.should == Encoding::UTF_8
EvalSpecs::Vπsame_line.frozen?.should be_true
ensure
EvalSpecs.send(:remove_const, :Vπsame_line)
end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
@ -420,6 +434,8 @@ CODE
value.should == "frozen"
value.encoding.should == Encoding::BINARY
value.frozen?.should == !frozen_string_default
ensure
EvalSpecs.send(:remove_const, binary_constant)
end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do

View File

@ -219,10 +219,28 @@ module KernelSpecs
block_given?
end
def self.accept_block_inside_block()
yield_self {
block_given?
}
end
def self.accept_block_as_argument_inside_block(&block)
yield_self {
block_given?
}
end
class << self
define_method(:defined_block) do
block_given?
end
define_method(:defined_block_inside_block) do
yield_self {
block_given?
}
end
end
end
@ -235,10 +253,28 @@ module KernelSpecs
self.send(:block_given?)
end
def self.accept_block_inside_block
yield_self {
self.send(:block_given?)
}
end
def self.accept_block_as_argument_inside_block(&block)
yield_self {
self.send(:block_given?)
}
end
class << self
define_method(:defined_block) do
self.send(:block_given?)
end
define_method(:defined_block_inside_block) do
yield_self {
self.send(:block_given?)
}
end
end
end
@ -251,10 +287,28 @@ module KernelSpecs
Kernel.block_given?
end
def self.accept_block_inside_block
yield_self {
Kernel.block_given?
}
end
def self.accept_block_as_argument_inside_block(&block)
yield_self {
Kernel.block_given?
}
end
class << self
define_method(:defined_block) do
Kernel.block_given?
end
define_method(:defined_block_inside_block) do
yield_self {
Kernel.block_given?
}
end
end
end

View File

@ -16,10 +16,7 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
provided = %w[complex enumerator rational thread ruby2_keywords]
ruby_version_is "3.1" do
provided << "fiber"
end
provided = %w[complex enumerator fiber rational thread ruby2_keywords]
it "#{provided.join(', ')} are already required" do
out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')

View File

@ -165,7 +165,6 @@ describe :kernel_load, shared: true do
end
describe "when passed a module for 'wrap'" do
ruby_version_is "3.1" do
it "sets the enclosing scope to the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@ -197,7 +196,6 @@ describe :kernel_load, shared: true do
mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
end
end
end
describe "(shell expansion)" do
before :each do

View File

@ -30,17 +30,9 @@ describe "main#private" do
end
end
ruby_version_is ''...'3.1' do
it "returns Object" do
eval("private :main_public_method", TOPLEVEL_BINDING).should equal(Object)
end
end
ruby_version_is '3.1' do
it "returns argument" do
eval("private :main_public_method", TOPLEVEL_BINDING).should equal(:main_public_method)
end
end
it "raises a NameError when at least one of given method names is undefined" do
-> do

View File

@ -30,17 +30,9 @@ describe "main#public" do
end
end
ruby_version_is ''...'3.1' do
it "returns Object" do
eval("public :main_private_method", TOPLEVEL_BINDING).should equal(Object)
end
end
ruby_version_is '3.1' do
it "returns argument" do
eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
end
end
it "raises a NameError when given an undefined name" do

View File

@ -599,7 +599,6 @@ describe "Marshal.dump" do
Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006"
end
ruby_version_is "3.1" do
it "dumps a Hash with compare_by_identity" do
h = {}
h.compare_by_identity
@ -613,7 +612,6 @@ describe "Marshal.dump" do
Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
end
end
it "raises a TypeError with hash having default proc" do
-> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError, "can't dump hash with default proc")

View File

@ -23,7 +23,6 @@ describe :marshal_load, shared: true do
-> { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError)
end
ruby_version_is "3.1" do
describe "when called with freeze: true" do
it "returns frozen strings" do
string = Marshal.send(@method, Marshal.dump("foo"), freeze: true)
@ -222,10 +221,8 @@ describe :marshal_load, shared: true do
end
end
end
end
describe "when called with a proc" do
ruby_bug "#18141", ""..."3.1" do
it "call the proc with fully initialized strings" do
utf8_string = "foo".encode(Encoding::UTF_8)
Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
@ -241,7 +238,6 @@ describe :marshal_load, shared: true do
string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
string.should.frozen?
end
end
ruby_bug "#19427", ""..."3.3" do
it "call the proc with extended objects" do
@ -255,7 +251,6 @@ describe :marshal_load, shared: true do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end
ruby_bug "#18141", ""..."3.1" do
it "calls the proc for recursively visited data" do
a = [1]
a << a
@ -290,7 +285,6 @@ describe :marshal_load, shared: true do
Struct.send(:remove_const, :Brittle)
end
end
end
describe "when called with nil for the proc argument" do
it "behaves as if no proc argument was passed" do
@ -364,7 +358,6 @@ describe :marshal_load, shared: true do
end
end
ruby_bug "#18141", ""..."3.1" do
it "loads an array containing objects having _dump method, and with proc" do
arr = []
myproc = Proc.new { |o| arr << o.dup; o }
@ -397,7 +390,6 @@ describe :marshal_load, shared: true do
arr.size.should == 6
end
end
it "assigns classes to nested subclasses of Array correctly" do
arr = ArraySub.new(ArraySub.new)
@ -526,7 +518,6 @@ describe :marshal_load, shared: true do
unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
end
ruby_version_is "3.1" do
it "preserves compare_by_identity behaviour" do
h = { a: 1 }
h.compare_by_identity
@ -548,7 +539,6 @@ describe :marshal_load, shared: true do
unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should_not.compare_by_identity?
end
end
it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do
h = UserHash.new({ a: 1 })

View File

@ -2,8 +2,7 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "MatchData#match_length" do
describe "MatchData#match_length" do
it "returns the length of the corresponding match when given an Integer" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
@ -30,5 +29,4 @@ ruby_version_is "3.1" do
md.match_length(:t).should == 1
md.match_length(:a).should == nil
end
end
end

View File

@ -2,8 +2,7 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "MatchData#match" do
describe "MatchData#match" do
it "returns the corresponding match when given an Integer" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
@ -30,5 +29,4 @@ ruby_version_is "3.1" do
md.match(:t).should == 't'
md.match(:a).should == nil
end
end
end

View File

@ -257,31 +257,18 @@ describe "Method#parameters" do
end
end
ruby_version_is '3.1' do
it "adds block arg with name & for anonymous block argument" do
object = Object.new
eval(<<~RUBY).should == [[:block, :&]]
def object.foo(&)
end
object.method(:foo).parameters
RUBY
end
object.method(:foo).parameters.should == [[:block, :&]]
end
ruby_version_is ""..."3.1" do
it "returns [:rest, :*], [:block, :&] for forward parameters operator" do
m = MethodSpecs::Methods.new
m.method(:forward_parameters).parameters.should == [[:rest, :*], [:block, :&]]
end
end
ruby_version_is "3.1" do
it "returns [:rest, :*], [:keyrest, :**], [:block, :&] for forward parameters operator" do
m = MethodSpecs::Methods.new
m.method(:forward_parameters).parameters.should == [[:rest, :*], [:keyrest, :**], [:block, :&]]
end
end
it "returns the args and block for a splat and block argument" do
m = MethodSpecs::Methods.new

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#private?" do
ruby_version_is "3.1"..."3.2" do
ruby_version_is ""..."3.2" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).private?.should == false

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#protected?" do
ruby_version_is "3.1"..."3.2" do
ruby_version_is ""..."3.2" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).protected?.should == false

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#public?" do
ruby_version_is "3.1"..."3.2" do
ruby_version_is ""..."3.2" do
it "returns true when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).public?.should == true

View File

@ -486,7 +486,6 @@ describe "Module#autoload" do
ScratchPad.recorded.should == [:raise, :raise]
end
ruby_version_is "3.1" do
it "removes the constant from Module#constants if the loaded file does not define it" do
path = fixture(__FILE__, "autoload_o.rb")
ScratchPad.record []
@ -503,26 +502,6 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload?(:O).should == nil
-> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
end
end
ruby_version_is ""..."3.1" do
it "does not remove the constant from Module#constants if the loaded file does not define it, but leaves it as 'undefined'" do
path = fixture(__FILE__, "autoload_o.rb")
ScratchPad.record []
ModuleSpecs::Autoload.autoload :O, path
ModuleSpecs::Autoload.const_defined?(:O).should == true
ModuleSpecs::Autoload.should have_constant(:O)
ModuleSpecs::Autoload.autoload?(:O).should == path
-> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
ModuleSpecs::Autoload.const_defined?(:O).should == false
ModuleSpecs::Autoload.should have_constant(:O)
ModuleSpecs::Autoload.autoload?(:O).should == nil
-> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
end
end
it "does not try to load the file again if the loaded file did not define the constant" do
path = fixture(__FILE__, "autoload_o.rb")
@ -654,7 +633,6 @@ describe "Module#autoload" do
end
end
ruby_version_is "3.1" do
it "looks up in parent scope after failed autoload" do
@remove << :DeclaredInCurrentDefinedInParent
module ModuleSpecs::Autoload
@ -674,30 +652,6 @@ describe "Module#autoload" do
DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
end
end
end
ruby_version_is ""..."3.1" do
it "and fails when finding the undefined autoload constant in the current scope when declared in current and defined in parent" do
@remove << :DeclaredInCurrentDefinedInParent
module ModuleSpecs::Autoload
ScratchPad.record -> {
DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
}
class LexicalScope
autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
-> { DeclaredInCurrentDefinedInParent }.should raise_error(NameError)
# Basically, the autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
const_defined?(:DeclaredInCurrentDefinedInParent).should == false
self.should have_constant(:DeclaredInCurrentDefinedInParent)
-> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
end
DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
end
end
end
it "in the included modules" do
@remove << :DefinedInIncludedModule

View File

@ -65,6 +65,8 @@ describe "Module#const_defined?" do
str = "CS_CONSTλ".encode("euc-jp")
ConstantSpecs.const_set str, 1
ConstantSpecs.const_defined?(str).should be_true
ensure
ConstantSpecs.send(:remove_const, str)
end
it "returns false if the constant is not defined in the receiver, its superclass, or any included modules" do

View File

@ -202,40 +202,60 @@ describe "Module#const_get" do
ConstantSpecs::ContainerA::ChildA::CS_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST301).should == :const301_5
ensure
ConstantSpecs::ClassA.send(:remove_const, :CS_CONST301)
ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST301)
ConstantSpecs::ParentA.send(:remove_const, :CS_CONST301)
ConstantSpecs::ContainerA::ChildA.send(:remove_const, :CS_CONST301)
end
it "searches a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CS_CONST302 = :const302_1
ConstantSpecs::ModuleF::CS_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST302).should == :const302_2
ensure
ConstantSpecs::ParentB.send(:remove_const, :CS_CONST302)
ConstantSpecs::ModuleF.send(:remove_const, :CS_CONST302)
end
it "searches the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CS_CONST303 = :const303_1
ConstantSpecs::ParentB::CS_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST303).should == :const303_2
ensure
ConstantSpecs::ModuleE.send(:remove_const, :CS_CONST303)
ConstantSpecs::ParentB.send(:remove_const, :CS_CONST303)
end
it "searches a module included in the superclass" do
ConstantSpecs::ModuleA::CS_CONST304 = :const304_1
ConstantSpecs::ModuleE::CS_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST304).should == :const304_2
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST304)
ConstantSpecs::ModuleE.send(:remove_const, :CS_CONST304)
end
it "searches the superclass chain" do
ConstantSpecs::ModuleA::CS_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST305).should == :const305
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST305)
end
it "returns a toplevel constant when the receiver is a Class" do
Object::CS_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST306).should == :const306
ensure
Object.send(:remove_const, :CS_CONST306)
end
it "returns a toplevel constant when the receiver is a Module" do
Object::CS_CONST308 = :const308
ConstantSpecs.const_get(:CS_CONST308).should == :const308
ConstantSpecs::ModuleA.const_get(:CS_CONST308).should == :const308
ensure
Object.send(:remove_const, :CS_CONST308)
end
it "returns the updated value of a constant" do
@ -246,6 +266,8 @@ describe "Module#const_get" do
ConstantSpecs::ClassB::CS_CONST309 = :const309_2
}.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_get(:CS_CONST309).should == :const309_2
ensure
ConstantSpecs::ClassB.send(:remove_const, :CS_CONST309)
end
end
end

View File

@ -8,16 +8,23 @@ describe "Module#const_set" do
ConstantSpecs.const_set "CS_CONST402", :const402
ConstantSpecs.const_get(:CS_CONST402).should == :const402
ensure
ConstantSpecs.send(:remove_const, :CS_CONST401)
ConstantSpecs.send(:remove_const, :CS_CONST402)
end
it "returns the value set" do
ConstantSpecs.const_set(:CS_CONST403, :const403).should == :const403
ensure
ConstantSpecs.send(:remove_const, :CS_CONST403)
end
it "sets the name of an anonymous module" do
m = Module.new
ConstantSpecs.const_set(:CS_CONST1000, m)
m.name.should == "ConstantSpecs::CS_CONST1000"
ensure
ConstantSpecs.send(:remove_const, :CS_CONST1000)
end
it "sets the name of a module scoped by an anonymous module" do
@ -38,6 +45,8 @@ describe "Module#const_set" do
b.name.should == "ModuleSpecs_CS3::B"
c.name.should == "ModuleSpecs_CS3::B::C"
d.name.should == "ModuleSpecs_CS3::D"
ensure
Object.send(:remove_const, :ModuleSpecs_CS3)
end
it "raises a NameError if the name does not start with a capital letter" do
@ -55,6 +64,8 @@ describe "Module#const_set" do
ConstantSpecs.const_set("CS_CONST404", :const404).should == :const404
-> { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError)
-> { ConstantSpecs.const_set "Name?", 1 }.should raise_error(NameError)
ensure
ConstantSpecs.send(:remove_const, :CS_CONST404)
end
it "calls #to_str to convert the given name to a String" do
@ -62,6 +73,8 @@ describe "Module#const_set" do
name.should_receive(:to_str).and_return("CS_CONST405")
ConstantSpecs.const_set(name, :const405).should == :const405
ConstantSpecs::CS_CONST405.should == :const405
ensure
ConstantSpecs.send(:remove_const, :CS_CONST405)
end
it "raises a TypeError if conversion to a String by calling #to_str fails" do

View File

@ -19,40 +19,60 @@ describe "Module#const_source_location" do
ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ClassA.send(:remove_const, :CSL_CONST301)
ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST301)
ConstantSpecs::ParentA.send(:remove_const, :CSL_CONST301)
ConstantSpecs::ContainerA::ChildA.send(:remove_const, :CSL_CONST301)
end
it "searches a path in a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CSL_CONST302 = :const302_1
ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ParentB.send(:remove_const, :CSL_CONST302)
ConstantSpecs::ModuleF.send(:remove_const, :CSL_CONST302)
end
it "searches a path in the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1
ConstantSpecs::ParentB::CSL_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ModuleE.send(:remove_const, :CSL_CONST303)
ConstantSpecs::ParentB.send(:remove_const, :CSL_CONST303)
end
it "searches a path in a module included in the superclass" do
ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1
ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST304)
ConstantSpecs::ModuleE.send(:remove_const, :CSL_CONST304)
end
it "searches a path in the superclass chain" do
ConstantSpecs::ModuleA::CSL_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST305)
end
it "returns path to a toplevel constant when the receiver is a Class" do
Object::CSL_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1]
ensure
Object.send(:remove_const, :CSL_CONST306)
end
it "returns path to a toplevel constant when the receiver is a Module" do
Object::CSL_CONST308 = :const308
ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2]
ensure
Object.send(:remove_const, :CSL_CONST308)
end
it "returns path to the updated value of a constant" do
@ -63,6 +83,8 @@ describe "Module#const_source_location" do
ConstantSpecs::ClassB::CSL_CONST309 = :const309_2
}.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2]
ensure
ConstantSpecs::ClassB.send(:remove_const, :CSL_CONST309)
end
end

View File

@ -476,6 +476,9 @@ describe "Module#define_method" do
ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } }
ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo)
}.should raise_error(TypeError, /bind argument must be a subclass of ChildClass/)
ensure
Object.send(:remove_const, :ParentClass)
Object.send(:remove_const, :ChildClass)
end
it "raises a TypeError when an UnboundMethod from one class is defined on an unrelated class" do

View File

@ -44,7 +44,11 @@ describe "Module#include" do
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
-> { ModuleSpecs::SubclassSpec.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
class ModuleSpecs::SubclassSpec::AClass
end
-> { ModuleSpecs::SubclassSpec::AClass.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
ruby_version_is ""..."3.2" do
@ -427,6 +431,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdated)
end
it "updates the constant when a module included after a call is later updated" do
@ -453,6 +459,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstLaterUpdated)
end
it "updates the constant when a module included in another module after a call is later updated" do
@ -479,6 +487,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstModuleLaterUpdated)
end
it "updates the constant when a nested included module is updated" do
@ -507,6 +517,8 @@ describe "Module#include" do
N.const_set(:FOO, 'n')
B.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncludeUpdated)
end
it "updates the constant when a new module is included" do
@ -531,6 +543,8 @@ describe "Module#include" do
B.include(M)
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNewInclude)
end
it "updates the constant when a new module with nested module is included" do
@ -559,6 +573,8 @@ describe "Module#include" do
B.include M
B.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncluded)
end
it "overrides a previous super method call" do

View File

@ -38,16 +38,6 @@ describe "Module#module_function with specific method names" do
m.respond_to?(:test3).should == false
end
ruby_version_is ""..."3.1" do
it "returns self" do
Module.new do
def foo; end
module_function(:foo).should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
Module.new do
def foo; end
@ -55,7 +45,6 @@ describe "Module#module_function with specific method names" do
module_function(:foo, :foo).should == [:foo, :foo]
end
end
end
it "creates an independent copy of the method, not a redirect" do
module Mixin
@ -216,21 +205,11 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
m.respond_to?(:test2).should == true
end
ruby_version_is ""..."3.1" do
it "returns self" do
Module.new do
module_function.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns nil" do
Module.new do
module_function.should equal(nil)
end
end
end
it "stops creating module functions if the body encounters another toggle " \
"like public/protected/private without arguments" do

View File

@ -30,6 +30,8 @@ describe "Module#name" do
m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
ModuleSpecs::Anonymous::WasAnnon = m::N
m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :WasAnnon)
end
it "may be the repeated in different module objects" do
@ -76,12 +78,16 @@ describe "Module#name" do
m = Module.new
ModuleSpecs::Anonymous::A = m
m.name.should == "ModuleSpecs::Anonymous::A"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :A)
end
it "is set when assigning to a constant (constant path does not match outer module name)" do
m = Module.new
ModuleSpecs::Anonymous::SameChild::A = m
m.name.should == "ModuleSpecs::Anonymous::Child::A"
ensure
ModuleSpecs::Anonymous::SameChild.send(:remove_const, :A)
end
it "is not modified when assigning to a new constant after it has been accessed" do
@ -90,6 +96,9 @@ describe "Module#name" do
m.name.should == "ModuleSpecs::Anonymous::B"
ModuleSpecs::Anonymous::C = m
m.name.should == "ModuleSpecs::Anonymous::B"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :B)
ModuleSpecs::Anonymous.send(:remove_const, :C)
end
it "is not modified when assigned to a different anonymous module" do
@ -125,6 +134,8 @@ describe "Module#name" do
m::N = Module.new
ModuleSpecs::Anonymous::E = m
m::N.name.should == "ModuleSpecs::Anonymous::E::N"
ensure
ModuleSpecs::Anonymous.send(:remove_const, :E)
end
# https://bugs.ruby-lang.org/issues/19681
@ -138,6 +149,8 @@ describe "Module#name" do
"ModuleSpecs::Anonymous::StoredInMultiplePlaces::O"
]
valid_names.should include(m::N.name) # You get one of the two, but you don't know which one.
ensure
ModuleSpecs::Anonymous.send(:remove_const, :StoredInMultiplePlaces)
end
ruby_version_is "3.2" do

View File

@ -261,6 +261,8 @@ describe "Module#prepend" do
B.prepend M
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatePrepended)
end
it "updates the constant when a prepended module is updated" do
@ -281,6 +283,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstPrependedUpdated)
end
it "updates the constant when there is a base included constant and the prepended module overrides it" do
@ -302,6 +306,8 @@ describe "Module#prepend" do
A.prepend M
A.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstIncludedPrependedOverride)
end
it "updates the constant when there is a base included constant and the prepended module is later updated" do
@ -325,6 +331,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
A.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstIncludedPrependedLaterUpdated)
end
it "updates the constant when a module prepended after a constant is later updated" do
@ -348,6 +356,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterLaterUpdated)
end
it "updates the constant when a module is prepended after another and the constant is defined later on that module" do
@ -372,6 +382,8 @@ describe "Module#prepend" do
N.const_set(:FOO, 'n')
A.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterConstDefined)
end
it "updates the constant when a module is included in a prepended module and the constant is defined later" do
@ -399,6 +411,8 @@ describe "Module#prepend" do
N.const_set(:FOO, 'n')
A.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedIncludedInPrependedConstDefinedLater)
end
it "updates the constant when a new module with an included module is prepended" do
@ -425,6 +439,8 @@ describe "Module#prepend" do
B.prepend M
B.foo.should == 'n'
end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNewModuleIncludedPrepended)
end
it "raises a TypeError when the argument is not a Module" do
@ -432,7 +448,11 @@ describe "Module#prepend" do
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
-> { ModuleSpecs::SubclassSpec.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
class ModuleSpecs::SubclassSpec::AClass
end
-> { ModuleSpecs::SubclassSpec::AClass.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
ruby_version_is ""..."3.2" do
@ -787,22 +807,6 @@ describe "Module#prepend" do
# https://bugs.ruby-lang.org/issues/17423
describe "when module already exists in ancestor chain" do
ruby_version_is ""..."3.1" do
it "does not modify the ancestor chain" do
m = Module.new do; end
a = Module.new do; end
b = Class.new do; end
b.include(a)
a.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object]
b.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object]
end
end
ruby_version_is "3.1" do
it "modifies the ancestor chain" do
m = Module.new do; end
a = Module.new do; end
@ -816,7 +820,6 @@ describe "Module#prepend" do
b.ancestors.take(5).should == [m, b, m, a, Object]
end
end
end
describe "called on a module" do
describe "included into a class"

View File

@ -38,17 +38,6 @@ describe "Module#private" do
:module_specs_public_method_on_object_for_kernel_private)
end
ruby_version_is ""..."3.1" do
it "returns self" do
(class << Object.new; self; end).class_eval do
def foo; end
private(:foo).should equal(self)
private.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
@ -58,7 +47,6 @@ describe "Module#private" do
private.should equal(nil)
end
end
end
it "raises a NameError when given an undefined name" do
-> do

View File

@ -39,17 +39,6 @@ describe "Module#protected" do
:module_specs_public_method_on_object_for_kernel_protected)
end
ruby_version_is ""..."3.1" do
it "returns self" do
(class << Object.new; self; end).class_eval do
def foo; end
protected(:foo).should equal(self)
protected.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
@ -59,7 +48,6 @@ describe "Module#protected" do
protected.should equal(nil)
end
end
end
it "raises a NameError when given an undefined name" do
-> do

View File

@ -27,17 +27,6 @@ describe "Module#public" do
:module_specs_private_method_on_object_for_kernel_public)
end
ruby_version_is ""..."3.1" do
it "returns self" do
(class << Object.new; self; end).class_eval do
def foo; end
public(:foo).should equal(self)
public.should equal(self)
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
@ -47,7 +36,6 @@ describe "Module#public" do
public.should equal(nil)
end
end
end
it "raises a NameError when given an undefined name" do
-> do

View File

@ -300,67 +300,6 @@ describe "Module#refine" do
result.should == "foo from IncludeMeLater"
end
ruby_version_is ""..."3.1" do
it "looks in prepended modules from the refinement first" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine refined_class do
include ModuleSpecs::IncludedModule
prepend ModuleSpecs::PrependedModule
def foo; "foo from refinement"; end
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from prepended module"
end
it "looks in refinement then" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine(refined_class) do
include ModuleSpecs::IncludedModule
def foo; "foo from refinement"; end
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from refinement"
end
it "looks in included modules from the refinement then" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine refined_class do
include ModuleSpecs::IncludedModule
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from included module"
end
end
it "looks in the class then" do
refined_class = ModuleSpecs.build_refined_class
@ -606,30 +545,6 @@ describe "Module#refine" do
end
context "when super is called in a refinement" do
ruby_version_is ""..."3.1" do
it "looks in the included to refinery module" do
refined_class = ModuleSpecs.build_refined_class
refinement = Module.new do
refine refined_class do
include ModuleSpecs::IncludedModule
def foo
super
end
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == "foo from included module"
end
end
it "looks in the refined class" do
refined_class = ModuleSpecs.build_refined_class
@ -650,59 +565,6 @@ describe "Module#refine" do
result.should == "foo"
end
ruby_version_is ""..."3.1" do
it "looks in the refined class from included module" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == [:A, :C]
end
it "looks in the refined ancestors from included module" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
subclass = Class.new(refined_class)
a = Module.new do
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = subclass.new.foo
end
result.should == [:A, :C]
end
end
# super in a method of a refinement invokes the method in the refined
# class even if there is another refinement which has been activated
# in the same context.
@ -763,179 +625,6 @@ describe "Module#refine" do
}.should raise_error(NoMethodError)
end
end
ruby_version_is ""..."3.1" do
it "does't have access to active refinements for C from included module" do
refined_class = ModuleSpecs.build_refined_class
a = Module.new do
def foo
super + bar
end
end
refinement = Module.new do
refine refined_class do
include a
def bar
"bar is not seen from A methods"
end
end
end
Module.new do
using refinement
-> {
refined_class.new.foo
}.should raise_error(NameError) { |e| e.name.should == :bar }
end
end
it "does't have access to other active refinements from included module" do
refined_class = ModuleSpecs.build_refined_class
refinement_integer = Module.new do
refine Integer do
def bar
"bar is not seen from A methods"
end
end
end
a = Module.new do
def foo
super + 1.bar
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
Module.new do
using refinement
using refinement_integer
-> {
refined_class.new.foo
}.should raise_error(NameError) { |e| e.name.should == :bar }
end
end
# https://bugs.ruby-lang.org/issues/16977
it "looks in the another active refinement if super called from included modules" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
b = Module.new do
def foo
[:B] + super
end
end
refinement_a = Module.new do
refine refined_class do
include a
end
end
refinement_b = Module.new do
refine refined_class do
include b
end
end
result = nil
Module.new do
using refinement_a
using refinement_b
result = refined_class.new.foo
end
result.should == [:B, :A, :C]
end
it "looks in the current active refinement from included modules" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
b = Module.new do
def foo
[:B] + super
end
end
refinement = Module.new do
refine refined_class do
def foo
[:LAST] + super
end
end
end
refinement_a_b = Module.new do
refine refined_class do
include a
include b
end
end
result = nil
Module.new do
using refinement
using refinement_a_b
result = refined_class.new.foo
end
result.should == [:B, :A, :LAST, :C]
end
it "looks in the lexical scope refinements before other active refinements" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
refinement_local = Module.new do
refine refined_class do
def foo
[:LOCAL] + super
end
end
end
a = Module.new do
using refinement_local
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == [:A, :LOCAL, :C]
end
end
end
it 'and alias aliases a method within a refinement module, but not outside it' do

View File

@ -101,5 +101,7 @@ describe "Module#remove_const" do
A.send(:remove_const,:FOO)
A.foo.should == 'm'
end
ensure
ConstantSpecs.send(:remove_const, :RemovedConstantUpdate)
end
end

View File

@ -51,6 +51,8 @@ describe "Module#to_s" do
ModuleSpecs::RefinementInspect::R.name.should == 'ModuleSpecs::RefinementInspect::R'
ModuleSpecs::RefinementInspect::R.to_s.should == '#<refinement:String@ModuleSpecs::RefinementInspect>'
ensure
ModuleSpecs.send(:remove_const, :RefinementInspect)
end
it 'does not call #inspect or #to_s for singleton classes' do

View File

@ -193,7 +193,6 @@ describe "ObjectSpace.define_finalizer" do
ret[1].should.equal?(p)
end
ruby_version_is "3.1" do
describe "when $VERBOSE is not nil" do
it "warns if an exception is raised in finalizer" do
code = <<-RUBY
@ -213,5 +212,4 @@ describe "ObjectSpace.define_finalizer" do
ruby_exe(code, args: "2>&1", options: "-W0").should == ""
end
end
end
end

View File

@ -0,0 +1,27 @@
require_relative '../../../spec_helper'
ruby_version_is '3.3' do
describe "ObjectSpace::WeakKeyMap#clear" do
it "removes all the entries" do
m = ObjectSpace::WeakKeyMap.new
key = Object.new
value = Object.new
m[key] = value
key2 = Object.new
value2 = Object.new
m[key2] = value2
m.clear
m.key?(key).should == false
m.key?(key2).should == false
end
it "returns self" do
m = ObjectSpace::WeakKeyMap.new
m.clear.should.equal?(m)
end
end
end

View File

@ -33,8 +33,19 @@ ruby_version_is '3.3' do
end
it "returns nil if the key is not found when no block is given" do
m = ObjectSpace::WeakMap.new
m = ObjectSpace::WeakKeyMap.new
m.delete(Object.new).should == nil
end
it "returns nil when a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new
map.delete(1).should == nil
map.delete(1.0).should == nil
map.delete(:a).should == nil
map.delete(true).should == nil
map.delete(false).should == nil
map.delete(nil).should == nil
end
end
end

View File

@ -1,4 +1,5 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.3" do
describe "ObjectSpace::WeakKeyMap#[]" do
@ -15,12 +16,92 @@ ruby_version_is "3.3" do
map[key2].should == ref2
end
it "matches using equality semantics" do
it "compares keys with #eql? semantics" do
map = ObjectSpace::WeakKeyMap.new
key = [1.0]
map[key] = "x"
map[[1]].should == nil
map[[1.0]].should == "x"
key.should == [1.0] # keep the key alive until here to keep the map entry
map = ObjectSpace::WeakKeyMap.new
key = [1]
map[key] = "x"
map[[1.0]].should == nil
map[[1]].should == "x"
key.should == [1] # keep the key alive until here to keep the map entry
map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a a].map(&:upcase)
ref = "x"
map[key1] = ref
map[key2].should == ref
end
it "compares key via #hash first" do
x = mock('0')
x.should_receive(:hash).and_return(0)
map = ObjectSpace::WeakKeyMap.new
key = 'foo'
map[key] = :bar
map[x].should == nil
end
it "does not compare keys with different #hash values via #eql?" do
x = mock('x')
x.should_not_receive(:eql?)
x.stub!(:hash).and_return(0)
y = mock('y')
y.should_not_receive(:eql?)
y.stub!(:hash).and_return(1)
map = ObjectSpace::WeakKeyMap.new
map[y] = 1
map[x].should == nil
end
it "compares keys with the same #hash value via #eql?" do
x = mock('x')
x.should_receive(:eql?).and_return(true)
x.stub!(:hash).and_return(42)
y = mock('y')
y.should_not_receive(:eql?)
y.stub!(:hash).and_return(42)
map = ObjectSpace::WeakKeyMap.new
map[y] = 1
map[x].should == 1
end
it "finds a value via an identical key even when its #eql? isn't reflexive" do
x = mock('x')
x.should_receive(:hash).at_least(1).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
map = ObjectSpace::WeakKeyMap.new
map[x] = :x
map[x].should == :x
end
it "supports keys with private #hash method" do
key = WeakKeyMapSpecs::KeyWithPrivateHash.new
map = ObjectSpace::WeakKeyMap.new
map[key] = 42
map[key].should == 42
end
it "returns nil and does not raise error when a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new
map[1].should == nil
map[1.0].should == nil
map[:a].should == nil
map[true].should == nil
map[false].should == nil
map[nil].should == nil
end
end
end

View File

@ -8,10 +8,6 @@ ruby_version_is "3.3" do
map[key].should == value
end
def should_not_accept(map, key, value)
-> { map[key] = value }.should raise_error(ArgumentError)
end
it "is correct" do
map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a b].map(&:upcase)
@ -40,32 +36,47 @@ ruby_version_is "3.3" do
should_accept(map, y, x)
end
it "rejects symbols as keys" do
it "does not duplicate and freeze String keys (like Hash#[]= does)" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, :foo, true)
should_not_accept(map, rand.to_s.to_sym, true)
key = +"a"
map[key] = 1
map.getkey("a").should.equal? key
map.getkey("a").should_not.frozen?
key.should == "a" # keep the key alive until here to keep the map entry
end
it "rejects integers as keys" do
context "a key cannot be garbage collected" do
it "raises ArgumentError when Integer is used as a key" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, 42, true)
should_not_accept(map, 2 ** 68, true)
-> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "rejects floats as keys" do
it "raises ArgumentError when Float is used as a key" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, 4.2, true)
-> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "rejects booleans as keys" do
it "raises ArgumentError when Symbol is used as a key" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, true, true)
should_not_accept(map, false, true)
-> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "rejects nil as keys" do
it "raises ArgumentError when true is used as a key" do
map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, nil, true)
-> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "raises ArgumentError when false is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
it "raises ArgumentError when nil is used as a key" do
map = ObjectSpace::WeakKeyMap.new
-> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
end
end
end

View File

@ -0,0 +1,5 @@
module WeakKeyMapSpecs
class KeyWithPrivateHash
private :hash
end
end

View File

@ -9,6 +9,20 @@ ruby_version_is "3.3" do
map[key1] = true
map.getkey(key2).should equal(key1)
map.getkey("X").should == nil
key1.should == "A" # keep the key alive until here to keep the map entry
key2.should == "A" # keep the key alive until here to keep the map entry
end
it "returns nil when a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new
map.getkey(1).should == nil
map.getkey(1.0).should == nil
map.getkey(:a).should == nil
map.getkey(true).should == nil
map.getkey(false).should == nil
map.getkey(nil).should == nil
end
end
end

View File

@ -12,6 +12,10 @@ ruby_version_is "3.3" do
map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
map[key3] = 3
map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
key1.should == "foo" # keep the key alive until here to keep the map entry
key2.should == "bar" # keep the key alive until here to keep the map entry
key3.should == "bar" # keep the key alive until here to keep the map entry
end
end
end

View File

@ -29,5 +29,16 @@ ruby_version_is "3.3" do
map[key] = nil
map.key?(key).should == true
end
it "returns false when a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new
map.key?(1).should == false
map.key?(1.0).should == false
map.key?(:a).should == false
map.key?(true).should == false
map.key?(false).should == false
map.key?(nil).should == false
end
end
end

View File

@ -64,7 +64,7 @@ describe "Proc#parameters" do
end
it "regards keyword parameters in lambdas as required" do
eval("lambda {|x:| }").parameters.first.first.should == :keyreq
-> x: { }.parameters.first.first.should == :keyreq
end
it "sets the first element of each sub-Array to :rest for parameters prefixed with asterisks" do
@ -130,10 +130,8 @@ describe "Proc#parameters" do
end
end
ruby_version_is '3.1' do
it "adds block arg with name & for anonymous block argument" do
eval('-> & {}.parameters').should == [[:block, :&]]
end
-> & {}.parameters.should == [[:block, :&]]
end
it "does not add locals as block options with a block and splat" do

View File

@ -1,7 +1,6 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "Process._fork" do
describe "Process._fork" do
it "for #respond_to? returns the same as Process.respond_to?(:fork)" do
Process.respond_to?(:_fork).should == Process.respond_to?(:fork)
end
@ -20,5 +19,4 @@ ruby_version_is "3.1" do
pid.should equal(42)
end
end
end
end

View File

@ -0,0 +1,17 @@
require_relative '../../../spec_helper'
describe "Process::Tms#cstime" do
it "returns cstime attribute" do
cstime = Object.new
Process::Tms.new(nil, nil, nil, cstime).cstime.should == cstime
end
end
describe "Process::Tms#cstime=" do
it "assigns a value to the cstime attribute" do
cstime = Object.new
tms = Process::Tms.new
tms.cstime = cstime
tms.cstime.should == cstime
end
end

View File

@ -0,0 +1,17 @@
require_relative '../../../spec_helper'
describe "Process::Tms#cutime" do
it "returns cutime attribute" do
cutime = Object.new
Process::Tms.new(nil, nil, cutime, nil).cutime.should == cutime
end
end
describe "Process::Tms#cutime=" do
it "assigns a value to the cutime attribute" do
cutime = Object.new
tms = Process::Tms.new
tms.cutime = cutime
tms.cutime.should == cutime
end
end

View File

@ -0,0 +1,17 @@
require_relative '../../../spec_helper'
describe "Process::Tms#stime" do
it "returns stime attribute" do
stime = Object.new
Process::Tms.new(nil, stime, nil, nil).stime.should == stime
end
end
describe "Process::Tms#stime=" do
it "assigns a value to the stime attribute" do
stime = Object.new
tms = Process::Tms.new
tms.stime = stime
tms.stime.should == stime
end
end

View File

@ -0,0 +1,17 @@
require_relative '../../../spec_helper'
describe "Process::Tms#utime" do
it "returns utime attribute" do
utime = Object.new
Process::Tms.new(utime, nil, nil, nil).utime.should == utime
end
end
describe "Process::Tms#utime=" do
it "assigns a value to the ctime attribute" do
utime = Object.new
tms = Process::Tms.new
tms.utime = utime
tms.utime.should == utime
end
end

View File

@ -11,7 +11,6 @@ describe "Queue#initialize" do
Queue.private_instance_methods.include?(:initialize).should == true
end
ruby_version_is '3.1' do
it "adds all elements of the passed Enumerable to self" do
q = Queue.new([1, 2, 3])
q.size.should == 3
@ -58,5 +57,4 @@ describe "Queue#initialize" do
-> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)")
end
end
end

View File

@ -40,21 +40,21 @@ describe "Range#each" do
it "works with endless ranges" do
a = []
eval("(-2..)").each { |x| break if x > 2; a << x }
(-2..).each { |x| break if x > 2; a << x }
a.should == [-2, -1, 0, 1, 2]
a = []
eval("(-2...)").each { |x| break if x > 2; a << x }
(-2...).each { |x| break if x > 2; a << x }
a.should == [-2, -1, 0, 1, 2]
end
it "works with String endless ranges" do
a = []
eval("('A'..)").each { |x| break if x > "D"; a << x }
('A'..).each { |x| break if x > "D"; a << x }
a.should == ["A", "B", "C", "D"]
a = []
eval("('A'...)").each { |x| break if x > "D"; a << x }
('A'...).each { |x| break if x > "D"; a << x }
a.should == ["A", "B", "C", "D"]
end
@ -82,7 +82,6 @@ describe "Range#each" do
enum.to_a.should == [1, 2, 3]
end
ruby_version_is "3.1" do
it "supports Time objects that respond to #succ" do
t = Time.utc(1970)
def t.succ; self + 1 end
@ -92,18 +91,6 @@ describe "Range#each" do
(t..t_succ).to_a.should == [Time.utc(1970), Time.utc(1970, nil, nil, nil, nil, 1)]
(t...t_succ).to_a.should == [Time.utc(1970)]
end
end
ruby_version_is ""..."3.1" do
it "raises a TypeError if the first element is a Time object even if it responds to #succ" do
t = Time.utc(1970)
def t.succ; self + 1 end
t_succ = t.succ
def t_succ.succ; self + 1; end
-> { (t..t_succ).each { |i| i } }.should raise_error(TypeError)
end
end
it "passes each Symbol element by using #succ" do
(:aa..:ac).each.to_a.should == [:aa, :ab, :ac]

View File

@ -20,8 +20,8 @@ describe :range_cover_and_include, shared: true do
end
it "returns true if other is an element of self for endless ranges" do
eval("(1..)").send(@method, 2.4).should == true
eval("(0.5...)").send(@method, 2.4).should == true
(1..).send(@method, 2.4).should == true
(0.5...).send(@method, 2.4).should == true
end
it "returns true if other is an element of self for beginless ranges" do
@ -29,6 +29,17 @@ describe :range_cover_and_include, shared: true do
(...10.5).send(@method, 2.4).should == true
end
it "returns false if values are not comparable" do
(1..10).send(@method, nil).should == false
(1...10).send(@method, nil).should == false
(..10).send(@method, nil).should == false
(...10).send(@method, nil).should == false
(1..).send(@method, nil).should == false
(1...).send(@method, nil).should == false
end
it "compares values using <=>" do
rng = (1..5)
m = mock("int")

View File

@ -322,14 +322,12 @@ describe "Range#step" do
ScratchPad.recorded.should eql([1.0, 2.8, 4.6])
end
ruby_version_is '3.1' do
it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612
(1.0...55.6).step(18.2) { |x| ScratchPad << x }
ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994])
(1.0...55.6).step(18.2).size.should == 4
end
end
it "handles infinite values at either end" do
(-Float::INFINITY...0.0).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
@ -408,108 +406,108 @@ describe "Range#step" do
describe "with an endless range" do
describe "and Integer values" do
it "yield Integer values incremented by 1 when not passed a step" do
eval("(-2..)").step { |x| break if x > 2; ScratchPad << x }
(-2..).step { |x| break if x > 2; ScratchPad << x }
ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
ScratchPad.record []
eval("(-2...)").step { |x| break if x > 2; ScratchPad << x }
(-2...).step { |x| break if x > 2; ScratchPad << x }
ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
end
it "yields Integer values incremented by an Integer step" do
eval("(-5..)").step(2) { |x| break if x > 3; ScratchPad << x }
(-5..).step(2) { |x| break if x > 3; ScratchPad << x }
ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
ScratchPad.record []
eval("(-5...)").step(2) { |x| break if x > 3; ScratchPad << x }
(-5...).step(2) { |x| break if x > 3; ScratchPad << x }
ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
end
it "yields Float values incremented by a Float step" do
eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x }
(-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
ScratchPad.record []
eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x }
(-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
end
end
describe "and Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
eval("(-2.0..)").step { |x| break if x > 1.5; ScratchPad << x }
(-2.0..).step { |x| break if x > 1.5; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
ScratchPad.record []
eval("(-2.0...)").step { |x| break if x > 1.5; ScratchPad << x }
(-2.0...).step { |x| break if x > 1.5; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
eval("(-5.0..)").step(2) { |x| break if x > 3.5; ScratchPad << x }
(-5.0..).step(2) { |x| break if x > 3.5; ScratchPad << x }
ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
ScratchPad.record []
eval("(-5.0...)").step(2) { |x| break if x > 3.5; ScratchPad << x }
(-5.0...).step(2) { |x| break if x > 3.5; ScratchPad << x }
ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
eval("(-1.0..)").step(0.5) { |x| break if x > 0.6; ScratchPad << x }
(-1.0..).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
ScratchPad.record []
eval("(-1.0...)").step(0.5) { |x| break if x > 0.6; ScratchPad << x }
(-1.0...).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
end
it "handles infinite values at the start" do
eval("(-Float::INFINITY..)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
(-Float::INFINITY..).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
eval("(-Float::INFINITY...)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
(-Float::INFINITY...).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
end
end
describe "and String values" do
it "yields String values incremented by #succ and less than or equal to end when not passed a step" do
eval("('A'..)").step { |x| break if x > "D"; ScratchPad << x }
('A'..).step { |x| break if x > "D"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "B", "C", "D"]
ScratchPad.record []
eval("('A'...)").step { |x| break if x > "D"; ScratchPad << x }
('A'...).step { |x| break if x > "D"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "B", "C", "D"]
end
it "yields String values incremented by #succ called Integer step times" do
eval("('A'..)").step(2) { |x| break if x > "F"; ScratchPad << x }
('A'..).step(2) { |x| break if x > "F"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "C", "E"]
ScratchPad.record []
eval("('A'...)").step(2) { |x| break if x > "F"; ScratchPad << x }
('A'...).step(2) { |x| break if x > "F"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "C", "E"]
end
it "raises a TypeError when passed a Float step" do
-> { eval("('A'..)").step(2.0) { } }.should raise_error(TypeError)
-> { eval("('A'...)").step(2.0) { } }.should raise_error(TypeError)
-> { ('A'..).step(2.0) { } }.should raise_error(TypeError)
-> { ('A'...).step(2.0) { } }.should raise_error(TypeError)
end
ruby_version_is "3.4" do
it "yields String values adjusted by step" do
eval("('A'..)").step("A") { |x| break if x > "AAA"; ScratchPad << x }
('A'..).step("A") { |x| break if x > "AAA"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "AA", "AAA"]
ScratchPad.record []
eval("('A'...)").step("A") { |x| break if x > "AAA"; ScratchPad << x }
('A'...).step("A") { |x| break if x > "AAA"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "AA", "AAA"]
end
it "raises a TypeError when passed an incompatible type step" do
-> { eval("('A'..)").step([]) { } }.should raise_error(TypeError)
-> { eval("('A'...)").step([]) { } }.should raise_error(TypeError)
-> { ('A'..).step([]) { } }.should raise_error(TypeError)
-> { ('A'...).step([]) { } }.should raise_error(TypeError)
end
end
end

View File

@ -2,7 +2,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Refinement#import_methods" do
ruby_version_is "3.1" do
context "when methods are defined in Ruby code" do
it "imports methods" do
str_utils = Module.new do
@ -265,5 +264,4 @@ describe "Refinement#import_methods" do
end
end
end
end
end

View File

@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "Refinement#include" do
ruby_version_is "3.1"..."3.2" do
ruby_version_is ""..."3.2" do
it "warns about deprecation" do
Module.new do
refine String do

Some files were not shown because too many files have changed in this diff Show More