动态细化

改进有特殊限制。

refine 只能在模块范围内使用,但可以使用 send :refine 进行编程。

using 更受限制。它只能在类/模块定义中调用。但是,它可以接受指向模块的变量,并且可以在循环中调用。

显示这些概念的示例:

module Patch
  def patched?; true; end
end

Patch.send(:refine, String) { include Patch }

patch_classes = [Patch]

class Patched
  patch_classes.each { |klass| using klass }
  "".patched? # => true
end

由于 using 是静态的,如果未首先加载细化文件,则可以发出加载顺序。解决此问题的方法是将修补的类/模块定义包装在 proc 中。例如:

module Patch
  refine String do
    def patched; true; end
  end
end

class Foo
end

# This is a proc since methods can't contain class definitions
create_patched_class = Proc.new do
  Foo.class_exec do
    class Bar
      using Patch
      def self.patched?; ''.patched == true; end
    end
  end
end
create_patched_class.call
Foo::Bar.patched? # => true

调用 proc 会创建补丁类 Foo::Bar。这可以延迟到所有代码加载完毕之后。