Одиночный method_missing для Array, Hash и Range - PullRequest
1 голос
/ 11 марта 2012

Я новичок в Ruby.Есть ли способ написать один массив def / Array / Range / Hash с методом method_missing, который будет работать для всех диапазонов, массивов и хэша, т.е. для всех Enumerables ?Например, должно работать следующее:

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

Sum () - наш пользовательский метод , определенный внутри method_missing.На данный момент я написал три разные функции, которые обрабатывают method_missing для Array, Range и Hash по отдельности.

Ответы [ 2 ]

4 голосов
/ 11 марта 2012

Вы можете определить method_missing для всех перечисляемых, открыв модуль 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
0 голосов
/ 11 марта 2012

Как сказал Алекс, лучшим способом было бы просто определить свой собственный метод #sum для Enumerable, однако, хотя каждый Enumerable должен иметь #each, то, что он дает, отличается для каждого подкласса.Например, Hash дает пару ключ-значение, с которой ваш единственный метод #sum должен знать, как справиться.

Вот один пример того, как он может это сделать, он пытается разбить входящие аргументы намассив и сумма включает в себя только последний элемент массива.Это работает для хэшей, массивов и диапазонов (однако, вероятно, работает только в 1.9)

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

В качестве альтернативы вы можете определить свой собственный метод итерации для каждого перечисляемого, например #each_for_sum, и позволить #sum использовать этот метод для выполнениясуммирование.Но вам, вероятно, придется написать несколько версий #each_for_sum для разных Enumerables (например, по умолчанию #each_for_sum будет просто Enumerable # каждая, а 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
...