Ruby: modules extending / including modules

I am trying to better understand how modules expand 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 my tricks package in B :

 module B extend A end B.learned_from_A # true 

I naively try to give C all B :

 module C extend B end C.learned_from_A # NoMethodError 

I think I wrapped it around this. When B extends A , copies of instance methods A are bound to B through the B singleton class:

 B.singleton_methods # [:learned_from_A] 

While: learn_from_A can be used for B , this is not one of the methods of instance B , so when C extends B ,: learn_from_A is not copied to C.


If B instead included A , copies of the methods of instance A would be included in the methods of native instance B.

 module B include A end B.instance_methods # [:learned_from_A] 

Then C can extend B , and all instances of B instance (including: learn_from_A) will be copied and attached to C.

 module C extend B end C.singleton_methods # [:learned_from_A] 

To do: learn_from_A can use either B or C , B can expand to 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 realistic, if I want methods A to be called on B , and for B to define another native method and be able to mix the entire repertoire in C , I cannot 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, and not with single methods. Therefore, to make a method as callable on B and shared by 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 have been many trials and errors associated with this. Is this the exact way to see what happens?

+8
ruby module extend
source share
1 answer

I mix my pack of tricks in B

This phrase and your question as a whole led me to believe that there is a slight misunderstanding in the include / extend concept. I apologize in advance because I do not quite understand the question.

For example, you have a module like this:

 module A def a puts "a" end def self.b puts "b" end end 

As you can see, there are two types of methods:

  • singleton_methods
  • instance_methods

Here is the easiest way to show that they are really different:

 A.singleton_methods => [:b] A.instance_methods => [:a] Aa NoMethodError: undefined method `a' for A:Module Ab b => nil 

If you simplify include A , you add instance methods to the current instance methods. When you simplify extend A , you add instance methods to the current 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] 

Another thing to say is that you could extend self , but not include self , as this makes no sense and also throws 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] Da a #no error there because we have such singleton method => nil 

I think these things can help you. There are many questions about extend / include in StackOverflow that you can check ( example ).

+2
source share

All Articles