In Ruby, all methods have a receiver. In the case where no receiver is explicitly specified, it is assumed to be `self` - thus line 7 of semiquaver's example desugars to `self.puts "hello"`. This is the "default object," referred to in
Metaprogramming Ruby as the "implicit receiver."
Since `self.class == Foo` at line 7, we must check that `self.class` (which is Foo) either defines an instance method `:puts`, or that some Module included in its ancestor list can `respond_to?(:puts)`:
Foo.ancestors.map { |a| [a, a.is_a?(Class) ? a.instance_methods.include?(:puts) : a.respond_to?(:puts)] }
=> [[Foo, true], [Object, false], [Kernel, true], [BasicObject, false]]
We find that `Foo.instance_methods.include?(:puts)`, and so that is the method that ends up being invoked:
Foo.instance_method(:puts).source_location
=> ["(irb)", 2] # line 2 of semiquaver's example
Consider now the class Bar:
class Bar
def initialize
puts "hello"
end
end
... and notice that it does not contain any instance method `puts`:
Bar.instance_method(:puts).source_location
=> nil
Thus, unlike in the case of Foo, we need to traverse `Bar.ancestors` until we find a suitable definition for the method `:puts`:
Bar.ancestors.map { |a| [a, a.is_a?(Class) ? a.instance_methods.include?(:puts) : a.respond_to?(:puts)] }
=> [[Bar, false], [Object, false], [Kernel, true], [BasicObject, false]]
We find that Kernel responds to the method :puts, and so that will be the method invoked when we call `Bar.new`. We can patch Kernel to see what happens when we call Bar.new:
module Kernel
alias_method :orig_puts, :puts
def puts(*args)
orig_puts "Receiver #{self.inspect}"
orig_puts(*args)
end
end
Bar.new
Receiver #<Bar:0x000000012006eae8>
hello
=> #<Bar:0x000000012006eae8>
Notice that `self`, the
implicit receiver or "default object," is in fact an instance of the class `Bar`, even though the actual method invoked after going up the `Bar.ancestors` chain is on Kernel.
Hence, there are no globals - every method is invoked on some `self`, explicit or implicit, and method lookup goes up the ancestor chain until you bottom out at Kernel or BasicObject. Note that Kernel is itself an Object.
This is still an oversimplification. I recommend reading Metaprogramming Ruby and playing around in a REPL after reading the docs on Object, Class, Module, and BasicObject.