I was just talking to @dchelimsky over Twitter about a weird corner case
we’ve run into on 1.3.1 (I’ve also been able to reproduce it in 1.3.2)
So we’re using this gem called ClassyStruct that’s a higher performing
OpenStruct:
Basically it acts the same as OpenStruct but defines methods on the
object’s class instead of the object itself on the fly.
When it receives a call that hits method_missing it calls attr_accessor
on the method name then passes the call on to the object.
Our problem comes from having one spec that stubs out a call to the
object:
foo.stub! :bar => ‘test’
and later in another spec file trying to set the same method with a
value then having our code use that value:
spec
foo.bar = ‘other test’
code
puts “#{foo.bar} baz”
So our expectation is that foo.bar will return ‘other test’. Instead it
hits the old stub on foo which calls method_missing which is picked up
again by ClassyStruct causing it to fire off attr_accessor again then
passing the method through causing the stub to call method_missing and
on and on finally giving us a “stack level too deep” error.
The crux of the problem is that ClassyStruct is adding a method to the
class after Rspec has added the same method to the instance.
As I said it’s a very weird corner case because we’re calling
attr_accessor on a class that already has objects floating around. The
easiest way to fix this is to use stub! in both places.
Regardless we were surprised that the proxy sticks around after a test
run. What is the reason for keeping it around?
Our problem comes from having one spec that stubs out a call to the object:
The crux of the problem is that ClassyStruct is adding a method to the class
after Rspec has added the same method to the instance.
As I said it’s a very weird corner case because we’re calling attr_accessor on a
class that already has objects floating around. The easiest way to fix this is to
use stub! in both places.
Regardless we were surprised that the proxy sticks around after a test run. What
is the reason for keeping it around?
There’s no intent to keep it around, so there is a bug at play here, but
let’s see if we can narrow it down.
Can you post (gist or pastie) an example that I can just run as/is to
see the behavior you’re seeing?
NoMethodError in ‘TestClass fails after the stub’
undefined method foo' for #<TestClass:0x00000101180158> test.rb:28:inblock (2 levels) in <top (required)>’