It is known that in Ruby, class methods get inherited:

class P
  def self.mm; puts 'abc' end
end
class Q < P; end
Q.mm # works

However, it comes as a surprise to me that it does not work with mixins:

module M
  def self.mm; puts 'mixin' end
end
class N; include M end
M.mm # works
N.mm # does not work!

I know that #extend method can do this:

module X; def mm; puts 'extender' end end
Y = Class.new.extend X
X.mm # works

But I am writing a mixin (or, rather, would like to write) containing both instance methods and class methods:

module Common
  def self.class_method; puts "class method here" end
  def instance_method; puts "instance method here" end
end

Now what I would like to do is this:

class A; include Common
  # custom part for A
end
class B; include Common
  # custom part for B
end

I want A, B inherit both instance and class methods from Common module. But, of course, that does not work. So, isn't there a secret way of making this inheritance work from a single module?

It seems inelegant to me to split this into two different modules, one to include, the other to extend. Another possible solution would be to use a class Common instead of a module. But this is just a workaround. (What if there are two sets of common functionalities Common1 and Common2 and we really need to have mixins?) Is there any deep reason why class method inheritance does not work from mixins?

推荐答案

A common idiom is to use included hook and inject class methods from there.

module Foo
  def self.included base
    base.send :include, InstanceMethods
    base.extend ClassMethods
  end

  module InstanceMethods
    def bar1
      'bar1'
    end
  end

  module ClassMethods
    def bar2
      'bar2'
    end
  end
end

class Test
  include Foo
end

Test.new.bar1 # => "bar1"
Test.bar2 # => "bar2"

Ruby相关问答推荐

为什么非数字在Ruby中被转换为integer?

清理 jruby 中输入数据的编码错误

Nokogiri/Xpath 命名空间查询

何时在 Ruby 方法中使用 `self.foo` 而不是 `foo`

在基于值的哈希数组上唯一

如何在 VIM 中导航 Ruby 方法?

如何将参数传递给 array.map 快捷方式?

Python 是否在 Ruby 中进行类似于字符串 #{var}的变量插值?

无法在 OSX Lion 上使用 RVM 安装 Ruby 企业版

Rails:Date.today 是 UTC 吗?

Ruby 运算符优先级表

在 Rails 中,如何向 String 类添加新方法?

处理来自 Net::HTTP 的异常的最佳方法是什么?

Ruby - time.now UTC

如何判断变量是数字还是字符串?

Ruby:使用 ENV 变量(如果存在)的最简洁方法,否则使用默认值

相当于 Ruby 的 cURL?

如何在文件夹及其所有子文件夹中搜索特定类型的文件

如何判断一个类是否已定义?

查找模块中可用的类