Skip to content

Instantly share code, notes, and snippets.

@mboeh
Created July 31, 2012 06:05
Show Gist options
  • Save mboeh/3214170 to your computer and use it in GitHub Desktop.
Save mboeh/3214170 to your computer and use it in GitHub Desktop.
#dup and #clone are so rude!
class Object
private :dup
private :clone
private :freeze
end
module ValueObject
def self.included(into)
into.send :public, :dup
into.send :public, :clone
into.send :public, :freeze
end
end
[Array, Hash, String].each do |value_class|
value_class.send :include, ValueObject
end
module ValueStruct
def initialize(*a)
super(*a)
include ValueObject
end
end
Struct.send :include, ValueStruct
if $0 == __FILE__
require 'test/unit'
class NoDupTest < Test::Unit::TestCase
def test_object_nodup
o = Object.new
assert_raise NoMethodError do
o.dup
end
assert_raise NoMethodError do
o.clone
end
end
def test_own_class_nodup
c = Class.new
o = c.new
assert_raise NoMethodError do
o.dup
end
assert_raise NoMethodError do
o.clone
end
end
def test_value_class_dup
c = Class.new do
include ValueObject
end
assert_nothing_raised do
c.dup
end
end
def test_array_dup
a = [:yes]
assert_equal a.dup.first, :yes
end
def test_hash_dup
h = {:yes => true}
assert h.dup[:yes]
end
def test_string_dup
s = "abc"
assert_equal s.dup, "abc"
end
# FIXME: How can I get ValueObject into every generated Struct class?
def test_struct_dup
s = Struct.new(:a, :b, :c)
o = s.new(1, 2, 3)
assert_equal o.dup.a, 1
end
end
end
# #dup and #clone break encapsulation
class Box
def initialize(size)
@size = size
@items = []
end
def <<(item)
if full?
raise "box is full"
else
@items << item
end
end
def full?
@items.length == @size
end
end
box1 = Box.new 3
box1 << :fork
box1 << :knife
box2 = box1.dup
box2 << :spoon
box1 << :napkin # raises "box is full"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment