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 ...
endThis 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 # => :fooThe 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 # => :barThis 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 # => trueThis 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!