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) * [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor) * [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)
ruby/spec describes the behavior of Ruby 3.0 and more recent Ruby versions. 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.0.x, 3.1.x, 3.2.x, etc), and those are tested in CI. 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 ### 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.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.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 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 ### Running the specs

View File

@ -2,8 +2,8 @@ require_relative '../spec_helper'
describe "ruby -U" do describe "ruby -U" do
it "sets Encoding.default_internal to UTF-8" do it "sets Encoding.default_internal to UTF-8" do
ruby_exe('print Encoding.default_internal.name', ruby_exe('print Encoding.default_internal.name',
options: '-U').should == 'UTF-8' options: '-U').should == 'UTF-8'
end end
it "sets Encoding.default_internal to UTF-8 when RUBYOPT is empty or only spaces" do it "sets Encoding.default_internal to UTF-8 when RUBYOPT is empty or only spaces" do
@ -14,25 +14,25 @@ describe "ruby -U" do
end end
it "does nothing different if specified multiple times" do it "does nothing different if specified multiple times" do
ruby_exe('print Encoding.default_internal.name', ruby_exe('print Encoding.default_internal.name',
options: '-U -U').should == 'UTF-8' options: '-U -U').should == 'UTF-8'
end end
it "is overruled by Encoding.default_internal=" do it "is overruled by Encoding.default_internal=" do
ruby_exe('Encoding.default_internal="ascii"; print Encoding.default_internal.name', ruby_exe('Encoding.default_internal="ascii"; print Encoding.default_internal.name',
options: '-U').should == 'US-ASCII' options: '-U').should == 'US-ASCII'
end end
it "does not affect the default external encoding" do it "does not affect the default external encoding" do
ruby_exe('Encoding.default_external="ascii"; print Encoding.default_external.name', ruby_exe('Encoding.default_external="ascii"; print Encoding.default_external.name',
options: '-U').should == 'US-ASCII' options: '-U').should == 'US-ASCII'
end end
it "does not affect the source encoding" do it "does not affect the source encoding" do
ruby_exe("print __ENCODING__.name", ruby_exe("print __ENCODING__.name",
options: '-U -KE').should == 'EUC-JP' options: '-U -KE').should == 'EUC-JP'
ruby_exe("print __ENCODING__.name", ruby_exe("print __ENCODING__.name",
options: '-KE -U').should == 'EUC-JP' options: '-KE -U').should == 'EUC-JP'
end end
# I assume IO redirection will break on Windows... # I assume IO redirection will break on Windows...

View File

@ -7,7 +7,7 @@ describe "Array#drop" do
end end
it "raises an ArgumentError if the number of elements specified is negative" do it "raises an ArgumentError if the number of elements specified is negative" do
-> { [1, 2].drop(-3) }.should raise_error(ArgumentError) -> { [1, 2].drop(-3) }.should raise_error(ArgumentError)
end end
it "returns an empty Array if all elements are dropped" do it "returns an empty Array if all elements are dropped" do

View File

@ -2,65 +2,63 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
describe 'Array#intersect?' do 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
describe 'when at least one element in two Arrays is the same' do it 'returns true' do
it 'returns true' do [1, 2].intersect?([2, 3, 4]).should == true
[1, 2].intersect?([2, 3, 4]).should == true [2, 3, 4].intersect?([1, 2]).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
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])
[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)
[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].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 "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
it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end end
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
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])
[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)
[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].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 "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
it "has semantic of !(a & b).empty?" do
[].intersect?([]).should == false
[nil].intersect?([nil]).should == true
end
end end

View File

@ -141,22 +141,11 @@ describe "BasicObject#instance_eval" do
caller.get_constant_with_string(receiver).should == :singleton_class caller.get_constant_with_string(receiver).should == :singleton_class
end end
ruby_version_is ""..."3.1" do it "looks in the receiver class next" do
it "looks in the caller scope next" do receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
caller.get_constant_with_string(receiver).should == :Caller caller.get_constant_with_string(receiver).should == :Receiver
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 end
it "looks in the caller class next" do it "looks in the caller class next" do

View File

@ -96,6 +96,8 @@ describe "BasicObject#singleton_method_added" do
end end
}.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/) }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/)
end end
ensure
BasicObjectSpecs.send(:remove_const, :NoSingletonMethodAdded)
end end
it "raises NoMethodError for a singleton instance" do 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 it "stores the new name if assigned to a constant" do
CoreClassSpecs::RecordCopy = CoreClassSpecs::Record.dup CoreClassSpecs::RecordCopy = CoreClassSpecs::Record.dup
CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy" CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy"
ensure
CoreClassSpecs.send(:remove_const, :RecordCopy)
end end
it "raises TypeError if called on BasicObject" do it "raises TypeError if called on BasicObject" do

View File

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

View File

@ -1,87 +1,85 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative '../module/fixtures/classes' 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
it "returns a list of classes directly inheriting from self" do assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
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)
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
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
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
it "does not return singleton classes" do
a = Class.new
a_obj = a.new
def a_obj.force_singleton_class
42
end end
it "does not return included modules from the parent" do a.subclasses.should_not include(a_obj.singleton_class)
parent = Class.new end
child = Class.new(parent)
mod = Module.new
parent.include(mod)
assert_subclasses(parent, [child]) it "has 1 entry per module or class" do
end ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
end
it "does not return included modules from the child" do it "works when creating subclasses concurrently" do
parent = Class.new t = 16
child = Class.new(parent) n = 1000
mod = Module.new go = false
parent.include(mod) superclass = Class.new
assert_subclasses(parent, [child]) threads = t.times.map do
end Thread.new do
Thread.pass until go
it "does not return prepended modules from the parent" do n.times.map do
parent = Class.new Class.new(superclass)
child = Class.new(parent)
mod = Module.new
parent.prepend(mod)
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)
assert_subclasses(parent, [child])
end
it "does not return singleton classes" do
a = Class.new
a_obj = a.new
def a_obj.force_singleton_class
42
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
end end
end end
go = true
classes = threads.map(&:value)
superclass.subclasses.size.should == t * n
superclass.subclasses.each { |c| c.should be_kind_of(Class) }
end end
def assert_subclasses(mod,subclasses) go = true
mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect) classes = threads.map(&:value)
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 end
end end

View File

@ -24,15 +24,15 @@ describe :complex_rect, shared: true do
end end
it "returns the real part of self as the first element" do it "returns the real part of self as the first element" do
@numbers.each do |number| @numbers.each do |number|
number.send(@method).first.should == number.real number.send(@method).first.should == number.real
end end
end end
it "returns the imaginary part of self as the last element" do it "returns the imaginary part of self as the last element" do
@numbers.each do |number| @numbers.each do |number|
number.send(@method).last.should == number.imaginary number.send(@method).last.should == number.imaginary
end end
end end
it "raises an ArgumentError if given any arguments" do it "raises an ArgumentError if given any arguments" do

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 module DataSpecs
guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
Measure = Data.define(:amount, :unit) Measure = Data.define(:amount, :unit)
class MeasureWithOverriddenName < Measure
def self.name
"A"
end
end
class DataSubclass < Data; end
end 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 dir.close
end 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 it "does not raise an Errno::ENOENT if the original directory no longer exists" do
dir_name1 = tmp('testdir1') dir_name1 = tmp('testdir1')
dir_name2 = tmp('testdir2') dir_name2 = tmp('testdir2')

View File

@ -89,31 +89,15 @@ describe "Dir.glob" do
Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected
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
it "recursively matches files and directories in nested dot subdirectory with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do expected = %w[
expected = %w[ nested/.
nested/. nested/.dotsubir
nested/.dotsubir nested/.dotsubir/.dotfile
nested/.dotsubir/. nested/.dotsubir/nondotfile
nested/.dotsubir/.dotfile ]
nested/.dotsubir/nondotfile
]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort 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/.
nested/.dotsubir
nested/.dotsubir/.dotfile
nested/.dotsubir/nondotfile
]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
end end
# This is a separate case to check **/ coming after a constant # This is a separate case to check **/ coming after a constant
@ -260,34 +244,31 @@ describe "Dir.glob" do
Dir.glob('**/.*', base: "deeply/nested").sort.should == expected Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
end end
# < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...] it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
ruby_version_is '3.1' do expected = %w[
it "handles **/.* with base keyword argument and FNM_DOTMATCH" do .
expected = %w[ .dotfile.ext
. directory/structure/.ext
.dotfile.ext ].sort
directory/structure/.ext
].sort
Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end end
it "handles **/** with base keyword argument and FNM_DOTMATCH" do it "handles **/** with base keyword argument and FNM_DOTMATCH" do
expected = %w[ expected = %w[
. .
.dotfile.ext .dotfile.ext
directory directory
directory/structure directory/structure
directory/structure/.ext directory/structure/.ext
directory/structure/bar directory/structure/bar
directory/structure/baz directory/structure/baz
directory/structure/file_one directory/structure/file_one
directory/structure/file_one.ext directory/structure/file_one.ext
directory/structure/foo directory/structure/foo
].sort ].sort
Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end
end end
it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do

