1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
require File.expand_path('../../spec_helper', __FILE__)
require File.expand_path('../../fixtures/class', __FILE__)
require File.expand_path('../fixtures/metaclass', __FILE__)
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
ruby_version_is ""..."1.9" do
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
end
ruby_version_is "1.9" do
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
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
ruby_version_is "1.9" do
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
end
|