Почему мой метод верхнего уровня общедоступен (в отличие от частного) во всех классах, когда я объявляю его в IRB? - PullRequest
0 голосов
/ 31 декабря 2018

В данный момент я читаю «Обоснованный рубин», и на странице 196 я вижу следующее:

Предположим, вы определили метод на верхнем уровне:

def talk
  puts "Hello"
end

....

Метод, который вы определяете на верхнем уровне, сохраняется как метод частного экземпляра класса Object.Предыдущий код эквивалентен этому:

class Object

  private

  def talk
    puts "Hello"
  end
end

...

Для иллюстрации давайте расширим пример talk.Здесь снова, с некоторым кодом, который его реализует:

puts "Trying 'talk' with no receiver..."
talk
puts "Trying 'talk' with an explicit receiver..."
obj = Object.new
obj.talk

Первый вызов talk успешен;второй сбой приводит к фатальной ошибке, потому что он пытается вызвать закрытый метод с явным получателем.

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

$ ruby talk.rb 
Trying 'talk' with no receiver...
Hello
Trying 'talk' with an explicit receiver...
Traceback (most recent call last):
talk.rb:22:in `<main>': private method `talk' called for #<Object:0x00007f9a8499c3e0> (NoMethodError)

Я также попробовал следующее, что привело к той же ошибке, что и запуск кода через интерпретатор Ruby:

irb(main):008:0> load 'talk.rb'
Trying 'talk' with no receiver...
Hello
Trying 'talk' with an explicit receiver...
Traceback (most recent call last):
        4: from /Users/richiethomas/.rbenv/versions/2.5.3/bin/irb:11:in `<main>'
        3: from (irb):8
        2: from (irb):8:in `load'
        1: from talk.rb:22:in `<top (required)>'
NoMethodError (private method `talk' called for #<Object:0x00007ffb219c95e0>)

ДалееЯ попробовал тот же код в irb, и на этот раз я получил следующие странные результаты:

irb(main):001:0> def talk
irb(main):002:1> puts "Hello"
irb(main):003:1> end
=> :talk
irb(main):004:0> puts "Trying 'talk' with no receiver..."
Trying 'talk' with no receiver...
=> nil
irb(main):005:0> talk
Hello
=> nil
irb(main):006:0> puts "Trying 'talk' with an explicit receiver..."
Trying 'talk' with an explicit receiver...
=> nil
irb(main):007:0> Object.new.talk
Hello
=> nil

Как вы можете видеть, в последнем примере кода я смог вызвать Object.new.talk ипусть он напечатает Hello, как если бы .talk был публичным методом в экземпляре Object.

Мой вопрос: почему метод talk общедоступен в классе Object, когда я реализую его непосредственно вREPL, но закрытый, когда я внедряю его в файл и загружаю в REPL (а также когда я запускаю тот же файл непосредственно в моем CLI через интерпретатор Ruby)?

1 Ответ

0 голосов
/ 31 декабря 2018

И irb, и pry ( sidenote: Я настоятельно рекомендую использовать последнее) настраивают их ввод, чтобы объявить все методы как публичные (во время E стадия цикла REP):

▶ def foo; end
#⇒ :foo
▶ public_methods.grep /foo/
#⇒ [:foo]

Вот и все, никакой магии.


Это делается главным образом для упрощения игры с ним в сценариях, когда определяетсяметод здесь и тогда хочет, чтобы он был доступен, например, оттуда.В REPL стоит сделать все доступным везде.

def pretty_print; self.inspect; end
class A; ...; end
class B; ...; end

A.new.pretty_print
B.new.pretty_print

Не следует обращать слишком много внимания на инкапсуляцию, SRP и т. Д. Во время игры в песочнице.


В общем, это все равно что объявить модуль с помощью общих помощников и включить его везде бесплатно.

...