When you use method_missing
to have an object return something on a method call, always make sure you also redefine respond_to_missing?
.
If you don't do it, nothing will break at a first glance, but you will run into trouble eventually.
Consider this class:
class Dog
def method_missing(method_name, *args, &block)
if method_name == :bark
'woof!'
else
super
end
end
end
This will allow you to say:
Dog.new.bark
=> "woof!"
But:
Dog.new.respond_to? :bark
=> false
Lots of code (gems or your own) relies on respond_to?
(for a good reason). For example
#respond_to?
Show archive.org snapshot
will call #respond_to_missing?
if the method is not defined within the receiver. When it has not been defined properly, its return value is a false negative!
Thus, you need to patch
respond_to_missing?
Show archive.org snapshot
as well:
class Dog
def method_missing(method_name, *args, &block)
if method_name == :bark
'woof!'
else
super
end
end
def respond_to_missing?(method_name, *args)
method_name == :bark or super
end
end
Dog.new.bark
=> "woof!"
Dog.new.respond_to? :bark
=> true
Differences between respond_to? and respond_to_missing?
Note that old articles will recommend to override respond_to?
instead of defining respond_to_missing?
. You should always define respond_to_missing?
, so
your dynamic method will work with #method
Show archive.org snapshot
.
Example from Marc's post:
class StereoPlayer
def method_missing(method, *args, &block)
if method.to_s =~ /play_(\w+)/
puts "Here's #{$1}"
else
super
end
end
def respond_to?(method, *)
method.to_s =~ /play_(\w+)/ || super
end
end
StereoPlayer.new.respond_to? :play_beethoven # => true
StereoPlayer.new.method :play_beethoven
# => NameError: undefined method `play_some_Beethoven'
# for class `StereoPlayer'