HEREDOC и его использование в Ruby

Что такое HEREDOC и для чего его используют? Основная цель - написание больших блоков текста (документации) в коде, а также его передача в переменные. HEREDOC - сокращение от "here document".

Чтобы передать HEREDOC переменной, можно использовать привычный синтаксис присваивания:

a = <<HEREDOC
  Текст документа в переменной
HEREDOC

puts a

Результат:

Текст документа в переменной

Для более подробного ознакомления с "heredoc" создадим пустой *.rb файл и запишeм в него следующую конструкцию:

def test_heredoc
<<HEREDOC
  Тут у нас будет первая строка документа.
  А тут вторая.
  И третья.
HEREDOC
end

Результат:

  Тут у нас будет первая строка документа.
  А тут вторая.
  И третья.

В данном примере документация начинается после строки "<< HEREDOC" и заканчивается перед "HEREDOC".

Стоит отметить, что "HEREDOC" вовсе не обязательно писать в верхнем регистре.

Также вместо ключевого слова "HEREDOC" можно использовать любое угодное. "HEREDOC" используется чаще всего программистами, что дает ясно понять, что описывается внутри этой конструкции.

def some_method
  <<-something
    Это документация, которая использует "something" вместо "HEREDOC".
    :)
  something
end

puts some_method

Результат запуска 'heredoc.rb':

    Это моя документация, которая использует "something" вместо "HEREDOC".
    :)

Если посмотреть на пример кода метода test_heredoc, показанный в самом начале этой страницы - можно заметить, что не хватает табуляции (отступов на строках, которыми открывается и закрывается "heredoc"). В следующем методе some_method - табуляция присутствует.

Это связано с тем, что конструкция из первого примера "<<" чувствительна к форматированию. Во втором примере конструкция "<<−" (с знаком 'минус' в конце) позволяет форматировать наш код.

"<<−" делает так, что идентификатор конструкции "heredoc" читается так, как если бы он начинался в самом начале строки. Код содержащийся внутри идентификатора читается буквально - и покажет отступы при выводе в терминале.

Чтобы отформатировать текст и избавиться от лишних отступов в начале строк при печати в терминал - нужно использовать символ лямбды "~" после "<<".

Называется эта конструкция - "squiggly".

def some_squiggly_method
  <<~something
    Это документация, которая имеет отступы у идентификатора "heredoc".
    Отступы в начале документации также обрезаются.
  something
end

puts some_squiggly_method

Результат:

Это документация, которая имеет отступы у идентификатора "heredoc".
Отступы в начале документации также обрезаются.

Обратите внимание, что "squiggly" не просто удаляет все отступы в начале строк, а принимает самый короткий отступ в качестве эталона. Все более длинные отступы будут обрезаны ровно по него. Этот функционал позволяет форматировать документацию и исключать ненужные отступы.

Пример:

def some_squiggly_method
  <<~something
      Это документация, которая имеет отступы у идентификатора "heredoc".
      Отступы в начале документации также обрезаются.
    Все отступы обрезаются по эту строку.
  something
end

puts some_squiggly_method

Вывод программы:

  Это документация, которая имеет отступы у идентификатора "heredoc".
  Отступы в начале документации также обрезаются.
Все отступы обрезаются по эту строку.

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

"HEREDOC" позволяет нам использовать Ruby-код внутри себя, что позволяет делать документацию динамической:

@rand_number = rand(10)

def some_method
  <<~something
    Случайное число #{@rand_number} + 1 = #{@rand_number + 1}
  something
end

puts some_method

Запустим код:

Случайное число 9 + 1 = 10

Если нам необходимо интерполировать Ruby-код в документации - мы просто возьмем идентификатор нашего "heredoc" в одинарные кавычки:

@rand_number = rand(10)

def some_method
  <<~'something'
    Случайное число #{@rand_number} + 1 = #{@rand_number + 1}
  something
end

puts some_method

Результат:

Случайное число #{@rand_number} + 1 = #{@rand_number + 1}

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

Существует способ комбинирования "heredoc", который выглядит так:

def some_method
  puts(<<~first, <<~second)
    Текст первого хирдока
  first
    Текст второго хирдока
  second
end

some_method

Результат:

Текст первого хирдока
Текст второго хирдока

Ссылки:
RubyDoc