View File

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

View File

@ -16,8 +16,8 @@ describe "Encoding::Converter#finish" do
end end
it "returns the last part of the converted String if it hasn't already" do it "returns the last part of the converted String if it hasn't already" do
@ec.convert("\u{9999}").should == "\e$B9a".dup.force_encoding('iso-2022-jp') @ec.convert("\u{9999}").should == "\e$B9a".dup.force_encoding('iso-2022-jp')
@ec.finish.should == "\e(B".dup.force_encoding('iso-2022-jp') @ec.finish.should == "\e(B".dup.force_encoding('iso-2022-jp')
end end
it "returns a String in the destination encoding" do it "returns a String in the destination encoding" do

View File

@ -23,8 +23,8 @@ describe "Encoding::Converter.search_convpath" do
end end
it "raises an Encoding::ConverterNotFoundError if no conversion path exists" do it "raises an Encoding::ConverterNotFoundError if no conversion path exists" do
-> do -> do
Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule) Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule)
end.should raise_error(Encoding::ConverterNotFoundError) end.should raise_error(Encoding::ConverterNotFoundError)
end end
end end

View File

@ -1,11 +1,9 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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
it 'returns array without nil elements' do arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true)
arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true) arr.compact.should == [1, 2, true]
arr.compact.should == [1, 2, true]
end
end end
end end

View File

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

View File

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

View File

@ -32,62 +32,60 @@ describe "Enumerable#tally" do
end end
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
before :each do ScratchPad.record []
ScratchPad.record [] end
end
it "returns a hash with counts according to the value" do it "returns a hash with counts according to the value" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1} enum.tally({ 'foo' => 1 }).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
end end
it "returns the given hash" do it "returns the given hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 } hash = { 'foo' => 1 }
enum.tally(hash).should equal(hash) enum.tally(hash).should equal(hash)
end end
it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
object = Object.new object = Object.new
def object.to_hash; { 'foo' => 1 }; end def object.to_hash; { 'foo' => 1 }; end
enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1} enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
end end
it "raises a FrozenError and does not update the given hash when the hash is frozen" do it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze hash = { 'foo' => 1 }.freeze
-> { enum.tally(hash) }.should raise_error(FrozenError) -> { enum.tally(hash) }.should raise_error(FrozenError)
hash.should == { 'foo' => 1 } hash.should == { 'foo' => 1 }
end end
it "raises a FrozenError even if enumerable is empty" do it "raises a FrozenError even if enumerable is empty" do
enum = EnumerableSpecs::Numerous.new() enum = EnumerableSpecs::Numerous.new()
hash = { 'foo' => 1 }.freeze hash = { 'foo' => 1 }.freeze
-> { enum.tally(hash) }.should raise_error(FrozenError) -> { enum.tally(hash) }.should raise_error(FrozenError)
end end
it "does not call given block" do it "does not call given block" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v } enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
ScratchPad.recorded.should == [] ScratchPad.recorded.should == []
end end
it "ignores the default value" do it "ignores the default value" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally(Hash.new(100)).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1} enum.tally(Hash.new(100)).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
end end
it "ignores the default proc" do it "ignores the default proc" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally(Hash.new {100}).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1} enum.tally(Hash.new {100}).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
end end
it "needs the values counting each elements to be an integer" do it "needs the values counting each elements to be an integer" do
enum = EnumerableSpecs::Numerous.new('foo') enum = EnumerableSpecs::Numerous.new('foo')
-> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError) -> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
end
end end
end end

View File

@ -1,16 +1,14 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative 'fixtures/classes' 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
it 'returns array without nil elements' do arr = [1, nil, 3, false, 5].to_enum.lazy.compact
arr = [1, nil, 3, false, 5].to_enum.lazy.compact arr.should be_an_instance_of(Enumerator::Lazy)
arr.should be_an_instance_of(Enumerator::Lazy) arr.force.should == [1, 3, false, 5]
arr.force.should == [1, 3, false, 5] end
end
it "sets #size to nil" do it "sets #size to nil" do
Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
end
end end
end end

View File

@ -9,16 +9,11 @@ describe "Enumerator::Lazy" do
it "defines lazy versions of a whitelist of Enumerator methods" do it "defines lazy versions of a whitelist of Enumerator methods" do
lazy_methods = [ 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, :find_all, :flat_map, :force, :grep, :grep_v, :lazy, :map, :reject,
:select, :slice_after, :slice_before, :slice_when, :take, :take_while, :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) Enumerator::Lazy.instance_methods(false).should include(*lazy_methods)
end end

View File

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

View File

@ -47,7 +47,7 @@ describe "ENV.fetch" do
it "warns on block and default parameter given" do it "warns on block and default parameter given" do
-> do -> do
ENV.fetch("foo", "default") { "bar" }.should == "bar" ENV.fetch("foo", "default") { "bar" }.should == "bar"
end.should complain(/block supersedes default value argument/) end.should complain(/block supersedes default value argument/)
end end

View File

@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/length' require_relative 'shared/length'
describe "ENV.length" do describe "ENV.length" do
it_behaves_like :env_length, :length it_behaves_like :env_length, :length
end end

View File

@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/length' require_relative 'shared/length'
describe "ENV.size" do describe "ENV.size" do
it_behaves_like :env_length, :size it_behaves_like :env_length, :size
end end

View File

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

View File

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

View File

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

View File

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

View File

@ -1,14 +1,6 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require 'fiber'
describe "Fiber.current" do 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 it "returns the root Fiber when called outside of a Fiber" do
root = Fiber.current root = Fiber.current
root.should be_an_instance_of(Fiber) root.should be_an_instance_of(Fiber)

View File

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

View File

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

View File

@ -1,5 +1,5 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative '../../shared/fiber/resume' require_relative 'shared/resume'
describe "Fiber#resume" do describe "Fiber#resume" do
it_behaves_like :fiber_resume, :resume it_behaves_like :fiber_resume, :resume
@ -67,4 +67,17 @@ describe "Fiber#resume" do
ruby_exe(code).should == "ensure executed\n" ruby_exe(code).should == "ensure executed\n"
end 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 end

View File

@ -1,7 +1,7 @@
describe :fiber_resume, shared: true do describe :fiber_resume, shared: true do
it "can be invoked from the root Fiber" do it "can be invoked from the root Fiber" do
fiber = Fiber.new { :fiber } fiber = Fiber.new { :fiber }
fiber.send(@method).should == :fiber fiber.send(@method).should == :fiber
end end
it "raises a FiberError if invoked from a different Thread" do it "raises a FiberError if invoked from a different Thread" do

View File

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

View File

@ -11,34 +11,32 @@ describe "File.dirname" do
File.dirname('/foo/foo').should == '/foo' File.dirname('/foo/foo').should == '/foo'
end end
ruby_version_is '3.1' do context "when level is passed" do
context "when level is passed" do it "returns all the components of filename except the last parts by the level" do
it "returns all the components of filename except the last parts by the level" do File.dirname('/home/jason', 2).should == '/'
File.dirname('/home/jason', 2).should == '/' File.dirname('/home/jason/poot.txt', 2).should == '/home'
File.dirname('/home/jason/poot.txt', 2).should == '/home' end
end
it "returns the same String if the level is 0" do it "returns the same String if the level is 0" do
File.dirname('poot.txt', 0).should == 'poot.txt' File.dirname('poot.txt', 0).should == 'poot.txt'
File.dirname('/', 0).should == '/' File.dirname('/', 0).should == '/'
end end
it "raises ArgumentError if the level is negative" do it "raises ArgumentError if the level is negative" do
-> { -> {
File.dirname('/home/jason', -1) File.dirname('/home/jason', -1)
}.should raise_error(ArgumentError, "negative level: -1") }.should raise_error(ArgumentError, "negative level: -1")
end end
it "returns '/' when level exceeds the number of segments in the path" do it "returns '/' when level exceeds the number of segments in the path" do
File.dirname("/home/jason", 100).should == '/' File.dirname("/home/jason", 100).should == '/'
end end
it "calls #to_int if passed not numeric value" do it "calls #to_int if passed not numeric value" do
object = Object.new object = Object.new
def object.to_int; 2; end def object.to_int; 2; end
File.dirname("/a/b/c/d", object).should == '/a/b' File.dirname("/a/b/c/d", object).should == '/a/b'
end
end end
end end
@ -65,19 +63,19 @@ describe "File.dirname" do
end end
it "returns all the components of filename except the last one (edge cases on all platforms)" do it "returns all the components of filename except the last one (edge cases on all platforms)" do
File.dirname("").should == "." File.dirname("").should == "."
File.dirname(".").should == "." File.dirname(".").should == "."
File.dirname("./").should == "." File.dirname("./").should == "."
File.dirname("./b/./").should == "./b" File.dirname("./b/./").should == "./b"
File.dirname("..").should == "." File.dirname("..").should == "."
File.dirname("../").should == "." File.dirname("../").should == "."
File.dirname("/").should == "/" File.dirname("/").should == "/"
File.dirname("/.").should == "/" File.dirname("/.").should == "/"
File.dirname("/foo/").should == "/" File.dirname("/foo/").should == "/"
File.dirname("/foo/.").should == "/foo" File.dirname("/foo/.").should == "/foo"
File.dirname("/foo/./").should == "/foo" File.dirname("/foo/./").should == "/foo"
File.dirname("/foo/../.").should == "/foo/.." File.dirname("/foo/../.").should == "/foo/.."
File.dirname("foo/../").should == "foo" File.dirname("foo/../").should == "foo"
end end
platform_is_not :windows do platform_is_not :windows do

