😎

Ruby でヒアドキュメント内で条件分岐やループ処理を行う方法

2021/09/06に公開

はじめに

複数行に渡る文字列を生成したいとき、ヒアドキュメントは便利だが、ヒアドキュメント内で条件分岐やループ処理を行う際に少し苦労したのでまとめておく。

実装方法

例として、以下のような仕様のコマンドラインスクリプトを実装してみる。

  • マークダウンで記述されるブログ記事に、自動で YAML ヘッダをつける機能を持つ
  • 引数としてタイトルやサムネイル画像、タグを与えると、@options 変数で各引数の値を取得できる

その際の、YAML ヘッダをヒアドキュメントで記述する。

require 'erb'

header = <<~'HEADER'
  ---
  layout: post
  title: "<%= @options[:title] %>"
  image: "<%= @options[:image] %>"
  date: "<%= Time.now.strftime('%Y-%m-%d') %>"
  tags:
  <%- @options[:tags]&.each do |tag| -%>
  - <%= tag %>
  <%- end -%>
  ---
HEADER

puts ERB.new(header, nil, '-').result(binding)

\n を実際の改行に変換した結果は以下のように出力される。

---
layout: post
title: "Hello world!"
image: "/images/2021/09/hello_world.png"
date: "2021-09-06 22:37:34"
tags:
- greeting
- first-post
---

解説

ヒアドキュメント内で条件分岐やループ処理を行いたい場合は ERB を使用する。

  • <%--%> で囲まれた箇所で Ruby が実行される
  • <%=%> で囲まれた箇所は Ruby が実行された際の戻り値が出力される

上記 2 つのどちらも、囲まれた箇所で Ruby が実行されるが、違いとしては出力結果がそのまま表示されるかされないかだ。

@options[:tags]&.each do |tag|end の部分は、結果を出力するわけではなく、単に Ruby を実行してほしいだけなので <%--%> で囲む。

trim_mode について

なお、<%--%> の記法は ERB のインスタンスを生成する際の第 3 引数に '-' を指定することで使用可能となる。これは trim_mode と呼ばれる。

# 第 3 引数に '-' を指定
ERB.new(header, nil, '-').result(binding)

trim_mode を使わずに、ヒアドキュメントの出力のみを引数に指定するならば、以下のように記述することもできる。

require 'erb'

erb = ERB.new <<~'HEADER'
  ---
  layout: post
  title: "<%= @options[:title] %>"
  image: "<%= @options[:image] %>"
  date: "<%= Time.now.strftime('%Y-%m-%d') %>"
  tags:
  <% @options[:tags]&.each do |tag| %>
  - <%= tag %>
  <% end %>
  ---
HEADER

puts erb.result(binding)

ERB インスタンス生成時の第 1 引数に直接ヒアドキュメントを渡す書き方だ。trim_mode を用いないので <%--%> ではなく <%%> を使用している。

この場合、出力が以下のようになる。

---
layout: post
title: "Hello world!"
image: "/images/2021/09/hello_world.png"
date: "2021-09-06 22:43:28"
tags:

- greeting

- first-post

---

余計な空行が出力されてしまっている。これは <% @options[:tags]&.each do |tag| %> の部分と <% end %> の部分が、行としては存在しているが、何も出力されないためである。

このように、ただ Ruby のコードを実行させたいだけの行でも、存在している以上は出力結果に反映されてしまう。

これを解決するのが trim_mode である。今回の例では第 3 引数に - を指定したので <%%> の代わりに <%--%> を使うことで、余計な改行が入らなくなる。

trim_mode についての詳細は ERB のリファレンスマニュアル を参照すること。

弱点

ERB を使用するとヒアドキュメント内で条件分岐やループ処理を行うことができるが、以下のデメリットがある。

  • シンタックスエラーが発生した際に、行数が若干わかりづらい

ERB を用いたヒアドキュメント内でシンタックスエラーが発生すると、そのエラーが発生した箇所が、ヒアドキュメント内の行数で表示される。ファイルの行数ではない。

そのため、ぱっと見で何行目にシンタックスエラーがあるのかがわからない。あまりヒアドキュメントが長くなりすぎると、シンタックスエラーが発生した際の追跡が難しくなる点に注意すること。

参考

GitHubで編集を提案

Discussion