Niklas B.
Niklas B.

Reputation: 95298

Ruby global scope

When answering another question, I realized that the following program does not quite do what I thought it does.

puts "test"
self.puts "test"  # => private method `puts' called for main:Object (NoMethodError)

The exception surprises me, as I always thought that top-level method calls would be resolved by the main object instance, but this doesn't seem to be the case.

Who's the actual receiver of the first call and how is it resolved? Is this a special rule that only applies to method calls at the top-level scope?

Upvotes: 6

Views: 1494

Answers (1)

mguymon
mguymon

Reputation: 9015

Here is a good discussion that talks about this question.

The top level methods, which are provided by Kernel, are automatically included to the Object class. This means the Kernel methods will appear in everything.

The error private method 'puts' called for main:Object (NoMethodError) is just stating that puts exists but is privately scoped.

ree-1.8.7-2011.03 :001 > puts "test"
test
ree-1.8.7-2011.03 :004 > self.send(:puts, "hi" )
hi

UPDATE

There is no magic for Kernel methods. There is no scope hopping or anything. I think the confusion lines in what the scope is when using self. You do not have access to private methods using self.

class PutsTest

  def success_puts
    private_puts
  end

  def failed_puts
    # trying to access a private method from self
    self.private_puts
  end

  private

  def private_puts
   puts 'hi'
  end
end

By using self, you are changing the scope from calling the method inside of PutsTest to calling from the outside of PutsTest

ree-1.8.7-2011.03 :095 > test = PutsTest.new
ree-1.8.7-2011.03 :096 > test.success_puts
hi
ree-1.8.7-2011.03 :097 > test.failed_puts
NoMethodError: private method `private_puts' called for #<PutsTest:0xd62c48>

Upvotes: 5

Related Questions