I'm trying to better understand how modules extend and include each other.
Say I have module A :
module A
def learned_from_A
true
end
end
A.instance_methods # [:learned_from_A]
I mix its bag of tricks into B :
module B
extend A
end
B.learned_from_A # true
I naively attempt to give C everything B has:
module C
extend B
end
C.learned_from_A # NoMethodError
I think I've wrapped my head around this. When B extends A , copies of A's instance methods are bound to B via B's singleton class:
B.singleton_methods # [:learned_from_A]
While :learned_from_A is callable on B , it's not one of B 's instance methods, so when C extends B , :learned_from_A is not copied to C .
If B had instead included A , copies of A's instance methods would've been included among B's own instance methods.
module B
include A
end
B.instance_methods # [:learned_from_A]
Then, C could extend B , and all of B's instance methods (including :learned_from_A ) would be copied and bound to C .
module C
extend B
end
C.singleton_methods # [:learned_from_A]
To make :learned_from_A callable on both B and C , B could extend and include A .
module B
include A
extend A
end
B.instance_methods # [:learned_from_A]
B.singleton_methods # [:learned_from_A]
module C
extend B
end
C.instance_methods # []
C.singleton_methods # [:learned_from_A]
More realistically, if I want A 's methods to be callable on B , and for B to define another method of its own, and be able to mix the whole repertoire into C , I can't do this:
module B
extend A
include A
def self.buzz
true
end
end
module C
extend B
end
B can only share its instance methods, not its singleton methods. So to make a method both callable on B and shareable to other objects, it must be defined as an instance method and extended into B itself:
module B
extend A
include A
extend self
def buzz
true
end
end
module C
extend B
end
There was a fair amount of trial and error in putting this all together. Is it an accurate way of viewing what's going on?
I mix its bag of tricks into B
This phrase and your question in general made me believe there is a little misunderstanding in concept of include
/ extend
thing. I apologize in advance, because I don't fully understand the question.
For example you have such module:
module A
def a
puts "a"
end
def self.b
puts "b"
end
end
As you see there are 2 types of methods:
Here is the easiest way to show that they actually differ:
A.singleton_methods
=> [:b]
A.instance_methods
=> [:a]
A.a
NoMethodError: undefined method `a' for A:Module
A.b
b
=> nil
If you do include A
simplistically you are adding its instance methods to the current module instance methods. When you do extend A
simplistically you are adding its instance methods to the current module singleton methods.
module B
include A
end
module C
extend A
end
B.instance_methods
=> [:a]
B.singleton_methods
=> []
C.instance_methods
=> []
C.singleton_methods
=> [:a]
One more thing to say is that you could extend self
but not include self
as that doesn't make any sense and also will raise an exception.
module D
extend self
def a
puts "a"
end
def self.b
puts "b"
end
end
D.singleton_methods
=> [:b, :a]
D.instance_methods
=> [:a]
D.a
a #no error there because we have such singleton method
=> nil
I guess these things could help you. There are a lot of questions about extend
/ include
on StackOverflow you may check ( example ).
The following seems to work at least for A
to B
to C
module A
def learned_from_A
true
end
end
module B
prepend A
end
B.learned_from_A # true
module C
extend B
end
C.learned_from_A # true
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.