2018-03-04 10:09:32 -05:00
|
|
|
require_relative '../spec_helper'
|
|
|
|
require_relative '../fixtures/class'
|
2017-05-07 08:04:49 -04:00
|
|
|
|
|
|
|
describe "A singleton class" do
|
|
|
|
it "is TrueClass for true" do
|
|
|
|
true.singleton_class.should == TrueClass
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is FalseClass for false" do
|
|
|
|
false.singleton_class.should == FalseClass
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is NilClass for nil" do
|
|
|
|
nil.singleton_class.should == NilClass
|
|
|
|
end
|
|
|
|
|
2020-12-20 11:16:26 -05:00
|
|
|
it "raises a TypeError for Integer's" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { 1.singleton_class }.should raise_error(TypeError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "raises a TypeError for symbols" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { :symbol.singleton_class }.should raise_error(TypeError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is a singleton Class instance" do
|
|
|
|
o = mock('x')
|
|
|
|
o.singleton_class.should be_kind_of(Class)
|
|
|
|
o.singleton_class.should_not equal(Object)
|
|
|
|
o.should be_kind_of(o.singleton_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is a Class for classes" do
|
|
|
|
ClassSpecs::A.singleton_class.should be_kind_of(Class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "inherits from Class for classes" do
|
|
|
|
Class.should be_ancestor_of(Object.singleton_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is a subclass of Class's singleton class" do
|
|
|
|
ec = ClassSpecs::A.singleton_class
|
|
|
|
ec.should be_kind_of(Class.singleton_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is a subclass of the same level of Class's singleton class" do
|
|
|
|
ecec = ClassSpecs::A.singleton_class.singleton_class
|
|
|
|
class_ec = Class.singleton_class
|
|
|
|
|
|
|
|
ecec.should be_kind_of(class_ec.singleton_class)
|
|
|
|
ecec.should be_kind_of(class_ec)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is a subclass of a superclass's singleton class" do
|
|
|
|
ClassSpecs::K.singleton_class.superclass.should ==
|
|
|
|
ClassSpecs::H.singleton_class
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is a subclass of the same level of superclass's singleton class" do
|
|
|
|
ClassSpecs::K.singleton_class.singleton_class.superclass.should ==
|
|
|
|
ClassSpecs::H.singleton_class.singleton_class
|
|
|
|
end
|
|
|
|
|
|
|
|
it "for BasicObject has Class as it's superclass" do
|
|
|
|
BasicObject.singleton_class.superclass.should == Class
|
|
|
|
end
|
|
|
|
|
|
|
|
it "for BasicObject has the proper level of superclass for Class" do
|
|
|
|
BasicObject.singleton_class.singleton_class.superclass.should ==
|
|
|
|
Class.singleton_class
|
|
|
|
end
|
|
|
|
|
|
|
|
it "has class String as the superclass of a String instance" do
|
|
|
|
"blah".singleton_class.superclass.should == String
|
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't have singleton class" do
|
2020-12-27 11:35:32 -05:00
|
|
|
-> { bignum_value.singleton_class }.should raise_error(TypeError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "A constant on a singleton class" do
|
|
|
|
before :each do
|
|
|
|
@object = Object.new
|
|
|
|
class << @object
|
|
|
|
CONST = self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can be accessed after the singleton class body is reopened" do
|
|
|
|
class << @object
|
|
|
|
CONST.should == self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can be accessed via self::CONST" do
|
|
|
|
class << @object
|
|
|
|
self::CONST.should == self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can be accessed via const_get" do
|
|
|
|
class << @object
|
|
|
|
const_get(:CONST).should == self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is not defined on the object's class" do
|
|
|
|
@object.class.const_defined?(:CONST).should be_false
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is not defined in the singleton class opener's scope" do
|
|
|
|
class << @object
|
|
|
|
CONST
|
|
|
|
end
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { CONST }.should raise_error(NameError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "cannot be accessed via object::CONST" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> do
|
2017-05-07 08:04:49 -04:00
|
|
|
@object::CONST
|
|
|
|
end.should raise_error(TypeError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises a NameError for anonymous_module::CONST" do
|
|
|
|
@object = Class.new
|
|
|
|
class << @object
|
|
|
|
CONST = 100
|
|
|
|
end
|
|
|
|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> do
|
2017-05-07 08:04:49 -04:00
|
|
|
@object::CONST
|
|
|
|
end.should raise_error(NameError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "appears in the singleton class constant list" do
|
|
|
|
@object.singleton_class.should have_constant(:CONST)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not appear in the object's class constant list" do
|
|
|
|
@object.class.should_not have_constant(:CONST)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is not preserved when the object is duped" do
|
|
|
|
@object = @object.dup
|
|
|
|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> do
|
2017-05-07 08:04:49 -04:00
|
|
|
class << @object; CONST; end
|
|
|
|
end.should raise_error(NameError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is preserved when the object is cloned" do
|
|
|
|
@object = @object.clone
|
|
|
|
|
|
|
|
class << @object
|
|
|
|
CONST.should_not be_nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-10-24 09:52:37 -04:00
|
|
|
describe "Defining yield in singleton class" do
|
|
|
|
ruby_version_is "2.7"..."3.0" do
|
|
|
|
it 'emits a deprecation warning' do
|
|
|
|
code = <<~RUBY
|
|
|
|
def m
|
|
|
|
class << Object.new
|
|
|
|
yield
|
|
|
|
end
|
|
|
|
end
|
|
|
|
m { :ok }
|
|
|
|
RUBY
|
|
|
|
|
|
|
|
-> { eval(code) }.should complain(/warning: `yield' in class syntax will not be supported from Ruby 3.0/)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-07 08:04:49 -04:00
|
|
|
describe "Defining instance methods on a singleton class" do
|
|
|
|
before :each do
|
|
|
|
@k = ClassSpecs::K.new
|
|
|
|
class << @k
|
|
|
|
def singleton_method; 1 end
|
|
|
|
end
|
|
|
|
|
|
|
|
@k_sc = @k.singleton_class
|
|
|
|
end
|
|
|
|
|
|
|
|
it "defines public methods" do
|
|
|
|
@k_sc.should have_public_instance_method(:singleton_method)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "Instance methods of a singleton class" do
|
|
|
|
before :each do
|
|
|
|
k = ClassSpecs::K.new
|
|
|
|
@k_sc = k.singleton_class
|
|
|
|
@a_sc = ClassSpecs::A.new.singleton_class
|
|
|
|
@a_c_sc = ClassSpecs::A.singleton_class
|
|
|
|
end
|
|
|
|
|
|
|
|
it "include ones of the object's class" do
|
|
|
|
@k_sc.should have_instance_method(:example_instance_method)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include class methods of the object's class" do
|
|
|
|
@k_sc.should_not have_instance_method(:example_class_method)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "include instance methods of Object" do
|
|
|
|
@a_sc.should have_instance_method(:example_instance_method_of_object)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include class methods of Object" do
|
|
|
|
@a_sc.should_not have_instance_method(:example_class_method_of_object)
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "for a class" do
|
|
|
|
it "include instance methods of Class" do
|
|
|
|
@a_c_sc.should have_instance_method(:example_instance_method_of_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include class methods of Class" do
|
|
|
|
@a_c_sc.should_not have_instance_method(:example_class_method_of_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include instance methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.should_not have_instance_method(:example_instance_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include class methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.should_not have_instance_method(:example_class_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "for a singleton class" do
|
|
|
|
it "includes instance methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.singleton_class.should have_instance_method(:example_instance_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include class methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.singleton_class.should_not have_instance_method(:example_class_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "Class methods of a singleton class" do
|
|
|
|
before :each do
|
|
|
|
k = ClassSpecs::K.new
|
|
|
|
@k_sc = k.singleton_class
|
|
|
|
@a_sc = ClassSpecs::A.new.singleton_class
|
|
|
|
@a_c_sc = ClassSpecs::A.singleton_class
|
|
|
|
end
|
|
|
|
|
|
|
|
it "include ones of the object's class" do
|
|
|
|
@k_sc.should have_method(:example_class_method)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include instance methods of the object's class" do
|
|
|
|
@k_sc.should_not have_method(:example_instance_method)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "include instance methods of Class" do
|
|
|
|
@a_sc.should have_method(:example_instance_method_of_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include class methods of Class" do
|
|
|
|
@a_sc.should_not have_method(:example_class_method_of_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "for a class" do
|
|
|
|
it "include instance methods of Class" do
|
|
|
|
@a_c_sc.should have_method(:example_instance_method_of_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "include class methods of Class" do
|
|
|
|
@a_c_sc.should have_method(:example_class_method_of_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "include instance methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.should have_method(:example_instance_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not include class methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.should_not have_method(:example_class_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "for a singleton class" do
|
|
|
|
it "include instance methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.singleton_class.should have_method(:example_instance_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "include class methods of the singleton class of Class" do
|
|
|
|
@a_c_sc.singleton_class.should have_method(:example_class_method_of_singleton_class)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "Instantiating a singleton class" do
|
|
|
|
it "raises a TypeError when new is called" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
Object.new.singleton_class.new
|
|
|
|
}.should raise_error(TypeError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises a TypeError when allocate is called" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
Object.new.singleton_class.allocate
|
|
|
|
}.should raise_error(TypeError)
|
|
|
|
end
|
|
|
|
end
|