Understanding how the methods in Ruby2.0 are searched and executed (1)

Source: Internet
Author: User

Introducing Ruby2.0 in advance is a good opportunity to review how to precisely establish method calls using Ruby.

Understanding the search method is necessary to grasp the hierarchical classes of Ruby. I have prepared a lot of code examples in this article. You need to use Ruby 1.9.2 or an updated version to debug and run most of the examples. This is a prepared example that can only run on Ruby2.0.0.

Class hierarchy

Let's start with the classic example of inheriting the base class.

 
 
  1. class Animal  
  2.   def initialize(name)  
  3.     @name = name  
  4.   end  
  5.  
  6.   def info  
  7.     puts "I'm a #{self.class}." 
  8.     puts "My name is '#{@name}'." 
  9.   end  
  10. end  
  11.  
  12. class Dog < Animal  
  13.   def info  
  14.     puts "I #{make_noise}." 
  15.     super 
  16.   end  
  17.  
  18.   def make_noise  
  19.     'bark "Woof woof"' 
  20.   end  
  21. end  
  22.  
  23. lassie = Dog.new "Lassie" 
  24. lassie.info  
  25. # => I bark "Woof woof".  
  26. #    I'm a dog.  
  27. #    My name is 'Lassie'. 

In this example, the dog class inherits from the animal class. We call the animal class the super class of the dog:

 
 
  1. Dog.superclass # => Animal 

Remember this method Dog # info calls the super class. This special keyword executes the definition of the next level. For example, Animal # info can be used to inherit the attributes of the class.

 
 
  1. Dog.ancestors # => [Dog, Animal, Object, Kernel, BasicObject] 

The inherited class is not very interesting when it ends with Animal.

 
 
  1. Animal.superclass # => Object 

The declaration of this Animal class is equivalent to writing an Animal class object.

This is why animal medicines have more methods than make_noise, especially reflection methods such as respond_to? Methods:

 
 
  1. lassie.respond_to? :upcase # => false 
  2. lassie.methods  
  3.  # => [:nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, ...] 

So how can we extract the kernel and basic objects? Later I will talk back to the kernel. In fact, there will not be too many things out of the basic object, but there will be a limited number of methods and it will end with the hierarchy of all classes.

 
 
  1. # BasicObject is the end of the line:  
  2. Object.superclass # => BasicObject  
  3. BasicObject.superclass # => nil  
  4. # It has very few methods:  
  5. Object.instance_methods.size # => 54 
  6. BasicObject.instance_methods.size # => 8 

Class is the root of a tree.

Mixins

Although Ruby only supports single inheritance (that is, a class has only one superclass), it supports mixins. mixin is a set of methods that can be included in other classes. In Ruby, it is implemented as a Module class:

 
 
  1. module Mamal  
  2.   def info  
  3.     puts "I'm a mamal" 
  4.     super 
  5.   end  
  6. end  
  7. Mamal.class # => Module 

To add this function to our Dog class, we can use include or prepend. They will insert this module before or after the Dog class:

 
 
  1. class Dog  
  2.   prepend Mamal  
  3. end  
  4. lassie = Dog.new "Lassie" 
  5. lassie.info  
  6. # => I'm a mamal.  
  7. #    I bark "Woof woof".  
  8. #    I'm a dog.  
  9. #    My name is 'Lassie'.  
  10. Dog.ancestors # => [Mamal, Dog, Animal, Object, ...] 

If this module is included in the Dog class instead of the prepend to Dog class, the effect is similar, but the output sequence is different. Can you guess the sequence of the result and the output of the ancestor (ancestors? Click here to view the results.

You can include any number of modules including and prepend at will. The module can also include and prepende other modules. When you are not sure about the module and class inheritance system, call ancestors to find out.

Single-piece class

In Ruby, there is only one additional layer in the module and class hierarchy. Any object can have a special class that takes precedence over anything: A single-piece class.Singleton class)

The following is an example:

 
 
  1. scooby = Dog.new "Scooby-Doo" 
  2.  
  3. class << scooby  
  4.   def make_noise  
  5.     'howl "Scooby-Dooby-Doo!"' 
  6.   end  
  7. end  
  8. scooby.info  
  9. # => I'm a mamal.  
  10. #    I howl "Scooby-Dooby-Doo!".  
  11. #    I'm a dog.  
  12. #    My name is 'Scooby-Doo'. 

