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.
- class Animal
- def initialize(name)
- @name = name
- end
-
- def info
- puts "I'm a #{self.class}."
- puts "My name is '#{@name}'."
- end
- end
-
- class Dog < Animal
- def info
- puts "I #{make_noise}."
- super
- end
-
- def make_noise
- 'bark "Woof woof"'
- end
- end
-
- lassie = Dog.new "Lassie"
- lassie.info
- # => I bark "Woof woof".
- # I'm a dog.
- # 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:
- 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.
- Dog.ancestors # => [Dog, Animal, Object, Kernel, BasicObject]
The inherited class is not very interesting when it ends with Animal.
- 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:
- lassie.respond_to? :upcase # => false
- lassie.methods
- # => [: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.
- # BasicObject is the end of the line:
- Object.superclass # => BasicObject
- BasicObject.superclass # => nil
- # It has very few methods:
- Object.instance_methods.size # => 54
- 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:
- module Mamal
- def info
- puts "I'm a mamal"
- super
- end
- end
- 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:
- class Dog
- prepend Mamal
- end
- lassie = Dog.new "Lassie"
- lassie.info
- # => I'm a mamal.
- # I bark "Woof woof".
- # I'm a dog.
- # My name is 'Lassie'.
- 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:
- scooby = Dog.new "Scooby-Doo"
-
- class << scooby
- def make_noise
- 'howl "Scooby-Dooby-Doo!"'
- end
- end
- scooby.info
- # => I'm a mamal.
- # I howl "Scooby-Dooby-Doo!".
- # I'm a dog.
- # 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:
- # Equivalent to the above example:
- Def scooby. make_noise
- 'Howl "Scooby-Dooby-Doo! "'
- End
A single-piece class is a real class, which can be accessed by calling singleton_class:
- # A single-piece class has a special name:
- Scooby. singleton_class #=># <Class: # <Dog: 0x00000100a0a8d8>
- # A single-piece class is a real class:
- Scooby. singleton_class.is_a? (Class) # => true
- # We can get a list of its instance methods:
- 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:
- Module.singleton_class
- .private_instance_methods
- .include?(:attr_accessor) # => true
-
- require 'active_record'
- ActiveRecord::Base.singleton_method
- .instance_methods(false)
- .size # => 170
The names of single-piece classes come from. They have only one instance:
- scooby2 = scooby.singleton_class.new
- # => TypeError: can't create instance of singleton class
For the same reason, you cannot directly inherit a single-piece class:
- class Scoobies < scooby.singleton_class
- # ...
- end
- # => 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:
- scooby.singleton_class.superclass == scooby.class == Dog
- # => 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:
- Dog.singleton_class.superclass == Dog.superclass.singleton_class
- # => 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:
- obj.extend MyModule
- # is a shortcut for
- class << obj
- include MyModule
- 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.
- lassie.woof # => NoMethodError: undefined method
- # `woof' for #<Dog:0x00000100a197e8 @name="Lassie">
-
- class Animal
- def method_missing(method, *args)
- if make_noise.include? method.to_s
- puts make_noise
- else
- super
- end
- end
- end
-
- lassie.woof # => bark "Woof woof!"
- scooby.woof # => NoMethodError ...
- 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.