Где методы определены на верхнем уровне ruby? - PullRequest
7 голосов
/ 19 ноября 2009

На верхнем уровне определение метода должно приводить к приватным методам на Object, и тесты, похоже, подтверждают это:

def hello; "hello world"; end

Object.private_instance_methods.include?(:hello) #=> true
Object.new.send(:hello) #=> "hello world"

Однако на верхнем уровне также работает следующее (self.meta - это собственный класс main):

self.meta.private_instance_methods(false).include?(:hello) #=> true

Похоже, что метод hello одновременно определяется как на собственном классе main, так и на Object. В чем дело? Обратите внимание, что параметр false для private_instance_methods исключает методы суперкласса из списка методов.

1 Ответ

8 голосов
/ 19 ноября 2009

Прежде всего, это поведение и лежащие в его основе рассуждения существовали всегда; В 1.9 нет ничего нового. Техническая причина, по которой это происходит, заключается в том, что main особенный и обрабатывается иначе, чем любой другой объект. Нет никакого причудливого объяснения: он ведет себя так, потому что он был спроектирован таким образом.

Хорошо, но почему? В чем причина main быть волшебным? Поскольку дизайнер Ruby Юкихиро Мацумото считает, что делает язык лучше , чтобы иметь такое поведение:

Это так, почему методы верхнего уровня не сделаны одноэлементными методами для этого объекта, вместо того, чтобы тянуть в качестве методов экземпляра в классе Object сам (и, следовательно, во все другие классы, т. е. загрязнение пространства имен больше, чем обычно предназначен). Это все еще позволило бы методам верхнего уровня вызывать другие методы верхнего уровня. И если объект верхнего уровня был упомянут немного константа, как Main, то эти методы могут быть вызваны из любого места с Main.method (...).

Вы действительно хотите напечатать "Main.print" везде?

Далее в обсуждении он объясняет, что он ведет себя так, потому что он чувствует, что «предположение естественно».

EDIT:

В ответ на ваш комментарий ваш вопрос направлен на то, почему собственный класс main, по-видимому, сообщает hello как метод частного экземпляра. Подвох в том, что ни одна из функций верхнего уровня на самом деле не добавляется в main, а напрямую в Object. При работе с собственными классами семейство функций instance_methods всегда ведет себя так, как будто собственный класс все еще является исходным классом. То есть методы, определенные в классе, обрабатываются как определенные непосредственно в собственном классе. Например:

class Object
  private
  def foo
    "foo"
  end
end

self.send :foo  # => "foo"
Object.private_instance_methods(false).include? :foo  # => true
self.meta.private_instance_methods(false).include? :foo  # => true

class Bar
  private
  def bar
    "bar"
  end
end

bar = Bar.new
bar.send :bar  # => "bar"
Bar.private_instance_methods(false).include? :bar  # => true
bar.meta.private_instance_methods(false).include? :bar  # => true

Однако мы можем добавить метод непосредственно к собственному классу main. Сравните ваш оригинальный пример с этим:

def self.hello; "hello world"; end

Object.instance_methods.include? :hello  # => false
self.meta.instance_methods.include? :hello  # => true

Хорошо, но что, если мы действительно хотим знать, что данная функция определена в собственном классе, а не в исходном классе?

def foo; "foo"; end  #Remember, this defines it in Object, not on main
def self.bar; "bar"; end  #This is defined on main, not Object

foo  # => "foo"
bar  # => "bar"

self.singleton_methods.include? :foo  # => false
self.singleton_methods.include? :bar  # => true
...