When you include module in class with method name conflict, it would use method defined by the class. Is there a 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"?
Ben, when you call a method (say it's hello
) in Ruby, this is what happens:
hello
, it will be called. If not:hello
, it will be called. If not:hello
, it will be called. If there are more than one, the most recently included module will "win". Otherwise:hello
, it will be called. If not:hello
is found, the same process is repeated with method_missing
, starting from the eigenclass, then the class, then included modules, then the superclass, then modules included by the superclass... this search always succeeds, because Kernel
defines a default implementation of method_missing
.So to answer your question, if there is more than one method called hello
, you can't choose which one will be invoked. The method lookup rules described above decide which one will be invoked.
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 think of 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"
Do you see? When a class include
s a module, the module's instance methods become instance methods on the class. When a class extend
s a module, the module's instance methods become class methods on the class.
The way it's set up it'd never call the included module's method anyway. Try leaving out the hello method in A and see what happens when you call A.hello
.
This will include the method from B. There's probably a more succinct way to do this. I just cribbed it from my codebase:
module B
def self.included(base)
base.extend Greetings
end
module Greetings
def hello
"hello B"
end
end
end
The module's method will always override the included module's method. That's the way it's supposed to work. However, you could conditionally return A's hello value like this:
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
When you call A.Hello all that is happening is the message "hello" is being passed to the A object. The A object then must determine how to handle that message. It will first look at it's own methods to determine if it has one called "hello" before looking to it's parents and included modules for a "hello" method.
While you could technically use A.ancestors to see that B is an ancestor of A, and call it's hello method, this would be violating the abstraction of A as an object.
The correct way to allow both methods to be called would be to create another method in A that calls B.hello, or to name A.hello something else so that it wouldn't override the functionality of B.hello.
Edit: Because you have included B in A, creating a method that calls B's hello within A is as simple as adding a method that calls B.hello
def self.hello2
B.hello
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With