ruby--ruby/spec/ruby/language/metaclass_spec.rb

144 lines
3.5 KiB
Ruby

require_relative '../spec_helper'
require_relative '../fixtures/class'
require_relative 'fixtures/metaclass'
describe "self in a metaclass body (class << obj)" do
it "is TrueClass for true" do
class << true; self; end.should == TrueClass
end
it "is FalseClass for false" do
class << false; self; end.should == FalseClass
end
it "is NilClass for nil" do
class << nil; self; end.should == NilClass
end
it "raises a TypeError for numbers" do
lambda { class << 1; self; end }.should raise_error(TypeError)
end
it "raises a TypeError for symbols" do
lambda { class << :symbol; self; end }.should raise_error(TypeError)
end
it "is a singleton Class instance" do
cls = class << mock('x'); self; end
cls.is_a?(Class).should == true
cls.should_not equal(Object)
end
end
describe "A constant on a metaclass" do
before :each do
@object = Object.new
class << @object
CONST = self
end
end
it "can be accessed after the metaclass 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 metaclass opener's scope" do
class << @object
CONST
end
lambda { CONST }.should raise_error(NameError)
end
it "cannot be accessed via object::CONST" do
lambda do
@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
lambda do
@object::CONST
end.should raise_error(NameError)
end
it "appears in the metaclass constant list" do
constants = class << @object; constants; end
constants.should include(:CONST)
end
it "does not appear in the object's class constant list" do
@object.class.constants.should_not include(:CONST)
end
it "is not preserved when the object is duped" do
@object = @object.dup
lambda do
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
describe "calling methods on the metaclass" do
it "calls a method on the metaclass" do
MetaClassSpecs::A.cheese.should == 'edam'
MetaClassSpecs::B.cheese.should == 'stilton'
end
it "calls a method on the instance's metaclass" do
b = MetaClassSpecs::B.new
b_meta = MetaClassSpecs.metaclass_of b
b_meta.send(:define_method, :cheese) {'cheshire'}
b.cheese.should == 'cheshire'
end
it "calls a method in deeper chains of metaclasses" do
b = MetaClassSpecs::B.new
b_meta = MetaClassSpecs.metaclass_of b
b_meta_meta = MetaClassSpecs.metaclass_of b_meta
b_meta_meta.send(:define_method, :cheese) {'gouda'}
b_meta.cheese.should == 'gouda'
b_meta_meta_meta = MetaClassSpecs.metaclass_of b_meta_meta
b_meta_meta_meta.send(:define_method, :cheese) {'wensleydale'}
b_meta_meta.cheese.should == 'wensleydale'
end
it "calls a method defined on the metaclass of the metaclass" do
d_meta = MetaClassSpecs::D.singleton_class
d_meta.ham.should == 'iberico'
end
end