In Ruby, what does a top-level assignment do?

2560 views ruby
5

I have the following code at the top-level of a .rb file:

class Times
    def initialize(n)
        @n = n               
    end
    def each()        
        (1..@n).each {yield}
    end
end
three_times = Times.new(3)

def f()
    Times.new(3).each {puts 'Test'}
end
f()

This works, and prints 'Test' three times, as expected. However, if I replace Times.new(3) in f with three_times, i.e. three_times.each {puts 'Test'}, I get an error:

`f': undefined local variable or method `three_times' for main:Object (NameError)

Why does this not work? Why is Times accessible from within f, but not three_times?

More generally, what exactly does an assignment at the top level (e.g. three_times = Times.new(3)) do?

answered question

2 Answers

4

It's because it's looking for a local variable called "three_times". If you wish to make "three_times" to be "top-level" or "global", prepend the variable name with $ so that it's "$three_times".

posted this
1

Because

  • three_times is a local variable
  • local variables are only accessible inside of a specific scope
  • def in ruby creates a new scope

So when f is invoked, it does not see or have access to three_times

To access three_times change it to either a global variable $three_times or an instance variable @three_times

The reason that you are able to reference the class Times is that it is a constant and ruby goes through a separate process of lookup for constants.


Sidestepping issue with def

You could also access the local variable by using a block to define your method, which sidesteps the whole scope gate issue. I do this sometimes when writing rake tasks but rarely do it outside of scripts.

three_times = Times.new(3)
define_method :foo do
  three_times.each { puts 'Tests'}
end
foo

posted this

Have an answer?

JD

Please login first before posting an answer.