2

在 Ruby 中,我可以这样做:

module Foo
end

class Bar
  include Foo
end

module Foo
  def do_something_instancey
    puts "I'm an instance!"
  end
end

然后,如果我实例化一个Bar对象,我可以调用do_something_instancey它:

b = Bar.new
b.do_something_instancey

但是,如果我这样做...

module Foo
  def self.included(base)
    def base.do_something_classy do
      puts "I'm a class!"
    end
  end
end

我的理解是,因为我Foo在定义该类方法Bar 之前包含在内,所以我无法调用Bar.do_something_classy,因为它从未“附加”到Bar.

我意识到这可能有点不准确/不是真正正确的术语。无论如何,在上面的例子中,有没有办法在模块已经包含之后Bar附加一个类方法?Foo

4

2 回答 2

2

这是类和实例方法的示例:

module Foo
  def self.included(base)
    base.extend(ClassMethods)
  end

   module ClassMethods
   end
end

class Bar
  include Foo
end

module Foo
  def do_something_instancey
    puts "I'm an instance!"
  end

  module ClassMethods
    def do_something_classy
      puts "I'm a class!"
    end
  end
end

b = Bar.new
b.do_something_instancey
# => I'm an instance!
Bar.do_something_classy
# => I'm a class!

要将类方法添加到(已经)包含特定模块的每个类中,您可以遍历 Ruby 的ObjectSpace

ObjectSpace.each_object(Class) do |klass|
  if klass.include? Foo
    klass.define_singleton_method(:do_something_classy) do
      puts "I'm a class!"
    end
  end
end
于 2012-07-24T15:58:20.927 回答
1

retroactive_module_inclusion gem的描述:

这个 gem 规避了“动态模块包含”(又名“双重包含”)问题,即 M.module_eval { include N } 不会使模块 N 的方法可用于预先包含模块 M 的模块和类,仅适用于其后包含它的人。这种行为损害了最不意外的原则,特别是因为如果 K 是一个类,那么 K.class_eval { include M }确实使 M 的所有方法对之前继承它的所有类都可用。

于 2014-03-31T21:23:24.457 回答