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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/dup_clone'
describe "Kernel#clone" do
it_behaves_like :kernel_dup_clone, :clone
before :each do
ScratchPad.clear
@obj = KernelSpecs::Duplicate.new 1, :a
end
it "calls #initialize_copy on the new instance" do
clone = @obj.clone
ScratchPad.recorded.should_not == @obj.object_id
ScratchPad.recorded.should == clone.object_id
end
it "uses the internal allocator and does not call #allocate" do
klass = Class.new
instance = klass.new
def klass.allocate
raise "allocate should not be called"
end
clone = instance.clone
clone.class.should equal klass
end
describe "with no arguments" do
it "copies frozen state from the original" do
o2 = @obj.clone
o2.should_not.frozen?
@obj.freeze
o3 = @obj.clone
o3.should.frozen?
end
it 'copies frozen?' do
o = ''.freeze.clone
o.frozen?.should be_true
end
end
describe "with freeze: nil" do
it "copies frozen state from the original, like #clone without arguments" do
o2 = @obj.clone(freeze: nil)
o2.should_not.frozen?
@obj.freeze
o3 = @obj.clone(freeze: nil)
o3.should.frozen?
end
it "copies frozen?" do
o = "".freeze.clone(freeze: nil)
o.frozen?.should be_true
end
end
describe "with freeze: true" do
it 'makes a frozen copy if the original is frozen' do
@obj.freeze
@obj.clone(freeze: true).should.frozen?
end
it 'freezes the copy even if the original was not frozen' do
@obj.clone(freeze: true).should.frozen?
end
it "calls #initialize_clone with kwargs freeze: true" do
obj = KernelSpecs::CloneFreeze.new
obj.clone(freeze: true)
ScratchPad.recorded.should == [obj, { freeze: true }]
end
it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
obj = KernelSpecs::Clone.new
-> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
describe "with freeze: false" do
it 'does not freeze the copy if the original is frozen' do
@obj.freeze
@obj.clone(freeze: false).should_not.frozen?
end
it 'does not freeze the copy if the original is not frozen' do
@obj.clone(freeze: false).should_not.frozen?
end
it "calls #initialize_clone with kwargs freeze: false" do
obj = KernelSpecs::CloneFreeze.new
obj.clone(freeze: false)
ScratchPad.recorded.should == [obj, { freeze: false }]
end
it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
obj = KernelSpecs::Clone.new
-> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
describe "with freeze: anything else" do
it 'raises ArgumentError when passed not true/false/nil' do
-> { @obj.clone(freeze: 1) }.should raise_error(ArgumentError, /unexpected value for freeze: Integer/)
-> { @obj.clone(freeze: "") }.should raise_error(ArgumentError, /unexpected value for freeze: String/)
-> { @obj.clone(freeze: Object.new) }.should raise_error(ArgumentError, /unexpected value for freeze: Object/)
end
end
it "copies instance variables" do
clone = @obj.clone
clone.one.should == 1
clone.two.should == :a
end
it "copies singleton methods" do
def @obj.special() :the_one end
clone = @obj.clone
clone.special.should == :the_one
end
it "copies modules included in the singleton class" do
class << @obj
include KernelSpecs::DuplicateM
end
clone = @obj.clone
clone.repr.should == "KernelSpecs::Duplicate"
end
it "copies constants defined in the singleton class" do
class << @obj
CLONE = :clone
end
clone = @obj.clone
class << clone
CLONE.should == :clone
end
end
it "replaces a singleton object's metaclass with a new copy with the same superclass" do
cls = Class.new do
def bar
['a']
end
end
object = cls.new
object.define_singleton_method(:bar) do
['b', *super()]
end
object.bar.should == ['b', 'a']
cloned = object.clone
cloned.singleton_methods.should == [:bar]
# bar should replace previous one
cloned.define_singleton_method(:bar) do
['c', *super()]
end
cloned.bar.should == ['c', 'a']
# bar should be removed and call through to superclass
cloned.singleton_class.class_eval do
remove_method :bar
end
cloned.bar.should == ['a']
end
end
|