Here's some code; can you tell what's wrong with it? I didn't spot the issue for quite a while. To boil it down a bit:
See the issue now? Another variant with no use of attr_accessor
:
With this code, when I run p Foo.new.bar
, I'd expect to get 42
as a result - that's what the buz
instance method is returning, it's not nil
, and so the unless
condition is false
and so the buz = 21
assignment never gets executed. But wrong! Instead, running that program produces output of nil
.
This is a somewhat surprising, but functioning as designed, feature of Ruby shadowing behavior - long story short, local variables shadow instance methods, and crucially, local variable definitions are made when the code is parsed, not when it is executed. The core Ruby docs describe this behavior here, Travis Dahlke has a nice post about it, and it's also briefly mentioned in the Ruby Hacking Guide, although there it refers to "compile time" vs parse time.
Misc notes: A simple fix is to explicitly invoke the instance method. So in the attr_accessor
example, just adding empty parentheses to the last buz
invocation causes Foo.new.bar
to return 42
. And as Ronie Henrich pointed out, in the second example the assignment would need to be either self.buz = 21
or @buz = 21
. I thought Rubocop's shadowing lint cop might find this, but that's different; it's a "local shadows local" check. Also, there's a PR to fix this issue in the docusign_rest project, hats off to Mark Wilson.