Почему Module.methods() и response_to? в irb работает иначе, чем в скрипте?

Я пытаюсь использовать рефлексивные методы в Ruby и сталкиваюсь с поведением, которое я нахожу действительно удивительным.

Следующие примеры работают по-разному в IRB и при вызове ruby-скрипта:

Пример 1:

def myfun; end
p respond_to?(:myfun)

В IRb это говорит «истина», в скрипте: «ложь».

Пример 2:

ml = methods
def myfun; end
p methods - ml

В IRb это говорит [:myfun]. В сценарии: [].

Я нашел это в версиях 1.8, 1.9 MRI, JRuby 1.5.6 и т. д., поэтому я предполагаю, что это нормально.

Почему разница?

Я был уверен, что 'respond_to?' это способ узнать, доступен ли метод - почему это не работает в приведенном выше случае?


person inger    schedule 04.03.2013    source источник


Ответы (1)


Эта функция — метод для «основного» объекта — определена как приватная в скрипте ruby. Вы можете легко это проверить:

ml = private_methods
def myfun; end
p private_methods - ml #=> [:myfun]
p respond_to?(:myfun, true) #=> true

Если вы вызовете его явно для себя, вы получите сообщение об ошибке:

self.myfun
# NoMethodError: private method ‘myfun’ called for main:Object

С другой стороны, в IRB ваш метод определяется как общедоступный. Под капотом это выглядит примерно так:

class Object
  def irb_binding
    # this is where your entered code is evaluated
    def myfun; :ok; end # you can define methods in other methods
    self.myfun # and they are public by default
  end
end

p irb_binding # :ok

IRB мог бы легко выполнить оценку на верхнем уровне, но вместо этого он создает отдельную среду с методом, чтобы локальные переменные не использовались совместно:

require "irb"
foo = :ok
IRB.start
#>> foo
# NameError: undefined local variable or method `foo' for main:Object

Я думаю, что общедоступность методов - это просто совпадение из-за реализации, и это не имеет большого значения. Все равно эти методы временные.

person Simon Perepelitsa    schedule 04.03.2013
comment
Очень приятно знать - это удивительно, я не сталкивался с этим после многих лет воздействия Ruby. Да, мне интересно, почему IRB делает их общедоступными, он пытается быть более дружелюбным - не так ли? :) Я понимаю, почему обычно они являются частными -- чтобы избежать путаницы, как def f;end; класс А;конец; A.new.f или что-то в этом роде? - person inger; 04.03.2013
comment
@Semyon Можете ли вы объяснить, почему методы irb общедоступны? И почему в irb myfun и self.myfun относится к одному и тому же методу? - person Rahul Tapali; 04.03.2013
comment
Для справки: пробовал с Pry. Это согласуется с автономным скриптом: методы верхнего уровня являются закрытыми (поэтому response_to? возвращает false). - person inger; 04.03.2013
comment
@codeit - просто чтобы ответить на последний вопрос, почему myfun и self.myfun относятся к одному и тому же методу - AFAIK, это точно так же, как в Ruby, когда дело доходит до вызова любого метода: если self опущен, он все еще подразумевается. (OTOH: def self.myfun.. будет совершенно другим: метод класса) - person inger; 04.03.2013
comment
Я считаю, что это просто совпадение (из-за реализации), и IRB не планировал этого. Имеет значение только в автономных программах. (почему это другой вопрос :-) - person Simon Perepelitsa; 04.03.2013
comment
@inger Вы имеете в виду, что нет никакой разницы в определении методов self и без методов self в irb. - person Rahul Tapali; 04.03.2013
comment
@SemyonPerepelitsa, когда вы определяете метод в irb и script (скажем, def a; puts "hello"; end). Когда вы вызываете a или self.a в irb, он будет ссылаться на тот же метод. Но не в script. Почему это? Почему классы a и self.a разные? - person Rahul Tapali; 04.03.2013
comment
Они относятся к одному и тому же методу в обоих сценариях. В сценарии это просто приватно: вы не можете вызвать его с явным получателем (self.a). Я не знаю, что вы подразумеваете под классом методов. - person Simon Perepelitsa; 04.03.2013
comment
Я расширил свой ответ, проверьте его, если вам все еще интересно узнать о реализации IRB. - person Simon Perepelitsa; 15.04.2013