Case 1
class A
def initialize(x,y)
@x = x
@y = y
end
def m
@x = 5
@y = 6
end
end
a1 = A.new(1,2)
#=> #<A:0x00005d22a3878048 @x=1, @y=2>
a1.m
a1 #=> #<A:0x00005d22a3878048 @x=5, @y=6>
a2 = A.new(3,4)
#=> #<A:0x00005d22a38b5330 @x=3, @y=4>
a2.m
a2 #=> #<A:0x00005d22a38b5330 @x=5, @y=6>
Then,
a1.instance_variables.all? { |e|
a1.instance_variable_get(e) == a2.instance_variable_get(e) }
#=> true
tells us that the values of @x and the values of @y are the same for both instances.
Case 2
Now let's change the code so that another instance variable is added conditionally.
class A
def initialize(x,y)
@x = x
@y = y
end
def m
@z = 3 if @x == 3
@x = 5
@y = 6
end
end
a1 = A.new(1,2)
#=> #<A:0x000057d1fd563c78 @x=1, @y=2>
a1.m
a1 #=> #<A:0x000057d1fd27f200 @x=5, @y=6>
a2 = A.new(3,4)
#=> #<A:0x000057d1fd57cb38 @x=3, @y=4>
a2.m
a2 #=> #<A:0x000057d1fd2f9e10 @x=5, @y=6, @z=3>
At this point are all instance variables of one of these instances equal to the corresponding instance variable of the other instance? No, because a2 has an additional instance variable, @z. Therefore,
a1.instance_variables.all? { |e|
a1.instance_variable_get(e) == a2.instance_variable_get(e) }
#=> true
gives the wrong answer, for obvious reasons. Perhaps we could test as follows:
a1.instance_variables.all? { |e|
a1.instance_variable_get(e) == a2.instance_variable_get(e) } &&
a2.instance_variables.all? { |e|
a1.instance_variable_get(e) == a2.instance_variable_get(e) }
#=> true && false => false
This has a gotcha, however, if @z equals nil.
Case 3
class A
def initialize(x,y)
@x = x
@y = y
end
def m
@z = nil if @x == 3
@x = 5
@y = 6
end
end
a1 = A.new(1,2)
#=> #<A:0x000057d1fd2d18e8 @x=1, @y=2>
a1.m
a1 #=> #<A:0x000057d1fd2d18e8 @x=5, @y=6>
a2 = A.new(3,4)
#=> #<A:0x000057d1fd46b460 @x=3, @y=4>
a2.m
a2
#=> #<A:0x000057d1fd46b460 @x=5, @y=6, @z=nil>
a1.instance_variables.all? { |e|
a1.instance_variable_get(e) == a2.instance_variable_get(e) } &&
a2.instance_variables.all? { |e|
a1.instance_variable_get(e) == a2.instance_variable_get(e) }
#=> true && true => true
We obtain this incorrect result because:
class A
end
A.new.instance_variable_get(:@z)
#=> nil
We therefore must confirm that if one instance has an instance variable named e, so does the other instance, and that each pair of instance variables with the same name are equal. One way to do that is as follows:
(a1.instance_variables.sort == a2.instance_variables.sort) &&
a1.instance_variables.all? { |e|
a1.instance_variable_get(e) == a2.instance_variable_get(e) }
#=> false && true => false
See Enumerable#all?, Object#instance_variables and Object#instance_variable_get.