Ruby local variable is undefined

Sergii Shevchyk picture Sergii Shevchyk · Mar 12, 2012 · Viewed 39.2k times · Source

I have the following Ruby code:

local_var = "Hello"

def hello
  puts local_var
end

hello

I get the following error:

local_variables.rb:4:in 'hello': undefined local variable or method 'local_var' 
for main:Object (NameError) from local_variables.rb:7:in '<main>'

I always thought that local variables are not accessible from outside of the block, function, closure, etc.

But now I defined local variable in the file and try to get an access from the function INSIDE the same file.

What's wrong with my understanding?

Answer

emre nevayeshirazi picture emre nevayeshirazi · Mar 12, 2012

In Ruby local variables only accessible in the scope that they are defined. Whenever you enter/leave a Class, a Module or a Method definiton your scope changes in Ruby.

For instance :

v1 = 1

class MyClass # SCOPE GATE: entering class
  v2 = 2
  local_variables # => ["v2"]

  def my_method # SCOPE GATE: entering def
    v3 = 3
    local_variables  # => ["v3"]
  end # SCOPE GATE: leaving def

  local_variables # => ["v2"]
end # SCOPE GATE: leaving class

These entering and leaving points are called Scope Gates. Since you enter through Scope Gate via method definition you cannot access your local_var inside hello method.


You can use Scope Flattening concept the pass your variable through these gates.

For instance instead of using def for defining your method you can use Module#define_method.

local_var = "Hello"

define_method :hello do
  puts local_var
end

In the same way you can define your classes via Class#New so that your scope does not change when you pass through class definition.

local_var = 'test'

MyClass = Class.new do
  puts local_var #valid
end

instead of

class MyClass
  puts local_var #invalid
end

In the same way you should use Module#New if you want to pass your local variables through Module gates.

Example is taken from Metaprogramming Ruby