How to choose a method to call in case of a conflict the name of the mixin method?

When you include a module in a class with a method name conflict, it will use the method defined by the class. Is there any way to choose which one I want to run?

module B def self.hello "hello B" end end class A include B def self.hello "hello A" end end A.hello #=> this prints "hello A", what if I want "hello B"? 
+4
source share
3 answers

Ben, when you call a method (say hello ) in Ruby, this happens:

  • If the eigenclass receiver has a method called hello , it will be called. If not:
  • If the receiver class has an instance method called hello , it will be called. If not:
  • If any module included in the receiver class has an instance method called hello , it will be called. If there are more than one, the last module will β€œwin”. Otherwise:
  • If the superclass of the receiver class has an instance method called hello , it will be called. If not:
  • If any module is included in the superclass of the receiver class ...
  • (And so on for the superclass of the superclass, up to BasicObject ...)
  • If no method named hello , the same process is repeated using method_missing , starting with eigenclass, then the class, then the modules are turned on, then the superclass, then the modules included by the superclass ... this search is always successful, because Kernel determines the implementation by default method_missing .

So, to answer your question, if there is more than one method called hello , you cannot choose which one will be called. The method search rules described above determine which one will be called.

HOWEVER: Ruby is a very flexible language, and if you post more details about what you want to do and why, I can probably help you come up with a way to simulate the desired effect.

Another point: if you want to add class methods from a module to a class, you can do this:

 module B; def hello; "hello B"; end end A.extend(B) A.hello => "hello B" 

You see? When the include class is a module, the instance methods of the module become instances of the class in the class. When the extend class is a module, the instance methods of the module become class methods of the class.

+10
source

The way it was configured will never call the included module method. Try leaving the hello method in and see what happens when you call A.hello .

This will include the method from B. Perhaps a shorter way to do this. I just fastened it from my code base:

 module B def self.included(base) base.extend Greetings end module Greetings def hello "hello B" end end end 

A module method will always override the included module method. This is how it should work. However, you can conditionally return hello as follows:

 module A include B def self.hello if show_hello_a? "hello A" else super end end def self.show_hello_a? false # insert an actual condition statement here end end 
+1
source

When you call A.Hello, all that happens is the message "hello" is passed to object A. Then object A must determine how to handle this message. He will first examine his own methods to determine if he has one called hello before looking at his parents and turning on the modules for the hello method.

While you can technically use A.ancestors to see that B is the ancestor of A and calls it a welcome method, this will violate the abstraction of A as an object.

The correct way to allow both methods to be called is to create another method in A that calls B.hello, or call A.hello something else so that it does not overlap B.hello's functionality.

Edit: since you included B in A, creating a method that calls B hello inside A is as simple as adding a method that calls B.hello

 def self.hello2 B.hello end 
+1
source

Source: https://habr.com/ru/post/1394256/


All Articles