Search code examples
rubymoduleincludemixins

Why is Ruby include polluting unrelated classes?


I am really confused why the methods in modules B and C are mixed in to the class in module A when I use include C. Does include somehow recursively mix in with all classes below the namespace where it is called?

module A
  class AClass
    def a_method_
    end
  end
end

module B
  extend self
  def b_method_
  end
end

module C
  extend self
  include B
  def c_method_
    puts A::AClass.new.methods.grep /_method_/
  end
end

C.c_method_

puts "----"
include C
c_method_

With the result that before the include, the AClass instance correctly only has method a_method_, but after the include it has access to the other two methods as well.

a_method_
----
a_method_
c_method_
b_method_

Can someone please help explain this?


Solution

  • If you change the tail end of your code to this:

    C.c_method_
    
    puts self.inspect
    puts "----"
    include C
    c_method_
    

    you should help you see what's going on. That will give you this output:

    a_method_
    main
    ----
    a_method_
    c_method_
    b_method_
    

    So what is this main business? Chuck has a nice summary over in this answer:

    Everything in Ruby occurs in the context of some object. The object at the top level is called "main". It's basically an instance of Object with the special property that any methods defined there are added as instance methods of Object (so they're available everywhere).

    That means that saying this at the top level:

    include C
    

    is the same as saying:

    Object.send(:include, C)
    

    Adding things to Object pollutes everything.