是否可以混入模块方法?

Is it possible to mix-in a module method?

假设我有一个模块声明了一个模块方法(不是一个实例方法):

module M
  def self.foo
    puts 'foo'
  end
end

现在假设我想将 M.foo 混合到另一个 class C 中,这样就定义了 C.foo

最后,我想这样做 而不改变 M.foo 的定义方式 而不仅仅是在 C 中创建方法调用 M.foo。 (即重写 foo 作为实例方法不算数。使用 module_function 也不算数。)

这在 Ruby 中不可能吗?

I want to do this without changing the way M.foo is defined

很遗憾,这是不可能的。 Ruby 只允许包含模块,而不是 classes。然而,foo 是在 M 的单例 class 上定义的,其中 一个 class。因此,你不能 include 它。同样的限制适用于 extend。尝试这样做会导致 TypeError:

module M
  def self.foo
    puts 'foo'
  end
end

class C
  extend M.singleton_class # TypeError: wrong argument type Class (expected Module)
end

然而,您可以通过将 foo 定义为单独模块中的实例方法来实现您想要的,然后可以通过 [=17] 将其混合到 MC 中=]:(该模块不必嵌套在 M 下)

module M
  module SingletonMethods
    def foo
      puts 'foo'
    end
  end

  extend SingletonMethods     # <- this makes foo available as M.foo
end

class C
  extend M::SingletonMethods  # <- this makes foo available as C.foo
end

或者使用 Ruby 的 included 回调进行一些元编程魔法:

module M
  module SingletonMethods
    def foo
      puts 'foo'
    end
  end

  extend SingletonMethods

  def self.included(mod)
    mod.extend(SingletonMethods)
  end
end

class C
  include M
end

这是 ActiveSupport::Concern 在 Rails 中工作方式的简化版本。