Note that the part I bark "Woof woof".) is replaced by the I howl "Scooby-Dooby-Doo! ". This will not affect other instances of the Dog class.

"Class <scooby" is a special method for opening a single-piece class of an object. There is also a way to define a single-piece method:

 
 
  1. # Equivalent to the above example:
  2. Def scooby. make_noise
  3. 'Howl "Scooby-Dooby-Doo! "'
  4. End

A single-piece class is a real class, which can be accessed by calling singleton_class:

 
 
  1. # A single-piece class has a special name:
  2. Scooby. singleton_class #=># <Class: # <Dog: 0x00000100a0a8d8>
  3. # A single-piece class is a real class:
  4. Scooby. singleton_class.is_a? (Class) # => true
  5. # We can get a list of its instance methods:
  6. Scooby. singleton_class.instance_methods (false) # => [: make_noise]

All Ruby objects can have single-piece classes, including classes themselves, and even single-piece classes themselves can also have single-piece classes.

This sounds crazy... isn't it a need for countless single-piece classes? In a sense, yes, but Ruby will be created when they need it.

Although the previous example is a single-piece class of an instance using the Dog class. For more information, see the class .. In fact, "class method" is a single-piece class method. For example, attr_accessor is an instance method of the Module single-piece class. ActiveRecord: The Base class in Ruby on Rails has many such methods, such as has_dependencies, validates_presence_of, and so on. The following shows the number of methods for the single-piece class of ActiveRecord: Base:

 
 
  1. Module.singleton_class  
  2.       .private_instance_methods  
  3.       .include?(:attr_accessor) # => true 
  4.  
  5. require 'active_record' 
  6. ActiveRecord::Base.singleton_method  
  7.                   .instance_methods(false)  
  8.                   .size  # => 170 

The names of single-piece classes come from. They have only one instance:

 
 
  1. scooby2 = scooby.singleton_class.new 
  2.   # => TypeError: can't create instance of singleton class 

For the same reason, you cannot directly inherit a single-piece class:

 
 
  1. class Scoobies < scooby.singleton_class  
  2.   # ...  
  3. end  
  4. # => TypeError: can't make subclass of singleton class 

On the other hand, a single-piece class has a complete class system.

For objects, we have:

 
 
  1. scooby.singleton_class.superclass == scooby.class == Dog  
  2.  # => true, as for most objects 

For classes, Ruby automatically sets the superclass, so different paths that traverse the superclass or single point classes are equal:

 
 
  1. Dog.singleton_class.superclass == Dog.superclass.singleton_class  
  2.  # => true, as for any Class 

This means that Dog inherits the Animal instance method and its single-piece method.

To thoroughly confuse everyone, I finally wrote an extend annotation. It can be seen as the abbreviation 3 of include a module in the single-piece class of the extended object:

 
 
  1. obj.extend MyModule  
  2. # is a shortcut for  
  3. class << obj  
  4.   include MyModule  
  5. end 

Ruby's single-piece class follows the eigenclass model.

Method lookup and missing Methods

Almost all of them are finished!

The rich inherited links supported by Ruby are the basis for searching all methods.

When the final superclass (BasicObject) are found, Ruby provides an additional method to handle Missing methods.

 
 
  1. lassie.woof # => NoMethodError: undefined method  
  2.   # `woof' for #<Dog:0x00000100a197e8 @name="Lassie">  
  3.  
  4. class Animal  
  5.   def method_missing(method, *args)  
  6.     if make_noise.include? method.to_s  
  7.       puts make_noise  
  8.     else 
  9.       super 
  10.     end  
  11.   end  
  12. end  
  13.  
  14. lassie.woof # => bark "Woof woof!" 
  15. scooby.woof # => NoMethodError ...  
  16. scooby.howl # => howl "Scooby-Dooby-Doo!" 

In the above example, when the method name is a part of the noise produced by animals, we call make_noise, otherwise we call the superclass. The superclass will continue to find out BasicObject # method_missing from the ancestor, and then throw the NoMethodError exception.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.