View File

@ -77,18 +77,6 @@ describe :file_path, shared: true do
after :each do after :each do
rm_r @dir rm_r @dir
end 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 end
end end

View File

@ -91,7 +91,7 @@ describe "Float#<=>" do
it "returns 1 when self is Infinity and other is infinite?=nil (which means finite)" do it "returns 1 when self is Infinity and other is infinite?=nil (which means finite)" do
obj = Object.new obj = Object.new
def obj.infinite? def obj.infinite?
nil nil
end end
(infinity_value <=> obj).should == 1 (infinity_value <=> obj).should == 1
end end

View File

@ -30,6 +30,11 @@ describe "Float#round" do
12.345678.round(3.999).should == 12.346 12.345678.round(3.999).should == 12.346
end 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 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) 0.8346268.round(-1).should eql(0)
end end
@ -68,6 +73,10 @@ describe "Float#round" do
0.42.round(2.0**30).should == 0.42 0.42.round(2.0**30).should == 0.42
end 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 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 )
-2.5e20.round(-20).should eql( -3 * 10 ** 20 ) -2.5e20.round(-20).should eql( -3 * 10 ** 20 )

View File

@ -1,19 +1,17 @@
require_relative '../../spec_helper' 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
before :each do @default = GC.measure_total_time
@default = GC.measure_total_time end
end
after :each do after :each do
GC.measure_total_time = @default GC.measure_total_time = @default
end end
it "can set and get a boolean value" do it "can set and get a boolean value" do
original = GC.measure_total_time original = GC.measure_total_time
GC.measure_total_time = !original GC.measure_total_time = !original
GC.measure_total_time.should == !original GC.measure_total_time.should == !original
end
end end
end end

View File

@ -1,15 +1,13 @@
require_relative '../../spec_helper' 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
it "returns an Integer" do GC.total_time.should be_kind_of(Integer)
GC.total_time.should be_kind_of(Integer) end
end
it "increases as collections are run" do it "increases as collections are run" do
time_before = GC.total_time time_before = GC.total_time
GC.start GC.start
GC.total_time.should >= time_before GC.total_time.should >= time_before
end
end end
end end

View File

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

View File

@ -91,9 +91,9 @@ describe :hash_store, shared: true do
end end
it "does not raise an exception if changing the value of an existing key during iteration" do it "does not raise an exception if changing the value of an existing key during iteration" do
hash = {1 => 2, 3 => 4, 5 => 6} hash = {1 => 2, 3 => 4, 5 => 6}
hash.each { hash.send(@method, 1, :foo) } hash.each { hash.send(@method, 1, :foo) }
hash.should == {1 => :foo, 3 => 4, 5 => 6} hash.should == {1 => :foo, 3 => 4, 5 => 6}
end end
it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do

View File

@ -76,24 +76,12 @@ describe "Hash#transform_keys!" do
@hash.should == { b: 1, c: 2, d: 3, e: 4 } @hash.should == { b: 1, c: 2, d: 3, e: 4 }
end end
ruby_version_is ""..."3.0.2" do # https://bugs.ruby-lang.org/issues/17735 it "returns the processed keys and non evaluated keys if we break from the block" do
it "returns the processed keys if we break from the block" do @hash.transform_keys! do |v|
@hash.transform_keys! do |v| break if v == :c
break if v == :c v.succ
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
v.succ
end
@hash.should == { b: 1, c: 2, d: 4 }
end end
@hash.should == { b: 1, c: 2, d: 4 }
end end
it "keeps later pair if new keys conflict" do it "keeps later pair if new keys conflict" do
@ -129,7 +117,7 @@ describe "Hash#transform_keys!" do
end end
it "raises a FrozenError on hash argument" do it "raises a FrozenError on hash argument" do
->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError) ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
end end
context "when no block is given" do context "when no block is given" do

View File

@ -1,50 +1,48 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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
it "returns the argument if it's an Integer" do x = 42
x = 42 Integer.try_convert(x).should equal(x)
Integer.try_convert(x).should equal(x) end
end
it "returns nil when the argument does not respond to #to_int" do it "returns nil when the argument does not respond to #to_int" do
Integer.try_convert(Object.new).should be_nil Integer.try_convert(Object.new).should be_nil
end end
it "sends #to_int to the argument and returns the result if it's nil" do it "sends #to_int to the argument and returns the result if it's nil" do
obj = mock("to_int") obj = mock("to_int")
obj.should_receive(:to_int).and_return(nil) obj.should_receive(:to_int).and_return(nil)
Integer.try_convert(obj).should be_nil Integer.try_convert(obj).should be_nil
end end
it "sends #to_int to the argument and returns the result if it's an Integer" do it "sends #to_int to the argument and returns the result if it's an Integer" do
x = 234 x = 234
obj = mock("to_int") obj = mock("to_int")
obj.should_receive(:to_int).and_return(x) obj.should_receive(:to_int).and_return(x)
Integer.try_convert(obj).should equal(x) Integer.try_convert(obj).should equal(x)
end end
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
obj = mock("to_int") obj = mock("to_int")
obj.should_receive(:to_int).and_return(Object.new) obj.should_receive(:to_int).and_return(Object.new)
-> { -> {
Integer.try_convert obj Integer.try_convert obj
}.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)") }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
end end
it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
obj = mock("to_int") obj = mock("to_int")
obj.should_receive(:to_int).and_return("A String") obj.should_receive(:to_int).and_return("A String")
-> { -> {
Integer.try_convert obj Integer.try_convert obj
}.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)") }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
end end
it "does not rescue exceptions raised by #to_int" do it "does not rescue exceptions raised by #to_int" do
obj = mock("to_int") obj = mock("to_int")
obj.should_receive(:to_int).and_raise(RuntimeError) obj.should_receive(:to_int).and_raise(RuntimeError)
-> { Integer.try_convert obj }.should raise_error(RuntimeError) -> { Integer.try_convert obj }.should raise_error(RuntimeError)
end
end end
end end

View File

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

View File

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

View File

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

View File

@ -43,7 +43,7 @@ platform_is_not :windows do
it "checks if the file is writable if writing zero bytes" do it "checks if the file is writable if writing zero bytes" do
-> { -> {
@readonly_file.write_nonblock("") @readonly_file.write_nonblock("")
}.should raise_error(IOError) }.should raise_error(IOError)
end end
end end

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 it "returns true if and only if a block is supplied" do
@object.accept_block {}.should == true @object.accept_block {}.should == true
@object.accept_block_as_argument {}.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.should == false
@object.accept_block_as_argument.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 end
# Clarify: Based on http://www.ruby-forum.com/topic/137822 it appears # Clarify: Based on http://www.ruby-forum.com/topic/137822 it appears
# that Matz wanted this to be true in 1.9. # 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 it "returns false when a method defined by define_method is called with a block" do
@object.defined_block {}.should == false @object.defined_block {}.should == false
@object.defined_block_inside_block {}.should == false
end end
end end

View File

