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
|