tl;dr: Overriding !
outside of a class is a very weird thing to do! There are countless ways that you can "break" ruby by doing crazy things like this - so you may find it fun to play around with such strange ideas, but obviously don't do this in important code!
In ruby, all classes inherit from the top-level base class: BasicObject
. This class defines top-level object negation - i.e. Whenever you write
!foo
this is actually calling a method called !
on your object foo
:
foo.send(:!)
This makes it possible (although it's a very rare thing to do!) to redefine the method on a specific class. For example, when implementing the null object pattern you could do something like this:
class NullObject
def !
true
end
end
my_null = NullObject.new
!!my_null #=> false
(Normally, the only objects that would return false
in the above line are nil
and false
!)
Now then, back to your example. What you actually did here was define a method called !
on the class Object
(and didn't call super
to trigger the original method!). In other words, you basically re-defined the response a fundamental method that gets used all over the place internally. Something, somewhere (??) got confused by this bizarre behaviour and failed non-gracefully.
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#!>
Here are some other ways you could re-define methods to cause bizarre behaviour/errors, for example:
def nil?
true
end
# Will now die in weird ways!
class String
def ===(other)
true
end
end
"ruby" === "awesome"
#=> true