如何声明一个mixin方法,使它可以从实例方法和类方法中使用?

时间:2011-11-25 20:27:00

标签: 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

上述方法不起作用,因为类方法(cls)无法看到实例方法fmt。如果我将定义更改为self.fmt,则实例方法必须将其作为MyMod.fmt调用。

我希望能够从这两种方法中调用fmt (some stuff)。这样做有“ruby-ish”方式吗?我可以将模块定义为

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

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

2 个答案:

答案 0 :(得分:5)

你可以利用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

有关更详细的说明,请查看this article

答案 1 :(得分:1)

include extend模块中的MyModMyClass,以便将fmt方法作为实例和类方法添加到{ {1}}。

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