Search code examples
rubymethodsmodulemixins

Ruby module include, can't access included methods, only constants


I have a module structure like this:

module Parent

  PARENT_CONST = 'parent const'

  def Parent.meth
    puts 'parent meth'
  end

end

module Child
  include Parent
end

This works as expected:

puts Parent::PARENT_CONST
 => parent const
Parent.meth
 => parent meth

I can access the parent's constant from the child, but not the method. Like this:

Child::PARENT_CONST
 => parent const
Child.meth
 => in `<main>': undefined method `meth' for Child:Module (NoMethodError)

Is there a way for me to do this?


Solution

  • The following is a common way to mix a module containing constants, instance methods, and class methods into a class, but it can also be used to include constants and class methods of one module in another module, which is what you want to do. It uses the "callback" or "hook" method Module#included. Object#extend adds the instance methods in the module that is the argument to the module that is extend's receiver. Below it makes the instance methods (here just one) in Public::C_Meths class methods in the module Child.

    module Parent
      module I_Meths
        PARENT_CONST = 'parent const'
      end
    
      module C_Meths
        def cmeth
          'cmeth'
        end
      end
    
      def self.included(mod)
        mod.include(I_Meths)
        mod.extend(C_Meths)
      end
    end
    
    module Child
      include Parent
    end
    
    Child::PARENT_CONST
      #=> "parent const" 
    Child.cmeth
      #=> "cmeth" 
    

    It's more common to use this construct to mix a module containing constraints, instance methods and class methods into a class.

    Suppose we were to add the instance method:

    def imeth
      'imeth'
    end
    

    to the module Parent::I_Meths and include Parent in a class:

    class A
      include Parent
    end
    

    then

    A::PARENT_CONST
      #=> "parent const" 
    A.cmeth
      #=> "cmeth" 
    A.new.imeth
      #=> "imeth"