A local variable is any variable beginning with a lowercase letter. It exists within the lexical scope that it is initially used. Any other code within that scope can refer to a local variable first used in that scope. The "scope" referred to here is roughly equivalent to the indentation level of your code. As long as a variable is first used in a scope at or above the current scope, it can be used.
For every location in Ruby code, there is what's referred to as a "binding." This binding holds the state of that particular scope. The variables defined there, as well as methods, the object self refers to and various other things are stored in the "binding." This is also referred to as an "execution context."
Understanding bindings is important in understanding variables scopes in Ruby. In a typical method defined outside of any classes, the binding refers to only that method. Therefor, any local variable declarations are declared in that binding. If you were to prepend a symbol to any variable accesses such as the $ (dollar sign), Ruby would then go to the global variable binding to resolve that variable access. At any given time, there is a local binding, a global binding and perhaps an instance or class binding.
But the topic of discussion here is the local variable. One way to think of the scope of local variables is to look at the blocks in your Ruby code. Each new block creates a new lexical scope, and a new binding. The variable x referred to in one block is a different variable x in another block, because they refer to different variables named x in different bindings.
A more practical way of thinking about it is that variables at the same indentation level refer to the same values. And yet another way to think about it is the stack. In many languages, such as C, local variables exist on the stack. Each new block is a new stack context. In each stack context, you cannot refer to the variables in a different stack context.
But in the end, the way Ruby handles local variables should come to no surprise if you've done any programming in another language. All languages have local variables and, for the most part, they all work in the same way even if they're implemented differently under the hood.
In the following example, several variables are declared and are referenced. The comments preceding each line tell whether the reference to that variable will fail or not.
#!/usr/bin/env ruby def meth1 # This variable will be referenced a = 1337 # Variable in same scope: OK puts a 10.times do # Variable in parent scope: OK puts a end end def meth2 10.times do a = 10 end # Variable in child scope: FAIL puts a end meth1 meth2
One thing to note is that other variable scopes in Ruby behave a bit differently if you try to read an unknown variable. For instance, if you were to try to read the variable $doesnotexist (a global variable, since it begins with $, the dollar sign) you would get nil if nothing has assigned to the variable yet. The variable didn't exist at all, but it returns nil. The same is true for instance variables (those beginning with @, the at sign). If you try to read an instance variable before assigning a value to it, you will get the value nil.
The same is not true for local variables. If you try to read a local variable that doesn't exist, Ruby will raise an exception. And while it's not customary for Rubyists to declare all variables used in a method at the beginning of the method (as it would be for C programmers), it is customary to make these variable declarations visible. So, as long as you remember to assign values (even 0 or nil) to your local variables before use and keep those assignments visible, you shouldn't have any problems.
Was it Defined?
With all this discussion of declaring (or defining) variables, nothing was discussed of Ruby's reflective powers in this regard. The defined? operator takes a variable name and, if an entry for it is found in the current binding, will return true. Otherwise, it will return false. This is not often used for local variables, as Rubyists tend to break methods up into such small chunks that it's simple to tell at the time the method is composed whether a variable is defined. However, it's here in your toolbox, you may find use for it.
Local variables can also begin with the _ (underscore) character. Though this is not common, this may be particularly useful for referring to things that must be capitalized, such as calculations involving Henries (a unit of inductance, referred to with the capital H) and hours (a unit of time, referred to with a lowercase h). Remember that local variables cannot begin with capital letters, that would define a constant.