@ -313,6 +313,8 @@ CODE
eval(code) eval(code)
EvalSpecs.constants(false).should include(:"") EvalSpecs.constants(false).should include(:"")
EvalSpecs::.should == 3.14 EvalSpecs::.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπ)
end end
it "allows an emacs-style magic comment encoding" do it "allows an emacs-style magic comment encoding" do
@ -326,6 +328,8 @@ CODE
eval(code) eval(code)
EvalSpecs.constants(false).should include(:"Vπemacs") EvalSpecs.constants(false).should include(:"Vπemacs")
EvalSpecs::Vπemacs.should == 3.14 EvalSpecs::Vπemacs.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπemacs)
end end
it "allows spaces before the magic encoding comment" do it "allows spaces before the magic encoding comment" do
@ -339,6 +343,8 @@ CODE
eval(code) eval(code)
EvalSpecs.constants(false).should include(:"Vπspaces") EvalSpecs.constants(false).should include(:"Vπspaces")
EvalSpecs::Vπspaces.should == 3.14 EvalSpecs::Vπspaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπspaces)
end end
it "allows a shebang line before the magic encoding comment" do it "allows a shebang line before the magic encoding comment" do
@ -353,6 +359,8 @@ CODE
eval(code) eval(code)
EvalSpecs.constants(false).should include(:"Vπshebang") EvalSpecs.constants(false).should include(:"Vπshebang")
EvalSpecs::Vπshebang.should == 3.14 EvalSpecs::Vπshebang.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang)
end end
it "allows a shebang line and some spaces before the magic encoding comment" do it "allows a shebang line and some spaces before the magic encoding comment" do
@ -367,6 +375,8 @@ CODE
eval(code) eval(code)
EvalSpecs.constants(false).should include(:"Vπshebang_spaces") EvalSpecs.constants(false).should include(:"Vπshebang_spaces")
EvalSpecs::Vπshebang_spaces.should == 3.14 EvalSpecs::Vπshebang_spaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang_spaces)
end end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do 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.should == "frozen"
EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8 EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
EvalSpecs::Vπstring.frozen?.should == !frozen_string_default EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
ensure
EvalSpecs.send(:remove_const, :Vπstring)
end end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do 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.should == "frozen"
EvalSpecs::Vπsame_line.encoding.should == Encoding::UTF_8 EvalSpecs::Vπsame_line.encoding.should == Encoding::UTF_8
EvalSpecs::Vπsame_line.frozen?.should be_true EvalSpecs::Vπsame_line.frozen?.should be_true
ensure
EvalSpecs.send(:remove_const, :Vπsame_line)
end end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do 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.should == "frozen"
value.encoding.should == Encoding::BINARY value.encoding.should == Encoding::BINARY
value.frozen?.should == !frozen_string_default value.frozen?.should == !frozen_string_default
ensure
EvalSpecs.send(:remove_const, binary_constant)
end end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do 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? block_given?
end 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 class << self
define_method(:defined_block) do define_method(:defined_block) do
block_given? block_given?
end end
define_method(:defined_block_inside_block) do
yield_self {
block_given?
}
end
end end
end end
@ -235,10 +253,28 @@ module KernelSpecs
self.send(:block_given?) self.send(:block_given?)
end 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 class << self
define_method(:defined_block) do define_method(:defined_block) do
self.send(:block_given?) self.send(:block_given?)
end end
define_method(:defined_block_inside_block) do
yield_self {
self.send(:block_given?)
}
end
end end
end end
@ -251,10 +287,28 @@ module KernelSpecs
Kernel.block_given? Kernel.block_given?
end 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 class << self
define_method(:defined_block) do define_method(:defined_block) do
Kernel.block_given? Kernel.block_given?
end end
define_method(:defined_block_inside_block) do
yield_self {
Kernel.block_given?
}
end
end end
end end

View File

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

View File

@ -165,37 +165,35 @@ describe :kernel_load, shared: true do
end end
describe "when passed a module for 'wrap'" do describe "when passed a module for 'wrap'" do
ruby_version_is "3.1" do it "sets the enclosing scope to the supplied module" do
it "sets the enclosing scope to the supplied module" do path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR mod = Module.new
mod = Module.new @object.load(path, mod)
@object.load(path, mod)
Object.const_defined?(:LoadSpecWrap).should be_false Object.const_defined?(:LoadSpecWrap).should be_false
mod.const_defined?(:LoadSpecWrap).should be_true mod.const_defined?(:LoadSpecWrap).should be_true
wrap_module = ScratchPad.recorded[1] wrap_module = ScratchPad.recorded[1]
wrap_module.should == mod wrap_module.should == mod
end end
it "makes constants and instance methods in the source file reachable with the supplied module" do it "makes constants and instance methods in the source file reachable with the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new mod = Module.new
@object.load(path, mod) @object.load(path, mod)
mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1 mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
obj = Object.new obj = Object.new
obj.extend(mod) obj.extend(mod)
obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
end end
it "makes instance methods in the source file private" do it "makes instance methods in the source file private" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new mod = Module.new
@object.load(path, mod) @object.load(path, mod)
mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
end
end end
end end

View File

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

View File

@ -30,16 +30,8 @@ describe "main#public" do
end end
end end
ruby_version_is ''...'3.1' do it "returns argument" do
it "returns Object" do eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
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 end

View File

@ -599,20 +599,18 @@ describe "Marshal.dump" do
Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006" Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006"
end end
ruby_version_is "3.1" do it "dumps a Hash with compare_by_identity" do
it "dumps a Hash with compare_by_identity" do h = {}
h = {} h.compare_by_identity
h.compare_by_identity
Marshal.dump(h).should == "\004\bC:\tHash{\x00" Marshal.dump(h).should == "\004\bC:\tHash{\x00"
end end
it "dumps a Hash subclass with compare_by_identity" do it "dumps a Hash subclass with compare_by_identity" do
h = UserHash.new h = UserHash.new
h.compare_by_identity h.compare_by_identity
Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00" Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
end
end end
it "raises a TypeError with hash having default proc" do it "raises a TypeError with hash having default proc" do

View File

