Stubbing sequential method calls with RR

I recently found myself with the need to have a stubbed method return different values depending on the order it was called in. So that the first time the method is called, it returns one thing and the next time it returns another.

With Mocha this is neatly done using Exception#then:

object.stubs(:expected_method).returns(1, 2).then.returns(3)

However, I am using RR and that doesn’t provide any syntactic sugar for this. Thankfully, Laust showed me a way that is almost as clean:

values = [42, 37, 3.14]
stub(object).counter do
  values.shift
end
object.counter # => 42
object.counter # => 37
object.counter # => 3.14

This is useful if for example you need to mock out that a model can only be saved once, and it’ll raise an exception after the first save:

results = [lambda{ true }, lambda{ raise "Cannot be saved twice" }]
mock(model).save.times(results.size) do
  results.shift.call
end
model.save # => true
model.save # Raises an exception