Ruby 如何声明mixin方法,使其';实例方法和类方法都可用吗?

Ruby 如何声明mixin方法,使其';实例方法和类方法都可用吗?,ruby,module,mixins,Ruby,Module,Mixins,我想在Ruby模块中放置一个方法,这样就可以使用简单的语法从类方法或实例方法调用它: module MyMod def fmt *args args.map { | a | "You said #{a}" } end end class MyClass include MyMod def inst puts fmt 1,2,3 end def self.cls puts fmt 4,5,6 end end 上述方法不起作用,因为类方法(cl

我想在Ruby模块中放置一个方法,这样就可以使用简单的语法从类方法或实例方法调用它:

module MyMod
  def fmt *args
    args.map { | a | "You said #{a}" }
  end
end

class MyClass
  include MyMod
  def inst
    puts fmt 1,2,3
  end
  def self.cls
    puts fmt 4,5,6
  end
end
上述方法不起作用,因为类方法(
cls
)无法看到实例方法fmt。如果我将定义更改为
self.fmt
,那么实例方法必须将其作为
MyMod.fmt
调用

我希望能够从这两种方法中调用
fmt(一些东西)
。有没有“红宝石般”的方法?我可以将模块定义为

module MyMod
  def self.fmt *args
    args.map { | a | "You said #{a}" }
  end
  def fmt *args
    MyMod.fmt args
  end
end

但那不是很干,是吗?有一种更简单的方法吗?

包括
扩展
MyClass
中的
MyMod
模块,以便
fmt
方法作为实例和类方法添加到
MyClass


Object#extend
所做的是将模块的方法添加到单个实例中。在这种情况下,该实例就是类本身,这就是为什么这些方法可以作为类方法使用。

您可以使用
Module#included
方法的优点来这样做:

module MyMod
  # here base is a class the module is included into
  def self.included(base)
    # extend includes all methods of the module as class methods
    # into the target class
    base.extend self
  end

  def fmt(*args)
    args.map { |a| "You said #{a}" }
  end
end

class MyClass
  # regular include provides us with instance methods
  # and defined above MyMod#included hook - with class methods
  include MyMod

  def inst
    puts fmt(1, 2, 3)
  end

  def self.cls
    puts fmt(4, 5, 6)
  end
end

puts MyClass.cls
puts MyClass.new.inst
以下是输出:

You said 4
You said 5
You said 6

You said 1
You said 2
You said 3

要获得更详细的解释,请看。

当构建某种充当DSL的东西时,回调是很好的,其他开发人员应该将其包含到他们的类中。否则,这有点太神奇了,无法证明其合理性,因为使用
include
是否会导致添加类方法还不是很清楚。因此,如果这是在内部代码中,那么手动使用
extend
本身几乎总是有好处的,而不是麻烦地记录这种特殊行为。这一点很好,但是如果你想在多个地方使用这个模块,我不认为在你需要的地方调用
include
extend
都是一个很好的解决方案。@KL-7,为什么不呢?模块正在为您做这件事。。。你不必这么做。不管怎样,这是唯一的方法。这正是我们正在讨论的,模块是否应该“为你做那件事”。而且这是“唯一的方法”显然是错误的,因为仍然有“手动”方法……完全没有听到第一条评论,对不起;)