The first issue isn't really surprising once you understand how Ruby treats variables. I wrote about this a while ago for a more understandable case - basically, Ruby initializes variables to nil as soon as a left-hand assignment is encountered during a scope's parsing, regardless of context or reachability.
def foo
if false
bar = "baz"
end
lambda { bin = "bang" }.call
return local_variables, bar
end
def foo_two
if false
bar = "baz"
end
lambda { bar = "bonk" }.call
return local_variables, bar
end
puts foo.inspect
puts foo_two.inspect
=> [["bar"], nil]
[["bar"], "bonk"]
Obviously the code that initializes bar never gets run, but Ruby initializes a local variable "bar" anyway, since there is a left-hand assignment to it present in the method. The lamba defines a new scope, so its local variable assignments don't leak to its containing scope, but in that scope, unless there was a variable named bin initialized in the outer scope already, which is the case for the lambda in foo_two, which leaks the bar reference to its containing scope since bar was defined in the outer scope at the time of the lamba's definition.
http://www.coffeepowered.net/2009/03/02/syntactic-sugar-will...
Here's a cleaner way to visualize it:
Obviously the code that initializes bar never gets run, but Ruby initializes a local variable "bar" anyway, since there is a left-hand assignment to it present in the method. The lamba defines a new scope, so its local variable assignments don't leak to its containing scope, but in that scope, unless there was a variable named bin initialized in the outer scope already, which is the case for the lambda in foo_two, which leaks the bar reference to its containing scope since bar was defined in the outer scope at the time of the lamba's definition.