Блоки та ітератори Ruby

Ви можете використовувати блоки для реалізації зворотних викликів, передачі шматків коду і для реалізації ітераторів.


Блоки являють собою прості шматки коду укладені у фігурні дужки або між do... end

{puts «Hello»} # це блок

do #

club.enroll (person) # і це теж

person.socialize #

end #

Коли блок створено його можна асоціювати з викликом методу. Це робиться розміщенням блоку коду в кінці рядка, що містить виклик методу. Наприклад, у наступному коді блок, що містить puts «Hi», асоціюється з викликом методу greet.

greet { puts «Hi» }

Якщо у методу є параметри, вони перераховуються перед блоком:

verbose_greet(«Dave», «loyal customer») {puts «Hi»}

Метод може викликати асоційований блок один або кілька разів використовуючи вираз yield. Воно схоже на виклик методу, який викликає блок, асоційований з методом, що містить yield.

Наступний приклад показує це в дії. Ми визначимо метод який викликає yield два рази. Потім викличемо цей метод, помістивши блок на тій же лінії після виклику (і після перерахування аргументів методу)

def call_block

puts «Start of method»

yield

yield

puts «End of method»

end

call_block { puts «In the block» }

результатом буде:

Start of method

In the block

In the block

End of method

Кожен виклик yield виводить на друк «In the block».

Блок коду можна викликати з параметрами, передаючи їх через yield. Всередині блоку просто перерахуйте аргументи, уклавши їх між вертикальними рисами (|).

def call_block

yield(«hello», 99)

end

call_block {|str, num|}

Блоки коду використовуються всюди для реалізації ітераторів: методи, які повертають елементи послідовності взяті з певної збірки, наприклад, з масиву.

animals = %w( ant bee cat dog elk )

animals.each {|animal| puts animal }

дасть:

ant

bee

cat

dog

elk

Всередині класу Array ми б реалізували ітератор each наступним чином, використовуючи псевдо-код:

# всередині класу Array

def each

for each element # < - псевдо

yield element

end

end

Більшість конструкцій перебору вбудовані в C або Java в Рубі є простими методами, що викликають асоційовані блоки нуль або більше разів.

[ 'cat', 'dog', 'horse' ].each { |name| print name, "" ""}

5.times { print ""*"" }

3.upto(6) { |i| print i }

('a'..'e').each { |char| print char }

в результаті дає нам

cat dog horse *****3456abcde

Ми просимо об'єкт 5 викликати блок п'ять разів і потім просимо об'єкт викликати блок, передаючи послідовні значення поки вони не досягнуть значення 6. І в кінці діапазон величин від a до e викликає блок використовуючи метод each.

Все це - вільний переклад Dave Thomas - Programming ruby 2nd edition (The Pragmatic Programmers'Guide)