Issue #7240 has been updated by alexeymuranov (Alexey Muranov).


In my opinion, the most common use case for the `included` hook in modules is adding class methods.  However, to me this looks hackish -- hard to follow and understand.  I would have preferred if there was a way to define both instance-level and class-level behavior in a module and include both at once :

  module M
    def foo
      # ...
    end

    def base.bar  # here a fictional method Module#base is called
      # ...
    end
  end

  class C
    meta_include M
  end

  a = C.new
  a.foo
  C.bar

After all, ordinary objects have no method table, classes have one method table, why not to allow modules to have 2 method tables?

Talking about method tables, maybe if objects were allowed to have one, there would be no need for metaclasses? (Then classes would have 2 method tables, modules would have 3, and in fact methods and method tables could be regarded as different kinds of attributes.)

By the way, i think that from the point of view of English the method name `included` is not consistent with the method name `extended` (the *module* is included, but the *base* is extended).
----------------------------------------
Feature #7240: Inheritable #included/#extended Hooks For Modules
https://bugs.ruby-lang.org/issues/7240#change-32046

Author: apotonick (Nick Sutterer)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: 


An inheritable hook mechanism for modules would be a great way for module/gem authors to simplify their implementations.


The Problem
-----------

Let's say I have the following module.

  module A
    def self.included(base)
      # add class methods to base
    end
  end

So, A is overriding the #included hook to add class methods to base.

module B
  include A

  # class methods from A are here.
end

Since B is including A, A's #included method is invoked and A's class methods will be copied to B.

module C
  include B

  # class methods from B are lost.
end

When including B into C, B's #included is invoked and A's #included is lost. In our example, this means no class methods from A are in C.


Proposal
--------

It would be cool if #included/#extended in a module could be inherited to including descendants. I wrote a small gem "uber" that does this kind of stuff with a simple recursion. Roughly, it works like this.

  module A
    extend InheritableIncluded # "execute my #included everytime me or my descendents are included."

    def self.included(base)
      # add class methods to base
    end
  end

Now, A's #included is invoked every time it or a descending module is included. In our example, class methods from A would be around in C.

When discussing this with Matz we agreed that this might be really useful in Ruby itself. I'm just not sure how to mark inheritable hooks.


-- 
http://bugs.ruby-lang.org/