Ruby does not have any entry point to the code it is executing. Compare that to other languages like C, C++, Java, etc., which has a main() method in some way. And this main() is the entry point to the code. But in Ruby, we can open a file with a .rb extension and write our code at the top-level like:

foo = 'Great Scott!'
puts foo # => Great Scott!

... and Ruby will execute the file for us. You'll get introduced to this top-level scope as global scope throughout most tutorials. Even though the intention is correct, the terminology as global scope may be slightly confusing. I feel that it's better if we just stick to calling it the top-level instead of the global scope. Here's why.

When you write any code in the top-level, Ruby will quietly wrap the Object class around it. That is:

# ... some code ...

... loosely becomes:

class Object
  # ... some code ...
end

This means that whatever you do in the top-level, you're essentially just monkey-patching the Object class. The historical/philosophical reason behind this decision might be that Matz wanted everything to be an object in Ruby. Which is why you can see that even things like classes, modules, functions, etc., are all objects. And so it would make sense that any code lying at the top-level should also belong to an object in some way, and thus the Object class.

There are implications to this decision. Continue reading the below mentioned concepts affected due to this decision to connect the dots.

Method definition

When you define methods in the top-level:

def foo
  :foo
end

... then they will be available on every object:

42.foo # => :foo
3.14.foo # => :foo
'Ka-Chow!'.foo # => :foo
true.foo # => :foo
[].foo # => :foo

class FooBar; end
FooBar.new.foo # => :foo

The reason is because when we defined the foo method in the top-level, the effect was of monkey-patching the Object class. And since every other class in Ruby is a descendant of the Object class, it was available on every object.

Module inclusion

When you have a module:

module Foo
  def bar
    :bar
  end
end

... and you include it in the top-level:

include Foo

... then the methods defined inside of the module will be available on every object:

42.bar # => :bar
3.14.bar # => :bar
'SHAZAM!'.bar # => :bar
true.bar # => :bar
[].bar # => :bar

class FooBar; end
FooBar.new.bar # => :bar

This is also because of the same reason that when we include-ed the Foo module in the top-level, the effect was of include-ing it inside of the Object class. This allowed every object to have access to the bar method defined inside of the Foo module.

Constant definition

When you define any sort of constants in the top-level:

FOO = 42
class Bar; end
module Baz; end

... they get scoped by the Object class:

FOO == Object::FOO # => true
Bar == Object::Bar # => true
Baz == Object::Baz # => true

This is again because of the same reason that defining constants in the top-level is the same thing as re-opening the Object class and defining those inside of it since Ruby will quietly wrap everything in the top-level by the Object class.

Ruby is weird, and that's why we love it!


References