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


apotonick (Nick Sutterer) wrote:

> 
> Problem here is: The *user* has to know about whether or not to import class methods which is not what I want as a gem developer (I don't want my gem users to know whether they should use #include or #include!). Also, no fine-tuning since _all_ class methods are imported.

If i understood correctly, Thomas suggested the `include!` method name simply to not change the current behavior of `include`, but it seems that he also prefers a single method.

I do not think that in your example the method `m` should be callable on `U` because i think it is really a *personal* method of `M` not intended for inclusion. This is why i suggested to have a separate space (object/table/module/etc) where to keep methods intended for inclusion as class methods. But i think this is a huge feature request, which may bring into question even the relationship `Class < Module`.  I wonder what the core developers would say.

However it seems to me that if it is possible to implement this "single instance/class method inclusion", the end user of a gem would do exactly as before: simply call `include` (or `meta_include`, but it can be called `include` as it wouldn't conflict with current `include`). The fine tuning by the developer should be possible by choosing which methods to declare as "includable instance methods" and "includable class methods".

----------------------------------------
Feature #7240: Inheritable #included/#extended Hooks For Modules
https://bugs.ruby-lang.org/issues/7240#change-32086

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/