@ -23,224 +23,220 @@ describe :marshal_load, shared: true do
-> { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError) -> { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError)
end end
ruby_version_is "3.1" do describe "when called with freeze: true" do
describe "when called with freeze: true" do it "returns frozen strings" do
it "returns frozen strings" do string = Marshal.send(@method, Marshal.dump("foo"), freeze: true)
string = Marshal.send(@method, Marshal.dump("foo"), freeze: true) string.should == "foo"
string.should == "foo" string.should.frozen?
string.should.frozen?
utf8_string = "foo".encode(Encoding::UTF_8) utf8_string = "foo".encode(Encoding::UTF_8)
string = Marshal.send(@method, Marshal.dump(utf8_string), freeze: true) string = Marshal.send(@method, Marshal.dump(utf8_string), freeze: true)
string.should == utf8_string string.should == utf8_string
string.should.frozen? string.should.frozen?
end
it "returns frozen arrays" do
array = Marshal.send(@method, Marshal.dump([1, 2, 3]), freeze: true)
array.should == [1, 2, 3]
array.should.frozen?
end
it "returns frozen hashes" do
hash = Marshal.send(@method, Marshal.dump({foo: 42}), freeze: true)
hash.should == {foo: 42}
hash.should.frozen?
end
it "returns frozen regexps" do
regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true)
regexp.should == /foo/
regexp.should.frozen?
end
it "returns frozen structs" do
struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
struct.should == MarshalSpec::StructToDump.new(1, 2)
struct.should.frozen?
end
it "returns frozen objects" do
source_object = Object.new
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.should.frozen?
end
describe "deep freezing" do
it "returns hashes with frozen keys and values" do
key = Object.new
value = Object.new
source_object = {key => value}
hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
hash.size.should == 1
hash.keys[0].should.frozen?
hash.values[0].should.frozen?
end end
it "returns frozen arrays" do it "returns arrays with frozen elements" do
array = Marshal.send(@method, Marshal.dump([1, 2, 3]), freeze: true) object = Object.new
array.should == [1, 2, 3] source_object = [object]
array.should.frozen?
array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
array.size.should == 1
array[0].should.frozen?
end end
it "returns frozen hashes" do it "returns structs with frozen members" do
hash = Marshal.send(@method, Marshal.dump({foo: 42}), freeze: true) object1 = Object.new
hash.should == {foo: 42} object2 = Object.new
hash.should.frozen? source_object = MarshalSpec::StructToDump.new(object1, object2)
struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
struct.a.should.frozen?
struct.b.should.frozen?
end end
it "returns frozen regexps" do it "returns objects with frozen instance variables" do
regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true)
regexp.should == /foo/
regexp.should.frozen?
end
it "returns frozen structs" do
struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
struct.should == MarshalSpec::StructToDump.new(1, 2)
struct.should.frozen?
end
it "returns frozen objects" do
source_object = Object.new source_object = Object.new
instance_variable = Object.new
source_object.instance_variable_set(:@a, instance_variable)
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.instance_variable_get(:@a).should != nil
object.instance_variable_get(:@a).should.frozen?
end
it "deduplicates frozen strings" do
source_object = ["foo" + "bar", "foobar"]
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object[0].should equal(object[1])
end
end
it "does not freeze modules" do
object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
object.should_not.frozen?
Kernel.should_not.frozen?
end
it "does not freeze classes" do
object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
object.should_not.frozen?
Object.should_not.frozen?
end
ruby_bug "#19427", ""..."3.3" do
it "does freeze extended objects" do
object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
object.should.frozen? object.should.frozen?
end end
describe "deep freezing" do it "does freeze extended objects with instance variables" do
it "returns hashes with frozen keys and values" do object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
key = Object.new object.should.frozen?
value = Object.new end
source_object = {key => value} end
hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true) ruby_bug "#19427", "3.1"..."3.3" do
hash.size.should == 1 it "returns frozen object having #_dump method" do
hash.keys[0].should.frozen? object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
hash.values[0].should.frozen? object.should.frozen?
end
it "returns arrays with frozen elements" do
object = Object.new
source_object = [object]
array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
array.size.should == 1
array[0].should.frozen?
end
it "returns structs with frozen members" do
object1 = Object.new
object2 = Object.new
source_object = MarshalSpec::StructToDump.new(object1, object2)
struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
struct.a.should.frozen?
struct.b.should.frozen?
end
it "returns objects with frozen instance variables" do
source_object = Object.new
instance_variable = Object.new
source_object.instance_variable_set(:@a, instance_variable)
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.instance_variable_get(:@a).should != nil
object.instance_variable_get(:@a).should.frozen?
end
it "deduplicates frozen strings" do
source_object = ["foo" + "bar", "foobar"]
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object[0].should equal(object[1])
end
end end
it "does not freeze modules" do it "returns frozen object responding to #marshal_dump and #marshal_load" do
object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true) object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
object.should_not.frozen? object.should.frozen?
Kernel.should_not.frozen?
end end
it "does not freeze classes" do it "returns frozen object extended by a module" do
object = Marshal.send(@method, Marshal.dump(Object), freeze: true) object = Object.new
object.should_not.frozen? object.extend(MarshalSpec::ModuleToExtendBy)
Object.should_not.frozen?
end
ruby_bug "#19427", ""..."3.3" do
it "does freeze extended objects" do
object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
object.should.frozen?
end
it "does freeze extended objects with instance variables" do
object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
object.should.frozen?
end
end
ruby_bug "#19427", "3.1"..."3.3" do
it "returns frozen object having #_dump method" do
object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
object.should.frozen?
end
it "returns frozen object responding to #marshal_dump and #marshal_load" do
object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
object.should.frozen?
end
it "returns frozen object extended by a module" do
object = Object.new
object.extend(MarshalSpec::ModuleToExtendBy)
object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen?
end
end
it "does not call freeze method" do
object = MarshalSpec::ObjectWithFreezeRaisingException.new
object = Marshal.send(@method, Marshal.dump(object), freeze: true) object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen? object.should.frozen?
end end
end
it "returns frozen object even if object does not respond to freeze method" do it "does not call freeze method" do
object = MarshalSpec::ObjectWithoutFreeze.new object = MarshalSpec::ObjectWithFreezeRaisingException.new
object = Marshal.send(@method, Marshal.dump(object), freeze: true) object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen? object.should.frozen?
end end
it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do it "returns frozen object even if object does not respond to freeze method" do
source_object = UserString.new object = MarshalSpec::ObjectWithoutFreeze.new
source_object.instance_variable_set(:@foo, "bar") object = Marshal.send(@method, Marshal.dump(object), freeze: true)
object.should.frozen?
end
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
object.should.frozen? source_object = UserString.new
end source_object.instance_variable_set(:@foo, "bar")
describe "when called with a proc" do object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
it "call the proc with frozen objects" do object.should.frozen?
arr = [] end
s = +'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o; o}
Marshal.send( describe "when called with a proc" do
@method, it "call the proc with frozen objects" do
"\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", arr = []
proc, s = +'hi'
freeze: true, s.instance_variable_set(:@foo, 5)
) st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o; o}
arr.should == [ Marshal.send(
false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st, @method,
:b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]], "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F",
] proc,
freeze: true,
)
arr.each do |v| arr.should == [
v.should.frozen? false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
end :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
]
Struct.send(:remove_const, :Brittle) arr.each do |v|
v.should.frozen?
end end
it "does not freeze the object returned by the proc" do Struct.send(:remove_const, :Brittle)
string = Marshal.send(@method, Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true) end
string.should == "FOO"
string.should_not.frozen? it "does not freeze the object returned by the proc" do
end string = Marshal.send(@method, Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true)
string.should == "FOO"
string.should_not.frozen?
end end
end end
end end
describe "when called with a proc" do describe "when called with a proc" do
ruby_bug "#18141", ""..."3.1" do it "call the proc with fully initialized strings" do
it "call the proc with fully initialized strings" do utf8_string = "foo".encode(Encoding::UTF_8)
utf8_string = "foo".encode(Encoding::UTF_8) Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg| if arg.is_a?(String)
if arg.is_a?(String) arg.should == utf8_string
arg.should == utf8_string arg.encoding.should == Encoding::UTF_8
arg.encoding.should == Encoding::UTF_8 end
end arg
arg })
}) end
end
it "no longer mutate the object after it was passed to the proc" do it "no longer mutate the object after it was passed to the proc" do
string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc) string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
string.should.frozen? string.should.frozen?
end
end end
ruby_bug "#19427", ""..."3.3" do ruby_bug "#19427", ""..."3.3" do
@ -255,40 +251,38 @@ describe :marshal_load, shared: true do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4] Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end end
ruby_bug "#18141", ""..."3.1" do it "calls the proc for recursively visited data" do
it "calls the proc for recursively visited data" do a = [1]
a = [1] a << a
a << a ret = []
ret = [] Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg.inspect; arg })
Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg.inspect; arg }) ret[0].should == 1.inspect
ret[0].should == 1.inspect ret[1].should == a.inspect
ret[1].should == a.inspect ret.size.should == 2
ret.size.should == 2 end
end
it "loads an Array with proc" do it "loads an Array with proc" do
arr = [] arr = []
s = +'hi' s = +'hi'
s.instance_variable_set(:@foo, 5) s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none') st.instance_variable_set(:@clue, 'none')
st.a = 0.0 st.a = 0.0
h = Hash.new('def') h = Hash.new('def')
h['nine'] = 9 h['nine'] = 9
a = [:a, :b, :c] a = [:a, :b, :c]
a.instance_variable_set(:@two, 2) a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a] obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant') obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o.dup; o} proc = Proc.new { |o| arr << o.dup; o}
Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc) Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)
arr.should == [ arr.should == [
false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st, false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
:b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]], :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
] ]
Struct.send(:remove_const, :Brittle) Struct.send(:remove_const, :Brittle)
end
end end
end end
@ -364,39 +358,37 @@ describe :marshal_load, shared: true do
end end
end end
ruby_bug "#18141", ""..."3.1" do it "loads an array containing objects having _dump method, and with proc" do
it "loads an array containing objects having _dump method, and with proc" do arr = []
arr = [] myproc = Proc.new { |o| arr << o.dup; o }
myproc = Proc.new { |o| arr << o.dup; o } o1 = UserDefined.new;
o1 = UserDefined.new; o2 = UserDefinedWithIvar.new
o2 = UserDefinedWithIvar.new obj = [o1, o2, o1, o2]
obj = [o1, o2, o1, o2]
Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc) Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
arr[0].should == o1 arr[0].should == o1
arr[1].should == o2 arr[1].should == o2
arr[2].should == obj arr[2].should == obj
arr.size.should == 3 arr.size.should == 3
end end
it "loads an array containing objects having marshal_dump method, and with proc" do it "loads an array containing objects having marshal_dump method, and with proc" do
arr = [] arr = []
proc = Proc.new { |o| arr << o.dup; o } proc = Proc.new { |o| arr << o.dup; o }
o1 = UserMarshal.new o1 = UserMarshal.new
o2 = UserMarshalWithIvar.new o2 = UserMarshalWithIvar.new
Marshal.send(@method, "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc) Marshal.send(@method, "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc)
arr[0].should == 'stuff' arr[0].should == 'stuff'
arr[1].should == o1 arr[1].should == o1
arr[2].should == 'my data' arr[2].should == 'my data'
arr[3].should == ['my data'] arr[3].should == ['my data']
arr[4].should == o2 arr[4].should == o2
arr[5].should == [o1, o2, o1, o2] arr[5].should == [o1, o2, o1, o2]
arr.size.should == 6 arr.size.should == 6
end
end end
it "assigns classes to nested subclasses of Array correctly" do it "assigns classes to nested subclasses of Array correctly" do
@ -526,28 +518,26 @@ describe :marshal_load, shared: true do
unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar' unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
end end
ruby_version_is "3.1" do it "preserves compare_by_identity behaviour" do
it "preserves compare_by_identity behaviour" do h = { a: 1 }
h = { a: 1 } h.compare_by_identity
h.compare_by_identity unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled = Marshal.send(@method, Marshal.dump(h)) unmarshalled.should.compare_by_identity?
unmarshalled.should.compare_by_identity?
h = { a: 1 } h = { a: 1 }
unmarshalled = Marshal.send(@method, Marshal.dump(h)) unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should_not.compare_by_identity? unmarshalled.should_not.compare_by_identity?
end end
it "preserves compare_by_identity behaviour for a Hash subclass" do it "preserves compare_by_identity behaviour for a Hash subclass" do
h = UserHash.new({ a: 1 }) h = UserHash.new({ a: 1 })
h.compare_by_identity h.compare_by_identity
unmarshalled = Marshal.send(@method, Marshal.dump(h)) unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should.compare_by_identity? unmarshalled.should.compare_by_identity?
h = UserHash.new({ a: 1 }) h = UserHash.new({ a: 1 })
unmarshalled = Marshal.send(@method, Marshal.dump(h)) unmarshalled = Marshal.send(@method, Marshal.dump(h))
unmarshalled.should_not.compare_by_identity? unmarshalled.should_not.compare_by_identity?
end
end end
it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do

