As a rule of thumb, variables exist until you reach the “end” or
closing brace of the innermost block that they’re still contained in.
In your case, you have this:
def do_something
3.times do |x|
number = 10
end
puts number
end
The local variable number is created with the value 10 and then
immediately discarded. This happens three times, since the block
executes three times.
The goal of the next statement is to print a local variable called number. But there is no such local variable in this block. So Ruby
rightfully complains that you didn’t define it. If instead you had
written this:
def do_something
number = 0 # create number in this lexical scope
3.times do |x|
number = 10
end
puts number
end
Why does ruby get confused by the setter v. local variable assignment
when adding a block?
There’s no “setter” here. Both of those are local variable assignments.
In
the second example, the variable is created local to the block. After
the
block ends, the variable ceases to exist.
If you want the variable to exist in the outher block, just create it
there:
class ABC
def do_something
number = 0
3.times do |x|
number = 10
end
puts number
end
end
It’s not a problem - the issue is that number is scoped only to the
3.times
do block. That means that by the time you get to the puts, number is
already
out of scope. Thus Ruby looks for the next alternative which is a
instance
method by the name of number - not finding one it ends up back at
method_missing and thus the loop of death ensues.
Try this instead
class Roulette
def method_missing(name, *args)
person = name.to_s.capitalize
number = nil #you now have “number” scoped at the method level
instead of
the block level
3.times do
number = rand(10) + 1
puts “#{number}…”
end
The parser does not think number is a method by virtue of writing
“puts number”. It tries to invoke a method called number because there
is no local variable named number, because the local variable that you
named number is no longer in scope.
To see this for yourself, consider this snippet:
number = 10
def number
20
end
puts number
=> 10
Notice Ruby correctly picks the local variable named number,
not the method called number.