DenniJensen DenniJensen - 6 months ago 12
Ruby Question

Referencing global variables in a Ruby script (Block vs Function)

I am building an installation script in Ruby for my dotfiles. To parse some simple flags I use OptionParser.
I want to read the

-f
flag to force an override on existing files. Everything works fine. The Flag will be stored in the
options
hash.

options = {}
option_parse = OptionParser.new do |opt|
opt.on('-f', '--force') do
options[:force] = true
puts 'force overwrite'
end
end
option_parse.parse!


So I refactored my code into functions.
In the functions I can't use
options
without setting it into a global variable.

And now I have two questions:


  1. What is Ruby doing with the variable if I have to define it as global and it is not enough to define it over the function (no classes, just a script)?

  2. Do
    $options
    and
    OPTIONS
    behave the same way in the global context?


Answer

The ruby top-level scope behaves both like a class and like an instance.

When you define methods in that context, they will become private methods on the Object class.

Local variables also behave kind of like in a class. They are local to the class definition, and thus no accessible in the instances (where the methods you define end up).

Variables starting with $ are globals. They are available everywhere. The dollar sign is needed for the interpreter to tell locals and globals apart.

Variables starting with a capital letter are constants. When you create a constant it goes in whatever class or module you're in at the time. Constants can be referred to in the enclosing class or module and any inheriting classes. Constants can also be referred to "from the outside" by using fully qualified names like this: MyModule::MyClass::MyConstant.

Constants differ from globals in the way they are scoped. A constant lives in a class or module, whereas globals are just that - global.

Here are some examples:

$foo  = 'bar'
BAZ   = 'qux'

def x
  puts $foo, BAZ
end

x
# bar
# qux

class A
  B = 'C'
  def self.say
    puts B
  end
  def say
    puts B
  end
end

A.say
# C
A.new.say
# C
puts A::B
# C
puts B
# => raises an error
Comments