我可以“追溯”地从模块中添加类方法(在它已被包含之后)吗?

时间:2012-07-24 14:32:41

标签: ruby module metaprogramming class-method

在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

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

我意识到可能稍微不准确/不是真正合适的术语。无论如何,在上面的示例中,是否有一种方法可以在已经包含模块后将Bar的类方法附加到Bar

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

retroactive_module_inclusion gem的描述:

  

这个宝石绕过"动态模块包括" (又名"加倍   包含")问题,这是M.module_eval {包括N.   }不会使模块N的方法可用于模块和   事先包含模块M的类,仅限于那些类   之后包括它。这种行为伤害最少   原则,特别是因为如果K是一个类,那么K.class_eval {   包含M} 确实使所有类的M都可用   以前继承了它。