Вкратце: переопределение !
вне класса — это очень странная вещь! Существует бесчисленное множество способов «сломать» ruby, делая подобные сумасшедшие вещи, так что вам может показаться забавным экспериментировать с такими странными идеями, но, очевидно, не делайте этого в важном коде!
В ruby все классы наследуются от базового класса верхнего уровня: BasicObject
. Этот класс определяет отрицание объекта верхнего уровня, т.е. всякий раз, когда вы записывать
!foo
на самом деле это вызов метода с именем !
для вашего объекта foo
:
foo.send(:!)
Это позволяет (хотя это делается очень редко!) переопределить метод для конкретного класса. Например, при реализации шаблона пустой объект вы можете сделать что-то вроде этого:
class NullObject
def !
true
end
end
my_null = NullObject.new
!!my_null #=> false
(Обычно единственными объектами, которые возвращают false
в приведенной выше строке, являются nil
и false
!)
А теперь вернемся к вашему примеру. На самом деле здесь вы определили метод с именем !
в классе Object
(и не вызывали super
для запуска исходного метода!). Другими словами, вы фактически переопределили ответ как фундаментальный метод, который используется повсеместно внутри. Что-то, где-то (??) запуталось в этом странном поведении и не изящно потерпело неудачу.
irb(main):001:0> def !
irb(main):002:1> puts "foo"
irb(main):003:1> super # <-- !! This stops it from breaking completely !!
irb(main):004:1> end
=> :!
irb(main):005:0* method(:!)
foo
foo
=> #<Method: Object#!>
irb(main):006:0> method(:!).source_location
foo
foo
=> ["(irb)", 1]
irb(main):007:0> method(:!).super_method
foo
foo
=> #<Method: BasicObject#!>
Вот несколько других способов, которыми вы могли бы переопределить методы, чтобы вызвать странное поведение/ошибки, например:
def nil?
true
end
# Will now die in weird ways!
class String
def ===(other)
true
end
end
"ruby" === "awesome"
#=> true
person
Tom Lord
schedule
28.03.2018
BasicObject#!
- person Stefan   schedule 28.03.2018method(:!)
в IRB, чтобы увидеть происхождение метода. - person Stefan   schedule 28.03.2018