YAMLで複数行テキストを書きたい時のあれこれ


TL;DR

sample.yml
text0:
  吾輩は猫である
  名前はまだ無い
text1: |-
  吾輩は猫である
  名前はまだ無い
text2: >-
  吾輩は猫である
  名前はまだ無い
text3: "\
  吾輩は猫である\
  名前はまだ無い"
YAML.load_file('sample.yml')

=>
{
  "text0"=>"吾輩は猫である 名前はまだ無い",
  "text1"=>"吾輩は猫である\n名前はまだ無い",
  "text2"=>"吾輩は猫である 名前はまだ無い",
  "text3"=>"吾輩は猫である名前はまだ無い"
}

発端

Railsでの設定ファイルとして、Yaml形式がよく使われています。特にi18n用のファイルはよく長文を記述されます。しかし、長文を一行で書くことは保守上問題ですし、改行を入れて複数行にすると、変な改行やスペースが残されますし、今まではやむをえず、読み取り側で改行を取り除くロジックを組みました。
色々調べて、やっとこちらの回答にたどり着いた。

わかったこと

Yaml 複数行で検索すると、だいたいfoo: |foo: >を使いなさいと書かれるが、使い方は実は微妙でした。

foo: |foo: |-foo: |+

まずは基本形のfoo: |

foo: |
  bar
  baz

上記Yamlはこう解釈されます。

{ "foo": "bar\nbaz\n" }

-記号を追加すると、最後の改行が無くなります。

foo: |-
  bar
  baz
{ "foo": "bar\nbaz" }

+記号について

+記号は滅多に使われないが、その意味は最後に改行が複数ある場合、そのまま反映します。

foo: |
  bar
  baz


bar: 1
{ "foo": "bar\nbaz\n", "bar": 1 }
foo: |+
  bar
  baz


bar: 1
{ "foo": "bar\nbaz\n\n\n", "bar": 1 }

foo: >foo: >-foo: >+

foo: >シリーズもだいたい一緒で、foo: |との違いは、行末の改行がスペースになります。

foo: >
  bar
  baz
{ "foo": "bar baz\n" }

""''や何も書かない時

英語圏であれば、上記の2つで十分ですが、日本語で長文を書いて、改行をしたい時は、どうしても改行もスペースもなくなりたいので、次の方法でできます。

ヒントはHeredoc記法でした。

よくShellで、行末に\追加する手法があります。それはここで改行しませんという意味です。

cat <<DOC
foo\
bar
DOC

=> foobar

Yamlでは""で囲むと、似たような使い方ができます。

foo: "\
  bar\
  baz"

上記Yamlはこう解釈されます。

{ "foo": "barbaz" }

書き方は色々あります。例えば下記の書き方も可能です

foo: "bar\
  baz\
"

ちなみの行末の\がない時、改行がスペースと解釈されます。
もし改行が必要な場合、\nを入れましょう。

foo: "\
  b\nar\
  baz\
"
{ "foo": "b\narbaz" }

余談ですが、Rubyの仕様と同じように''で囲むとき、改行がスペースになり、\nなどエスケープ文字は全部解釈されなくなります。

foo: '\
  bar\
  baz\
'
{ "foo": "\\ bar\\ baz\\ " }

何も書かない時も、実は複数行の記入も可能でした。

foo:
  bar\
  baz
{ "foo": "bar\\ baz" }

改行がスペースになる、エスケープ文字は解釈しない、そして最初と最後の改行は無視されます。

最後に

こちらの回答はいろんなニッチな使い方も羅列しており、ぜひ読んでみてください。

参考