如何向 Enumerable 模块添加方法?

How to add methods to the Enumerable module?

如何将自定义方法添加到 Ruby 中现有的 Enumerable 模块?我正在运行 Ruby 2.0.

与您向每个其他模块添加方法的方式相同。

如果你想添加带有参数 bazquux 的方法 bar 到模块 Foo 你写

module Foo
  def bar(baz, quux)
    # code code code
  end
end

所以,如果你想添加方法 histogram 到模块 Enumerable 你写

module Enumerable
  # Counts the number of occurrences of each unique object in `self`.
  #
  # @return [Hash<E, Integer>] a `Hash` of objects mapped to number of occurrences in `self`.
  def histogram
    group_by(&:itself).map {|k, v| [k, v.size] }.to_hash
  end
end

在Ruby中可以使用monkey-patching,其中包含了open classes的概念。这意味着 Ruby 中的 classes 可以随时修改。例如,您可以在数字 class.

中创建一个 double 方法
class Integer < Numeric
  def self.double
    self * 2
  end
end

现在您可以对数字调用 double 方法

4.double
=> 8

希望对您有所帮助

Enumerable 模块中定义的所有方法都要求接收者是枚举器或具有方法 each。假设我们希望创建一个类似于 Enumerable#to_a 的可枚举方法 my_to_a 除了它 return 只是接收者元素的第一个 n (或者,如果它是一个枚举器,则它生成的第一个 n 个元素),nmy_to_a 的参数。

module Enumerable
  def my_to_a(n)
    enum = is_a?(Enumerator) ? self : each
    n.times.with_object([]) { |o,a| a << enum.next }
   end
end

[0,1,2,3,4].my_to_a(3)
  #=> [0, 1, 2] 
(0..4).my_to_a(3)
  #=> [0, 1, 2] 
{ a:1, b:2, c:3, d:4, e:5 }.my_to_a(3)
  #=> [[:a, 1], [:b, 2], [:c, 3]] 
'0ab_1ab_2ab_3ab_4ab'.gsub(/.(?=ab)/).my_to_a(3)
  #=> ["0", "1", "2"] 
require 'prime'; Prime.my_to_a(4)
  #=> [2, 3, 5, 7] 
[0,1,2,3,4].my_to_a(6)
  #=> StopIteration (iteration reached an end)
'0ab_1ab_2ab_3ab_4ab'.gsub(/.(?=ab)/).my_to_a(6)
  #=> StopIteration (iteration reached an end)

enum = is_a?(Enumerator) ? self : each
如果 self 是枚举数,

enum 设置为 self,否则设置为 self.each。后一种情况假设 self 有一个方法 each,这意味着 class self.class 有一个实例方法 each(或者方法 each 有已在 self 的单例 class 上定义)。 each 必须 return 一个枚举器。在该示例中,is_a?(Enumerator)(相当于 self.is_a?(Enumerator))仅对于使用 String#gsub 且没有块的两个示例 true 1 在其他示例中 self.class.included_modules.includes?(Enumerable) #=> trueself.class.instance_methods.include?(:each) #=> true。这些 class 是 ArrayRangeHashPrimeeach是前三个的实例方法,Prime的class方法。

一旦我们有了枚举器 enum

n.times.with_object([]) { |o,a| a << enum.next }

很简单。参见 Integer#times, Enumerator#with_object and Enumerator#next

1 请注意 Enumerator.included_modules #=> [Enumerable, Kernel],因此任何 return 枚举器的方法(Enumerator 的实例)都会响应 Enumerable 方法。即不需要方法的class(比如String)包含Enumerable或者有方法each.