CSC/ECE 517 Fall 2007/wiki1 2 p2

From Expertiza_Wiki
Jump to navigation Jump to search

ASSIGNMENT # 1 b

Q. There are plenty of examples of method_missing on the Web. Unfortunately, I find most of them rather difficult to understand. One needs to look at quite a bit of source code and figure out what it does. Fix this by giving a plain-English description of several uses of method_missing not covered in our class, with Web links to the pages where you found them


What is method_missing?

Method_missing is called when someone tries to call a method that does not exist on the object. Obj.method_missing(symbol,[*,args]) This method is invoked by Ruby when object Obj is passed a message that it can’t handle. Symbol is the symbol for the method called and args are the parameters for the method.

When you send a message to a Ruby object, Ruby looks for a method to invoke with the same name as the message you sent.


Search Path Used By Ruby When a Method Is Invoked On an Object

CURRENT OBJECT’S OWN SELF INSTANCE METHODS

INSTANCE METHODS SHARED BY ALL OBJECTS OF THE CLASS

EACH INCLUDED MODULE OF THE CLASS

SUPERCLASS OF THE CLASS

MODULES INCLUDED IN SUPERCLASS

HAVE YOU REACHED CLASS=OBJECT?

CALL METHOD_MISSING


When is method_missing called?

When you send a message to an object, the object executes the first method it finds on its method lookup path with the same name as the message. If it fails to find any such method, it raises a NoMethodError exception - unless you have provided the object with a method called method_missing. The method_missing method is passed the symbol of the nonexistent method, and any arguments that were passed in.


WHY method_missing??


A CLASS THAT DOESN’T PROVIDE AN IMPLEMENTATION FOR METHOD_MISSING

Suppose we have a file SimpleClass.rb that contains the following class:

  class  SimpleClass
    def  printMessage(msg)       
      puts  “The message is  #{msg}”
    end  
  end  
  a=SimpleClass.new
  a.printMessage(“Hello World”);
  a.abc(“Helllloo”);
  >ruby SimpleClass.rb
  The output is:
  The message is Hello World
  NoMethodError: undefined method `abc' for      #<SimpleClass:0x6688f34>

EXPLANATION

In the above example we create a new object of SimpleClass named a. We call method printMessage that accepts a message and pass a message “Hello World” to this method. The method outputs the message on the screen. Next we call method abc on the object. However, method abc is not defined on object a. By default, the interpreter raises an error if you call a method that hasn’t been defined for the object. So, in this case, the interpreter raises NoMethodError as it couldn’t find an appropriate definition for method abc.

However it is possible to override this default behavior.


EXAMPLES OF method_missing


1. A CLASS THAT PROVIDES AN IMPLEMENTATION FOR METHOD_MISSING

Suppose we have a file tmp.rb that contains the following class:

  class Method_Missing_Example   
    def method_missing(m, *args)       
      puts "There's no method called #{m} here -- please try again." 
    end  
  end  
  Method_Missing_Example.new.anything   
        
  >ruby tmp.rb 
  The output is:
  There's no method called anything here -- please try again.
  

EXPLANATION

In the above example method we create an object of class Method_Missing_Example and invoke the method anything on this object. The method anything is not defined on this object. So the method method_missing is invoked on the object. In this simple example the method method_missing simply prints a message saying “There’s no method called (method name passed as argument) please try again”.

Apart from specifying error messages for undefined methods, method_missing can also be used to provide more dynamic behavior in programming environment.


2. EXAMPLE WHERE YOU CAN ADD BUT CANT SUBTRACT TWO NUMBERS

  class MathWiz
    def add(a,b) 
      return a+b
    end
    def method_missing(name, *args)
      puts "I don't know the method #{name}"
    end
  end
  
  mathwiz = MathWiz.new
  puts mathwiz.add(1,4)
  puts mathwiz.subtract(4,2)
  The output is
  Mathwiz=#<MathWiz:0x6875018>
  5
  Nil
  I don't know the method subtract

EXPLANATION

MathWiz is a class where it is possible to add two numbers. But the class doesn’t provide a method to subtract two numbers. So when add method is called on Mathwiz object 5 is returned but when subtract method is called method_missing is invoked printing “I don’t know the method subtract”.


3. EXAMPLE THAT CONVERTS NUMBERS FROM ROMAN TO INTEGER REPRESENTATION

   class Roman
     def romanToInt(str)
        # Code that converts a number from roman representation to int representation
     end
    def method_missing(methId)
       str = methId.id2name
       romanToInt(str)
    end
  end
  r = Roman.new
  r.iv      #=> 4
  r.xxiii   #=> 23
  r.mm      #=> 2000
  The output is:
  4
  23
  2000

EXPLANATION

Class Roman given above is an example of dynamic behavior method_missing can offer. Class Roman has a method ‘romanToInt(str)’ to convert a roman numeral to integer. The most natural way to covert a roman numeral to integer is to pass the Roman numeral itself to object (e.g., r.iv) rather than calling a special method on object. However, this call needs to be diverted to method that actually performs the conversion. This can be easily accomplished using method_missing. As Roman numeral is not a valid method, method_missing gets invoked. Inside method_missing, roman numeral is converted to string with id2name method and passed as parameter to romanToInt method. romanToInt performs the actual conversion and/or handles the error conditions(implementation not given).


4. EXAMPLE THAT USES method_missing TO LOG METHOD CALLS

Another application that makes use of method_missing could be a simple logger used for debugging purposes. Many times, it may be required to log the trace of called methods and provide information such as: called method-name, arguments, return type. It can be tedious to repeat this part of code in every method. So, a simple solution to this problem can be obtained using method_missing as:

  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


EXPLANATION

This program makes use of method_missing in a way that it wraps around called method to output the logging information on entry and on exit, it logs the return type. Further, method_missing intercepts the method call and forward it to internal object with ‘send’ method of ruby. Hence, this use of method_missing acts as wrapper.


CONCLUSION

In a nutshell, method_missing not only allows interception of method calls but also saves the programmer’s time and typing by allowing him to use more user friendly method names.


REFERENCES:

1) http://blog.mauricecodik.com/2005/12/more-ruby-methodmissing.html

2) http://www.thirdbit.net/articles/2007/08/01/10-things-you-should-know-about-method_missing/

3) http://www.ruby-doc.org/core/classes/Kernel.html

4) http://www.fincher.org/tips/Languages/Ruby/