单个method_missing用于Array,Hash和Range

时间:2012-03-11 10:23:08

标签: ruby enumerable method-missing

我是Ruby新手。有没有办法写一个单一的def阵列/范围/哈希'使用method_missing将适用于所有范围,数组和哈希,即所有 Enumerables ?对于例如以下应该有效:

[1..5].Sum()  
[1,2,3,5].Sum()  
{'x' => 1, 'y' = 4}.Sum()  

Sum()是我在method_missing中定义的自定义方法 。截至目前,我已经编写了三个不同的函数来分别处理Array,Range和Hash的method_missing。

2 个答案:

答案 0 :(得分:4)

您可以通过打开method_missing模块并为其添加实例方法来为所有Enumerables定义Enumerable

module Enumerable
  def method_missing *args
    puts 'hi'
  end
end

[].hithere # => hi

但我建议定义具体的sum方法(根据Ruby方法命名指南以小写字母开头),而不是将此逻辑添加到method_missing

module Enumerable
  def sum
    # your implementation
  end
end

[].sum

答案 1 :(得分:0)

正如Alex所说,最好的方法是为Enumerable定义自己的方法#sum, 然而,虽然每个Enumerable都应该有#each,但它产生的每个子类都不同。例如,Hash产生一个键值对,您的单个#sum方法必须知道如何处理。

这是一个如何实现它的例子,它试图将传入的参数splat到一个数组中,而sum只包含数组的最后一个元素。这适用于Hashes,Array和Ranges(但它可能仅适用于1.9)

module Enumerable
  def sum
    r = 0
    each {|(*x)| r += x.last}
    r
  end
end

或者,您可以为每个Enumerable定义自己的迭代方法,例如#each_for_sum,让#sum使用该方法进行求和。但是你可能不得不为不同的Enumerables写几个版本的#each_for_sum(例如,默认的#each_for_sum只是Enumerable#each,但是Hash#each_for_sum只会产生值。)

module Enumerable
  def sum
    r = 0
    each_for_sum {|x| r += x}
    r
  end

  def each_for_sum &block
     each(&block)
  end
end

class Hash
  def each_for_sum
    values.each {|x| yield x}
  end
end