TL: DR Перечисляемый миксин работает по некоему контракту с вами.Вы говорите ему, что означает each
, и это приносит в жизнь несколько десятков дополнительных методов.inject
является одним из таких методов.
Актуальное обсуждение
Как работает inject
?Грубо говоря, он проходит через нечто, состоящее из элементов , применяя функцию к элементам по мере их поступления.Каковы элементы строки "the quick brown fox jumped"
?Возможно, они являются его персонажами.Поэтому, если мы будем рассматривать строку как массив символов и вставлять +
, который объединяет строки, мы ожидаем получить саму оригинальную строку:
arr = "The quick brown fox jumped".scan /./
puts arr.inject(:+) # => the quick brown fox jumped
Но теперь давайте пойдем дальше.В Ruby есть миксины, и, в частности, есть Enumerable mixin.Это позволяет нам трактовать все, что нам нравится , как «что-то, что имеет элементы».Итак, вместо массива, давайте сделаем возможным вставлять +
в элементы самой строки .Для этого мы должны определить each
для строки, чтобы можно было ходить по элементам строки.Как только мы это сделаем, многие методы Enumerable, в том числе inject
, оживут.
Что должен означать each
для строки?Опять же, мы можем просто сделать так, чтобы это означало каждый персонаж.Мы могли бы сделать это путем наложения псевдонима each
на существующий each_char
:
class String
include Enumerable
alias each each_char
end
s = "the quick brown fox jumped"
puts s.inject(:+) # => the quick brown fox jumped
Но вместо наложения псевдонима each
на each_char
мы могли бы определить each
сами с нуля.Мы уже знаем один способ сделать это, используя scan
:
class String
include Enumerable
def each
self.scan(/./) do |ch|
yield ch
end
end
end
s = "the quick brown fox jumped"
puts s.inject(:+) # => the quick brown fox jumped
Но определение each
зависит от меня, поэтому вместо сканирования на каждый символ яможет сканировать для некоторых другой шаблон!Например, я могу вместо этого искать гласные:
class String
include Enumerable
def each
self.scan(/[aeiou]/) do |ch|
yield ch
end
end
end
s = "the quick brown fox jumped"
puts s.inject(:+) # => euiooue
Но давайте не будем хромать String, определив each
таким любопытным способом.Давайте перенесем всю эту функциональность на пользовательский класс.Давайте назовем это VowelFinder!Таким образом, мы получаем код, с которого вы начали.