View File

@ -2,33 +2,31 @@
require_relative '../../spec_helper' 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
it "returns the length of the corresponding match when given an Integer" do md = /(.)(.)(\d+)(\d)/.match("THX1138.")
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
md.match_length(0).should == 6 md.match_length(0).should == 6
md.match_length(1).should == 1 md.match_length(1).should == 1
md.match_length(2).should == 1 md.match_length(2).should == 1
md.match_length(3).should == 3 md.match_length(3).should == 3
md.match_length(4).should == 1 md.match_length(4).should == 1
end end
it "returns nil on non-matching index matches" do it "returns nil on non-matching index matches" do
md = /\d+(\w)?/.match("THX1138.") md = /\d+(\w)?/.match("THX1138.")
md.match_length(1).should == nil md.match_length(1).should == nil
end end
it "returns the length of the corresponding named match when given a Symbol" do it "returns the length of the corresponding named match when given a Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/) md = 'haystack'.match(/(?<t>t(?<a>ack))/)
md.match_length(:a).should == 3 md.match_length(:a).should == 3
md.match_length(:t).should == 4 md.match_length(:t).should == 4
end end
it "returns nil on non-matching index matches" do it "returns nil on non-matching index matches" do
md = 'haystack'.match(/(?<t>t)(?<a>all)?/) md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
md.match_length(:t).should == 1 md.match_length(:t).should == 1
md.match_length(:a).should == nil md.match_length(:a).should == nil
end
end end
end end

View File

@ -2,33 +2,31 @@
require_relative '../../spec_helper' 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
it "returns the corresponding match when given an Integer" do md = /(.)(.)(\d+)(\d)/.match("THX1138.")
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
md.match(0).should == 'HX1138' md.match(0).should == 'HX1138'
md.match(1).should == 'H' md.match(1).should == 'H'
md.match(2).should == 'X' md.match(2).should == 'X'
md.match(3).should == '113' md.match(3).should == '113'
md.match(4).should == '8' md.match(4).should == '8'
end end
it "returns nil on non-matching index matches" do it "returns nil on non-matching index matches" do
md = /\d+(\w)?/.match("THX1138.") md = /\d+(\w)?/.match("THX1138.")
md.match(1).should == nil md.match(1).should == nil
end end
it "returns the corresponding named match when given a Symbol" do it "returns the corresponding named match when given a Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/) md = 'haystack'.match(/(?<t>t(?<a>ack))/)
md.match(:a).should == 'ack' md.match(:a).should == 'ack'
md.match(:t).should == 'tack' md.match(:t).should == 'tack'
end end
it "returns nil on non-matching index matches" do it "returns nil on non-matching index matches" do
md = 'haystack'.match(/(?<t>t)(?<a>all)?/) md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
md.match(:t).should == 't' md.match(:t).should == 't'
md.match(:a).should == nil md.match(:a).should == nil
end
end end
end end

View File

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

View File

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

View File

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

View File

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

View File

@ -486,42 +486,21 @@ describe "Module#autoload" do
ScratchPad.recorded.should == [:raise, :raise] ScratchPad.recorded.should == [:raise, :raise]
end end
ruby_version_is "3.1" do it "removes the constant from Module#constants if the loaded file does not define it" do
it "removes the constant from Module#constants if the loaded file does not define it" do path = fixture(__FILE__, "autoload_o.rb")
path = fixture(__FILE__, "autoload_o.rb") ScratchPad.record []
ScratchPad.record [] ModuleSpecs::Autoload.autoload :O, path
ModuleSpecs::Autoload.autoload :O, path
ModuleSpecs::Autoload.const_defined?(:O).should == true ModuleSpecs::Autoload.const_defined?(:O).should == true
ModuleSpecs::Autoload.should have_constant(:O) ModuleSpecs::Autoload.should have_constant(:O)
ModuleSpecs::Autoload.autoload?(:O).should == path ModuleSpecs::Autoload.autoload?(:O).should == path
-> { ModuleSpecs::Autoload::O }.should raise_error(NameError) -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
ModuleSpecs::Autoload.const_defined?(:O).should == false ModuleSpecs::Autoload.const_defined?(:O).should == false
ModuleSpecs::Autoload.should_not have_constant(:O) ModuleSpecs::Autoload.should_not have_constant(:O)
ModuleSpecs::Autoload.autoload?(:O).should == nil ModuleSpecs::Autoload.autoload?(:O).should == nil
-> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError) -> { 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 end
it "does not try to load the file again if the loaded file did not define the constant" do it "does not try to load the file again if the loaded file did not define the constant" do
@ -654,48 +633,23 @@ describe "Module#autoload" do
end end
end end
ruby_version_is "3.1" do it "looks up in parent scope after failed autoload" do
it "looks up in parent scope after failed autoload" do @remove << :DeclaredInCurrentDefinedInParent
@remove << :DeclaredInCurrentDefinedInParent module ModuleSpecs::Autoload
module ModuleSpecs::Autoload ScratchPad.record -> {
ScratchPad.record -> { DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent }
}
class LexicalScope class LexicalScope
autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb") autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
-> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError) -> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError)
# Basically, the autoload constant remains in a "undefined" state # Basically, the autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
const_defined?(:DeclaredInCurrentDefinedInParent).should == false const_defined?(:DeclaredInCurrentDefinedInParent).should == false
-> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError) -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
end
DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
end end
end
end
ruby_version_is ""..."3.1" do DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
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
end end

View File

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

View File

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

View File

