Одной из уникальных особенностей языков программирования Ruby являются блоки. Я никогда не слышал о блоках до того, как начал изучать Ruby, и мне потребовалось некоторое время, чтобы понять их использование и назначение. Это мощная функция, которая широко используется.

Вот самый простой пример использования блока в Ruby. Приведенный ниже код выполняет итерацию по каждому элементу в массиве названий книг и печатает его.

books = ['To Kill a Mockingbird', '1984', 'The Catcher in the Rye']
books.each do |book|
  puts book
end
# Outputs:
# To Kill a Mockingbird
# 1984
# The Catcher in the Rye

По сути, блок передает параметр (или параметры) и позволяет вам что-то с ним делать.

Блоки
— начинаются с do
— принимают один или несколько параметров
— делают что-то с параметрами
— заканчивают end

Параметры

Параметры — это просто аргументы, которые вы принимаете. Вы можете назвать их как угодно.

В приведенном выше примере мы назвали наш параметр book, но мы могли бы легко назвать его как угодно.

books = ['To Kill a Mockingbird', '1984', 'The Catcher in the Rye']
books.each do |book_title|
  puts book_title
end
# Outputs:
# To Kill a Mockingbird
# 1984
# The Catcher in the Rye

Какое бы имя вы ни приняли для своего параметра, это имя переменной, которое вы используете в своем блоке.

Сокращенный синтаксис

Ruby также предоставляет сокращенный синтаксис для блоков, который позволяет вам писать простые однострочники.

Тот же блок сверху можно записать следующим образом.

books = ['To Kill a Mockingbird', '1984', 'The Catcher in the Rye']
books.each { |book| puts book }
# Outputs:
# To Kill a Mockingbird
# 1984
# The Catcher in the Rye

Написание собственных блоков

Вы не ограничены использованием уже существующих блоков. Вы можете написать свой собственный.

Скажем, у вас есть метод инициализации для класса ApiClient. Он установит обычную конфигурацию по умолчанию, но вы хотите предоставить способ настроить конфигурацию, если это необходимо. Например, кто-то может захотеть добавить дополнительный заголовок, который должен присутствовать, когда ApiClient делает запросы.

Если вы хотите использовать значение по умолчанию, вы должны сделать следующее, не передавая блок.

client = ApiClient.new

Однако что, если вы хотите начать с настроек по умолчанию, а затем дополнительно настроить конфигурацию? Может быть, что-то вроде:

api_key = 'neXYWWxojNJxckDJxSLKjW2EurdI84R8ZZucMW89wHXmFOF13udOz'
client = ApiClient.new do |config|
  config.add_header('X-API-Key', api_key)
end

Как будет выглядеть наш метод initialize?

class ApiClient
  # ...
  def initialize
    @config = ApiConfig.new
    yield @config if block_given?
    self
  end
  #...
end

Обратите внимание на часть yield. Это то, что позволяет вам прикрепить блок к вашему методу. Вы можете передать любое количество аргументов методу yield. Эти аргументы будут параметрами, переданными блоку.

Используйте block_given?, чтобы проверить, был ли задан блок, если вы хотите, чтобы он был необязательным.