It seems that you cannot create a local variable dynamically in ruby using eval with a binding.
Here’s an example from an IRB session:
irb(main):001:0> def make_a(b) irb(main):002:1> eval "a = 'this is a!'", b irb(main):003:1> end => nil irb(main):004:0> a NameError: undefined local variable or method `a' for main:Object from (irb):4 from :0 irb(main):005:0> make_a(binding) => "this is a!" irb(main):006:0> a => "this is a!" irb(main):007:0> def test_a irb(main):008:1> a = 10 irb(main):009:1> make_a(binding) irb(main):010:1> puts a irb(main):011:1> end => nil irb(main):012:0> test_a this is a! => nil irb(main):013:0> def test_a irb(main):014:1> make_a(binding) irb(main):015:1> puts a irb(main):016:1> end => nil irb(main):017:0> test_a NameError: undefined local variable or method `a' for main:Object from (irb):15:in `test_a' from (irb):17 from :0 irb(main):018:0>
The last NameError in that IRB session makes no sense to me. I have tried this in Ruby 1.8.6 and in Ruby 1.9.1 and both give the same result.
Can somebody explain what is going on here? Are there any known workarounds for this? I was trying to DRY up some particularly repetitive code, part of which involves initializing a local variable, when I stumbled upon this. I’m having trouble finding blog posts that explain this unexpected behavior, and none of the official documentation that I’ve looked at for Binding and eval seem to point out that you cannot declare local variable in such a manner.
Here’s a stripped down version of the code if you want to put it in your own IRB session and play with it:
def make_a(b) eval "a = 'this is a!'", b end a make_a(binding) a def test_a a = 10 make_a(binding) puts a end test_a def test_a make_a(binding) puts a end test_a