3

我正在浏览 Facets API 并选择一些方法来包含在我的优化兼容补丁库中。

我在尝试修补内核时遇到了麻烦。它是一个模块,而我修补的其他东西是类(字符串、数组等)


这是无法使用我的核心类标准方法进行改进的证明:

module Patch
  refine Kernel do
    def patched?
      true
    end
  end
end

# TypeError: wrong argument type Module (expected Class)
# from (pry):16:in `refine' 

我还尝试将内核模块包装在一个类中,并将对内核的全局引用更改为该类。

class MyKernel
  include Kernel
  extend Kernel
end

# not sure if Object::Kernel is really the global reference
Object::Kernel = MyKernel

module Patch
  refine MyKernel do
    def patched?
      true
     end
  end
end

class Test
  using Patch
  patched?
end
# NoMethodError: undefined method `patched?' for Test:Class
# from (pry):15:in `<class:Test>'

在这种情况下,我可以通过将 Kernel 替换为 Object 来成功获得相同的功能:

module Patch
  refine Object do
    def patched?
      true
     end
  end
end

class Test
  using Patch
  patched?
end

但我不确定我是否可以与其他核心模块(例如 Enumerable)获得这种等效性。

4

2 回答 2

5

模块可以从ruby​​ 2.4开始改进:

Module#refine现在接受一个模块作为参数。[功能#12534 ]

旧的警告(“细化只修改类,而不是模块,所以参数必须是一个类”)不再适用(尽管它直到ruby​​ 2.6才从文档中删除)。

示例

module ModuleRefinement
  refine Enumerable do
    def tally(&block)
      block ||= ->(value) { value }
      counter = Hash.new(0)
      each { |value| counter[block[value]] += 1 }
      counter
    end
  end
end

using ModuleRefinement

p 'banana'.chars.tally # => {"b"=>1, "a"=>3, "n"=>2}
于 2019-03-02T20:25:46.113 回答
1

正如我在问题中提到的,可以通过使用 Object 类来执行扩展内核模块的等效功能。

我给出的另一个例子是 Enumerable 模块,它实际上可以通过 Enumerator 类进行扩展:

module Patch
  refine Enumerator do
    def patched?
      true
    end
  end
end

class Test
  using Patch
  Array.new.to_enum.patched?
end

所以我想一个可行的解决方案可能是不尝试将核心模块转换为类,而是扩展已经包含它们的类。

在这种情况下,我可以检查Enumerator < Enumerablewhich 返回 true 因为 Enumerator 类包含 Enumerable 模块(尽管它不检查它是否已被扩展)


在查看corefines源代码后进行更新,我找到了一个有用的方法来查找所有包含模块的类

classes_include_module

于 2016-12-12T00:51:44.180 回答