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
There are implications to this decision. Continue reading the below mentioned concepts affected due to this decision to connect the dots.
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.
When you have a module:
module Foo def bar :bar end end
... and you
include it in the top-level:
... 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
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
When you define any sort of constants in the top-level:
FOO = 42 class Bar; end module Baz; end
... they get scoped by the
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
Ruby is weird, and that's why we love it!