@ -8,16 +8,23 @@ describe "Module#const_set" do
ConstantSpecs.const_set "CS_CONST402", :const402 ConstantSpecs.const_set "CS_CONST402", :const402
ConstantSpecs.const_get(:CS_CONST402).should == :const402 ConstantSpecs.const_get(:CS_CONST402).should == :const402
ensure
ConstantSpecs.send(:remove_const, :CS_CONST401)
ConstantSpecs.send(:remove_const, :CS_CONST402)
end end
it "returns the value set" do it "returns the value set" do
ConstantSpecs.const_set(:CS_CONST403, :const403).should == :const403 ConstantSpecs.const_set(:CS_CONST403, :const403).should == :const403
ensure
ConstantSpecs.send(:remove_const, :CS_CONST403)
end end
it "sets the name of an anonymous module" do it "sets the name of an anonymous module" do
m = Module.new m = Module.new
ConstantSpecs.const_set(:CS_CONST1000, m) ConstantSpecs.const_set(:CS_CONST1000, m)
m.name.should == "ConstantSpecs::CS_CONST1000" m.name.should == "ConstantSpecs::CS_CONST1000"
ensure
ConstantSpecs.send(:remove_const, :CS_CONST1000)
end end
it "sets the name of a module scoped by an anonymous module" do 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" b.name.should == "ModuleSpecs_CS3::B"
c.name.should == "ModuleSpecs_CS3::B::C" c.name.should == "ModuleSpecs_CS3::B::C"
d.name.should == "ModuleSpecs_CS3::D" d.name.should == "ModuleSpecs_CS3::D"
ensure
Object.send(:remove_const, :ModuleSpecs_CS3)
end end
it "raises a NameError if the name does not start with a capital letter" do 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("CS_CONST404", :const404).should == :const404
-> { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError) -> { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError)
-> { 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 end
it "calls #to_str to convert the given name to a String" do 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") name.should_receive(:to_str).and_return("CS_CONST405")
ConstantSpecs.const_set(name, :const405).should == :const405 ConstantSpecs.const_set(name, :const405).should == :const405
ConstantSpecs::CS_CONST405.should == :const405 ConstantSpecs::CS_CONST405.should == :const405
ensure
ConstantSpecs.send(:remove_const, :CS_CONST405)
end end
it "raises a TypeError if conversion to a String by calling #to_str fails" do 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::CSL_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] 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 end
it "searches a path in a module included in the immediate class before the superclass" do it "searches a path in a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CSL_CONST302 = :const302_1 ConstantSpecs::ParentB::CSL_CONST302 = :const302_1
ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2 ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1] 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 end
it "searches a path in the superclass before a module included in the superclass" do it "searches a path in the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1 ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1
ConstantSpecs::ParentB::CSL_CONST303 = :const303_2 ConstantSpecs::ParentB::CSL_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1] 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 end
it "searches a path in a module included in the superclass" do it "searches a path in a module included in the superclass" do
ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1 ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1
ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2 ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1] 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 end
it "searches a path in the superclass chain" do it "searches a path in the superclass chain" do
ConstantSpecs::ModuleA::CSL_CONST305 = :const305 ConstantSpecs::ModuleA::CSL_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1] ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1]
ensure
ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST305)
end end
it "returns path to a toplevel constant when the receiver is a Class" do it "returns path to a toplevel constant when the receiver is a Class" do
Object::CSL_CONST306 = :const306 Object::CSL_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1] ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1]
ensure
Object.send(:remove_const, :CSL_CONST306)
end end
it "returns path to a toplevel constant when the receiver is a Module" do it "returns path to a toplevel constant when the receiver is a Module" do
Object::CSL_CONST308 = :const308 Object::CSL_CONST308 = :const308
ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1] ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2] ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2]
ensure
Object.send(:remove_const, :CSL_CONST308)
end end
it "returns path to the updated value of a constant" do 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 ConstantSpecs::ClassB::CSL_CONST309 = :const309_2
}.should complain(/already initialized constant/) }.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2] ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2]
ensure
ConstantSpecs::ClassB.send(:remove_const, :CSL_CONST309)
end end
end end
@ -207,7 +229,7 @@ describe "Module#const_source_location" do
end end
it "does search private constants path" do it "does search private constants path" do
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE] ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
end end
it "works for eval with a given line" do it "works for eval with a given line" do

View File

@ -476,6 +476,9 @@ describe "Module#define_method" do
ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } } ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } }
ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo) ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo)
}.should raise_error(TypeError, /bind argument must be a subclass of ChildClass/) }.should raise_error(TypeError, /bind argument must be a subclass of ChildClass/)
ensure
Object.send(:remove_const, :ParentClass)
Object.send(:remove_const, :ChildClass)
end end
it "raises a TypeError when an UnboundMethod from one class is defined on an unrelated class" do 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 end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do 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 end
ruby_version_is ""..."3.2" do ruby_version_is ""..."3.2" do
@ -427,6 +431,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm') M.const_set(:FOO, 'm')
B.foo.should == 'm' B.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdated)
end end
it "updates the constant when a module included after a call is later updated" do 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') M.const_set(:FOO, 'm')
B.foo.should == 'm' B.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstLaterUpdated)
end end
it "updates the constant when a module included in another module after a call is later updated" do 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') M.const_set(:FOO, 'm')
B.foo.should == 'm' B.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstModuleLaterUpdated)
end end
it "updates the constant when a nested included module is updated" do 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') N.const_set(:FOO, 'n')
B.foo.should == 'n' B.foo.should == 'n'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncludeUpdated)
end end
it "updates the constant when a new module is included" do it "updates the constant when a new module is included" do
@ -531,6 +543,8 @@ describe "Module#include" do
B.include(M) B.include(M)
B.foo.should == 'm' B.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNewInclude)
end end
it "updates the constant when a new module with nested module is included" do 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.include M
B.foo.should == 'n' B.foo.should == 'n'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncluded)
end end
it "overrides a previous super method call" do it "overrides a previous super method call" do

View File

@ -38,22 +38,11 @@ describe "Module#module_function with specific method names" do
m.respond_to?(:test3).should == false m.respond_to?(:test3).should == false
end end
ruby_version_is ""..."3.1" do it "returns argument or arguments if given" do
it "returns self" do Module.new do
Module.new do def foo; end
def foo; end module_function(:foo).should equal(:foo)
module_function(:foo).should equal(self) module_function(:foo, :foo).should == [:foo, :foo]
end
end
end
ruby_version_is "3.1" do
it "returns argument or arguments if given" do
Module.new do
def foo; end
module_function(:foo).should equal(:foo)
module_function(:foo, :foo).should == [:foo, :foo]
end
end end
end end
@ -216,19 +205,9 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
m.respond_to?(:test2).should == true m.respond_to?(:test2).should == true
end end
ruby_version_is ""..."3.1" do it "returns nil" do
it "returns self" do Module.new do
Module.new do module_function.should equal(nil)
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
end end

View File

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

View File

@ -261,6 +261,8 @@ describe "Module#prepend" do
B.prepend M B.prepend M
B.foo.should == 'm' B.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatePrepended)
end end
it "updates the constant when a prepended module is updated" do it "updates the constant when a prepended module is updated" do
@ -281,6 +283,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm') M.const_set(:FOO, 'm')
B.foo.should == 'm' B.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstPrependedUpdated)
end end
it "updates the constant when there is a base included constant and the prepended module overrides it" do 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.prepend M
A.foo.should == 'm' A.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstIncludedPrependedOverride)
end end
it "updates the constant when there is a base included constant and the prepended module is later updated" do 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') M.const_set(:FOO, 'm')
A.foo.should == 'm' A.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstIncludedPrependedLaterUpdated)
end end
it "updates the constant when a module prepended after a constant is later updated" do 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') M.const_set(:FOO, 'm')
B.foo.should == 'm' B.foo.should == 'm'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterLaterUpdated)
end end
it "updates the constant when a module is prepended after another and the constant is defined later on that module" do 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') N.const_set(:FOO, 'n')
A.foo.should == 'n' A.foo.should == 'n'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterConstDefined)
end end
it "updates the constant when a module is included in a prepended module and the constant is defined later" do 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') N.const_set(:FOO, 'n')
A.foo.should == 'n' A.foo.should == 'n'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedIncludedInPrependedConstDefinedLater)
end end
it "updates the constant when a new module with an included module is prepended" do 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.prepend M
B.foo.should == 'n' B.foo.should == 'n'
end end
ensure
ModuleSpecs.send(:remove_const, :ConstUpdatedNewModuleIncludedPrepended)
end end
it "raises a TypeError when the argument is not a Module" do it "raises a TypeError when the argument is not a Module" do
@ -432,7 +448,11 @@ describe "Module#prepend" do
end end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do 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 end
ruby_version_is ""..."3.2" do ruby_version_is ""..."3.2" do
@ -787,34 +807,17 @@ describe "Module#prepend" do
# https://bugs.ruby-lang.org/issues/17423 # https://bugs.ruby-lang.org/issues/17423
describe "when module already exists in ancestor chain" do describe "when module already exists in ancestor chain" do
ruby_version_is ""..."3.1" do it "modifies the ancestor chain" do
it "does not modify the ancestor chain" do m = Module.new do; end
m = Module.new do; end a = Module.new do; end
a = Module.new do; end b = Class.new do; end
b = Class.new do; end
b.include(a) b.include(a)
a.prepend(m) a.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object] b.ancestors.take(4).should == [b, m, a, Object]
b.prepend(m) b.prepend(m)
b.ancestors.take(4).should == [b, m, a, Object] b.ancestors.take(5).should == [m, 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
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(5).should == [m, b, m, a, Object]
end
end end
end end

View File

@ -38,25 +38,13 @@ describe "Module#private" do
:module_specs_public_method_on_object_for_kernel_private) :module_specs_public_method_on_object_for_kernel_private)
end end
ruby_version_is ""..."3.1" do it "returns argument or arguments if given" do
it "returns self" do (class << Object.new; self; end).class_eval do
(class << Object.new; self; end).class_eval do def foo; end
def foo; end private(:foo).should equal(:foo)
private(:foo).should equal(self) private([:foo, :foo]).should == [:foo, :foo]
private.should equal(self) private(:foo, :foo).should == [:foo, :foo]
end private.should equal(nil)
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
private(:foo).should equal(:foo)
private([:foo, :foo]).should == [:foo, :foo]
private(:foo, :foo).should == [:foo, :foo]
private.should equal(nil)
end
end end
end end

