Защо Module.methods() и respond_to? работи по различен начин в irb отколкото в скрипт?

Опитвам се да използвам отразяващи методи в Ruby и се натъквам на поведение, което намирам за наистина изненадващо.

Следните примери изглежда работят по различен начин в IRB и когато се наричат ​​рубинен скрипт:

Пример 1:

def myfun; end
p respond_to?(:myfun)

В IRb това казва „true“, в скрипта: „false“.

Пример 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.. Това е в съответствие със самостоятелния скрипт: методите от най-високо ниво са лични (така че respond_to? връща false). - person inger; 04.03.2013
comment
@codeit - само за да отговоря на последния въпрос защо myfun и self.myfun се отнасят за един и същи метод - AFAIK, това е точно така в Ruby, когато става въпрос за извикване на който и да е метод: ако self е пропуснат, той все още е impied. (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