-
-
Save teancom/5500095 to your computer and use it in GitHub Desktop.
# This one works | |
class DiceSet | |
def roll(size) | |
@dice = [] | |
size.times do |x| | |
@dice[x] = rand(1..6) | |
end | |
end | |
def values | |
@dice | |
end | |
end | |
vs | |
# This one doesn't (i.e., the test fails) - when run from within the koan test | |
# It totally works fine when run in irb | |
class DiceSet | |
def initialize | |
@dice = [] | |
end | |
def roll(size) | |
size.times do |x| | |
@dice[x] = rand(1..6) | |
end | |
end | |
def values | |
@dice | |
end | |
end | |
def test_dice_values_should_change_between_rolls | |
dice = DiceSet.new | |
dice.roll(5) | |
first_time = dice.values | |
dice.roll(5) | |
second_time = dice.values | |
assert_not_equal first_time, second_time, | |
"Two rolls should not be equal" | |
end |
Ok this is my theory.
@dice = []
that creates a reference to a new Array Object
in the initialize method only one Array Object is created
and referenced by @dice.
So every time you call roll, it updates that Array Object and the @dice always refers the same Array Object
regardless of the contents of the array.
So then in the test, another reference is created to the same object using the variable first_time and then another
reference is created using the variable second_time.
so when dice.roll(5) is called before second_time is assigned the reference, the variable first_time's reference to the
same object is updated.
So it is the second dice.roll(5) that makes first_time and second_time the same value.
In the original code because @dice = [] each time in the roll method a new Array Object is assigned to @dice each time.
The result being that first_time and second_time don't reference the same Array Object.
That makes a ton of sense, Carlo. Thanks!
Proof that the "broken" one works just fine in IRB, when I do exactly what the test is doing:
irb(main):001:0> class DiceSet
irb(main):002:1>
irb(main):003:1* def initialize
irb(main):004:2> @dice = []
irb(main):005:2> end
irb(main):006:1>
irb(main):007:1* def roll(size)
irb(main):008:2> @dice.clear
irb(main):009:2> size.times do |x|
irb(main):010:3* @dice[x] = rand(1..6)
irb(main):011:3> end
irb(main):012:2> end
irb(main):013:1>
irb(main):014:1* def values
irb(main):015:2> @dice
irb(main):016:2> end
irb(main):017:1>
irb(main):018:1* end
=> nil
irb(main):019:0> dice=DiceSet.new
=> #<DiceSet:0x007fe2338c91d8 @dice=[]>
irb(main):020:0> dice.roll(5)
=> 5
irb(main):021:0> dice.values
=> [4, 2, 6, 5, 3]
irb(main):022:0> dice.roll(5)
=> 5
irb(main):023:0> dice.values
=> [3, 6, 1, 4, 6]
irb(main):024:0>