View File

@ -39,25 +39,13 @@ describe "Module#protected" do
:module_specs_public_method_on_object_for_kernel_protected) :module_specs_public_method_on_object_for_kernel_protected)
end end
ruby_version_is ""..."3.1" do it "returns argument or arguments if given" do
it "returns self" do (class << Object.new; self; end).class_eval do
(class << Object.new; self; end).class_eval do def foo; end
def foo; end protected(:foo).should equal(:foo)
protected(:foo).should equal(self) protected([:foo, :foo]).should == [:foo, :foo]
protected.should equal(self) protected(:foo, :foo).should == [:foo, :foo]
end protected.should equal(nil)
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
protected(:foo).should equal(:foo)
protected([:foo, :foo]).should == [:foo, :foo]
protected(:foo, :foo).should == [:foo, :foo]
protected.should equal(nil)
end
end end
end end

View File

@ -27,25 +27,13 @@ describe "Module#public" do
:module_specs_private_method_on_object_for_kernel_public) :module_specs_private_method_on_object_for_kernel_public)
end end
ruby_version_is ""..."3.1" do it "returns argument or arguments if given" do
it "returns self" do (class << Object.new; self; end).class_eval do
(class << Object.new; self; end).class_eval do def foo; end
def foo; end public(:foo).should equal(:foo)
public(:foo).should equal(self) public([:foo, :foo]).should == [:foo, :foo]
public.should equal(self) public(:foo, :foo).should == [:foo, :foo]
end public.should equal(nil)
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
public(:foo).should equal(:foo)
public([:foo, :foo]).should == [:foo, :foo]
public(:foo, :foo).should == [:foo, :foo]
public.should equal(nil)
end
end end
end end

View File

@ -272,7 +272,7 @@ describe "Module#refine" do
it "looks in later included modules of the refined module first" do it "looks in later included modules of the refined module first" do
a = Module.new do a = Module.new do
def foo def foo
"foo from A" "foo from A"
end end
end end
@ -300,67 +300,6 @@ describe "Module#refine" do
result.should == "foo from IncludeMeLater" result.should == "foo from IncludeMeLater"
end 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 it "looks in the class then" do
refined_class = ModuleSpecs.build_refined_class refined_class = ModuleSpecs.build_refined_class
@ -606,30 +545,6 @@ describe "Module#refine" do
end end
context "when super is called in a refinement" do 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 it "looks in the refined class" do
refined_class = ModuleSpecs.build_refined_class refined_class = ModuleSpecs.build_refined_class
@ -650,59 +565,6 @@ describe "Module#refine" do
result.should == "foo" result.should == "foo"
end 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 # super in a method of a refinement invokes the method in the refined
# class even if there is another refinement which has been activated # class even if there is another refinement which has been activated
# in the same context. # in the same context.
@ -763,179 +625,6 @@ describe "Module#refine" do
}.should raise_error(NoMethodError) }.should raise_error(NoMethodError)
end end
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 end
it 'and alias aliases a method within a refinement module, but not outside it' do 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.send(:remove_const,:FOO)
A.foo.should == 'm' A.foo.should == 'm'
end end
ensure
ConstantSpecs.send(:remove_const, :RemovedConstantUpdate)
end end
end end

View File

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

View File

@ -19,8 +19,8 @@ describe :numeric_imag, shared: true do
end end
it "raises an ArgumentError if given any arguments" do it "raises an ArgumentError if given any arguments" do
@numbers.each do |number| @numbers.each do |number|
-> { number.send(@method, number) }.should raise_error(ArgumentError) -> { number.send(@method, number) }.should raise_error(ArgumentError)
end end
end end
end end

View File

@ -25,24 +25,24 @@ describe :numeric_rect, shared: true do
end end
it "returns self as the first element" do it "returns self as the first element" do
@numbers.each do |number| @numbers.each do |number|
if Float === number and number.nan? if Float === number and number.nan?
number.send(@method).first.nan?.should be_true number.send(@method).first.nan?.should be_true
else else
number.send(@method).first.should == number number.send(@method).first.should == number
end end
end end
end end
it "returns 0 as the last element" do it "returns 0 as the last element" do
@numbers.each do |number| @numbers.each do |number|
number.send(@method).last.should == 0 number.send(@method).last.should == 0
end end
end end
it "raises an ArgumentError if given any arguments" do it "raises an ArgumentError if given any arguments" do
@numbers.each do |number| @numbers.each do |number|
-> { number.send(@method, number) }.should raise_error(ArgumentError) -> { number.send(@method, number) }.should raise_error(ArgumentError)
end end
end end
end end

View File

@ -193,25 +193,23 @@ describe "ObjectSpace.define_finalizer" do
ret[1].should.equal?(p) ret[1].should.equal?(p)
end end
ruby_version_is "3.1" do describe "when $VERBOSE is not nil" do
describe "when $VERBOSE is not nil" do it "warns if an exception is raised in finalizer" do
it "warns if an exception is raised in finalizer" do code = <<-RUBY
code = <<-RUBY ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" } RUBY
RUBY
ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing") ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
end
end end
end
describe "when $VERBOSE is nil" do describe "when $VERBOSE is nil" do
it "does not warn even if an exception is raised in finalizer" do it "does not warn even if an exception is raised in finalizer" do
code = <<-RUBY code = <<-RUBY
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" } ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
RUBY RUBY
ruby_exe(code, args: "2>&1", options: "-W0").should == "" ruby_exe(code, args: "2>&1", options: "-W0").should == ""
end
end end
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 end
it "returns nil if the key is not found when no block is given" do 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 m.delete(Object.new).should == nil
end 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
end end

View File

@ -1,4 +1,5 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "3.3" do ruby_version_is "3.3" do
describe "ObjectSpace::WeakKeyMap#[]" do describe "ObjectSpace::WeakKeyMap#[]" do
@ -15,12 +16,92 @@ ruby_version_is "3.3" do
map[key2].should == ref2 map[key2].should == ref2
end 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 map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a a].map(&:upcase) key1, key2 = %w[a a].map(&:upcase)
ref = "x" ref = "x"
map[key1] = ref map[key1] = ref
map[key2].should == ref map[key2].should == ref
end 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
end end

View File

@ -8,10 +8,6 @@ ruby_version_is "3.3" do
map[key].should == value map[key].should == value
end end
def should_not_accept(map, key, value)
-> { map[key] = value }.should raise_error(ArgumentError)
end
it "is correct" do it "is correct" do
map = ObjectSpace::WeakKeyMap.new map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a b].map(&:upcase) key1, key2 = %w[a b].map(&:upcase)
@ -40,32 +36,47 @@ ruby_version_is "3.3" do
should_accept(map, y, x) should_accept(map, y, x)
end end
it "rejects symbols as keys" do it "does not duplicate and freeze String keys (like Hash#[]= does)" do
map = ObjectSpace::WeakKeyMap.new map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, :foo, true) key = +"a"
should_not_accept(map, rand.to_s.to_sym, true) 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 end
it "rejects integers as keys" do context "a key cannot be garbage collected" do
map = ObjectSpace::WeakKeyMap.new it "raises ArgumentError when Integer is used as a key" do
should_not_accept(map, 42, true) map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, 2 ** 68, true) -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end end
it "rejects floats as keys" do it "raises ArgumentError when Float is used as a key" do
map = ObjectSpace::WeakKeyMap.new 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 end
it "rejects booleans as keys" do it "raises ArgumentError when Symbol is used as a key" do
map = ObjectSpace::WeakKeyMap.new map = ObjectSpace::WeakKeyMap.new
should_not_accept(map, true, true) -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
should_not_accept(map, false, true) end
end
it "rejects nil as keys" do it "raises ArgumentError when true is used as a key" do
map = ObjectSpace::WeakKeyMap.new 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 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[key1] = true
map.getkey(key2).should equal(key1) map.getkey(key2).should equal(key1)
map.getkey("X").should == nil 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 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.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
map[key3] = 3 map[key3] = 3
map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ 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 end
end end

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