CSC/ECE 517 Fall 2007/wiki1b 2 22
Introduction - method_missing
The method_missing is a method that called whenever someone tries to call a method in your object that doesn't exist. When you call a method, Ruby looks for a method to invoke with the same name as the method you call. First it looks in the current self object’s own instance methods. Then it looks in the list of instance methods that all objects of that class share, and then in each of the included modules of that class. Then it looks in that class’s superclass, and then in the superclass’s included modules, all the way up until it reaches the class Object. If it still can’t find a method, the very last place it looks is in the Kernel module, included in the class Object. When a method call is not exist, Ruby use method_missing as the last resort. [1]
Examples
1. Object composition
class SimpleCallLogger def initialize(o) @obj = o end def method_missing(methodname, *args) puts "called: #{methodname}(#{args})" a = @obj.send(methodname, *args) puts "\t-> returned: #{a}" return a end end
This object "intercepts" all method calls made to it, prints out a message and forwards on the method call to an internal object using the 'send' method, without knowing anything about the object passed to it. It can be used to debug some code without littering it with print statements. [2]
2. Factorial
Let's create a Computer class that contains a factorial method (you know the famous n! thing).
class Computer def factorial n raise ArgumentError if n < 0 f = 1 n.downto(1) do |i| f = f * i end f end end computer = Computer.new puts computer.factorial(4)
We would like to use some notation close to the usual notation:
computer = Computer.new puts computer._4!
Obviously, we cannot create methods for every integer, to do it we use the method_missing.
def method_missing(meth, *args) meth.to_s =~ /_([0-9]*)!/ return super if ! $1 factorial($1.to_i) end
If we use the special notation (_<digits>!) the method_missing implementation extracts the number, from the method name, and calls the factorial method to get the result. Each time and for any method the same processing happens. [3]
3. Generic Handler
class NoBar def method_missing(methodname, *args) define_method(:bar) if "bar" == methodname.to_s define_method(:nobar) if "nobar" == methodname.to_s end end
This is an example of using method_missing as a generic handler to handle when a calling method is not exist. You can use missing_method to dynamically create a method at a runtime.
Advantages
- Allow you to catch problem at runtime.
- Allow you define a generic method_missing and handle any undefined method. This is a big advantage over Java. In Java, when you call method is not define, the program will not compile.
- The use of method_missing falls under the general technique of metaprogramming. You can employ metaprogramming in missing_function to write a another function to handle the call.
References
- 10 things you should know about method_missing.[4]
- More Ruby: method_missing [5]
- Hey Ruby, how much for the method_missing? [6]
Further reading
External links
- The Best of method_missing [9]