summaryrefslogtreecommitdiff
path: root/spec/ruby/core/class/new_spec.rb
blob: 989d674558f20c2dca263eb4c1c887b06b76dc3a (plain)
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
require_relative '../../spec_helper'
require_relative 'fixtures/classes'

describe "Class.new with a block given" do
  it "yields the new class as self in the block" do
    self_in_block = nil
    klass = Class.new do
      self_in_block = self
    end
    self_in_block.should equal klass
  end

  it "uses the given block as the class' body" do
    klass = Class.new do
      def self.message
        "text"
      end

      def hello
        "hello again"
      end
    end

    klass.message.should == "text"
    klass.new.hello.should == "hello again"
  end

  it "creates a subclass of the given superclass" do
    sc = Class.new do
      def self.body
        @body
      end
      @body = self
      def message; "text"; end
    end
    klass = Class.new(sc) do
      def self.body
        @body
      end
      @body = self
      def message2; "hello"; end
    end

    klass.body.should == klass
    sc.body.should == sc
    klass.superclass.should == sc
    klass.new.message.should == "text"
    klass.new.message2.should == "hello"
  end

  it "runs the inherited hook after yielding the block" do
    ScratchPad.record []
    klass = Class.new(CoreClassSpecs::Inherited::D) do
      ScratchPad << self
    end

    ScratchPad.recorded.should == [CoreClassSpecs::Inherited::D, klass]
  end
end

describe "Class.new" do
  it "creates a new anonymous class" do
    klass = Class.new
    klass.is_a?(Class).should == true

    klass_instance = klass.new
    klass_instance.is_a?(klass).should == true
  end

  it "raises a TypeError if passed a metaclass" do
    obj = mock("Class.new metaclass")
    meta = obj.singleton_class
    -> { Class.new meta }.should raise_error(TypeError)
  end

  it "creates a class without a name" do
    Class.new.name.should be_nil
  end

  it "creates a class that can be given a name by assigning it to a constant" do
    ::MyClass = Class.new
    ::MyClass.name.should == "MyClass"
    a = Class.new
    MyClass::NestedClass = a
    MyClass::NestedClass.name.should == "MyClass::NestedClass"
  end

  it "sets the new class' superclass to the given class" do
    top = Class.new
    Class.new(top).superclass.should == top
  end

  it "sets the new class' superclass to Object when no class given" do
    Class.new.superclass.should == Object
  end

  it "raises a TypeError when given a non-Class" do
    error_msg = /superclass must be a Class/
    -> { Class.new("")         }.should raise_error(TypeError, error_msg)
    -> { Class.new(1)          }.should raise_error(TypeError, error_msg)
    -> { Class.new(:symbol)    }.should raise_error(TypeError, error_msg)
    -> { Class.new(mock('o'))  }.should raise_error(TypeError, error_msg)
    -> { Class.new(Module.new) }.should raise_error(TypeError, error_msg)
  end
end

describe "Class#new" do
  it "returns a new instance of self" do
    klass = Class.new
    klass.new.is_a?(klass).should == true
  end

  it "invokes #initialize on the new instance with the given args" do
    klass = Class.new do
      def initialize(*args)
        @initialized = true
        @args = args
      end

      def args
        @args
      end

      def initialized?
        @initialized || false
      end
    end

    klass.new.should.initialized?
    klass.new(1, 2, 3).args.should == [1, 2, 3]
  end

  it "uses the internal allocator and does not call #allocate" do
    klass = Class.new do
      def self.allocate
        raise "allocate should not be called"
      end
    end

    instance = klass.new
    instance.should be_kind_of klass
    instance.class.should equal klass
  end

  it "passes the block to #initialize" do
    klass = Class.new do
      def initialize
        yield
      end
    end

    klass.new { break 42 }.should == 42
  end
end