My understanding was that ruby blocks have block scope, and all variables created inside block will live only within the block.
Example case:
food = ['toast', 'cheese', 'wine']
food.each { |food| puts food.capitalize}
puts food
Output:
"Toast"
"Cheese"
"Wine"
"Wine"
If you take the food
variable inside the block (Each block), my understanding was that it has block scope. It lives only within the block scope, and does not have any influence on the outer variable food
.
But the behavior is different, the outer variable named food
is modified in this case. Is this understanding correct, In ruby do we have block scope?
This is expected behaviour for ruby 1.8. It was fixed in 1.9. Snippets below are run with ruby 1.9.3
food = ['toast', 'cheese', 'wine']
food.each { |food| puts food.capitalize.inspect} # !> shadowing outer local variable - food
puts food.inspect
# >> "Toast"
# >> "Cheese"
# >> "Wine"
# >> ["toast", "cheese", "wine"]
You are correct, food
from the block is scoped to that block and shadows other variables with this name. But if you do something destructive to it, it will be reflected in the original array, because it is reference to array element, not its copy. Observe:
food = ['toast', 'cheese', 'wine']
food.each { |f| f.capitalize} # transform and discard
food # => ["toast", "cheese", "wine"]
food.each { |f| f.capitalize! } # transform destructively (bang-version)
food # => ["Toast", "Cheese", "Wine"]