YAML嫌いを克服する

## 本記事について
YAMLの分かりやすいようでモヤッとしたルールが苦手で、恥ずかしながら、困った時はJSONに逃げていました。

しかし、[YAMLでの失敗](https://www.kwbtblog.com/entry/2019/03/27/130027)もあり、YAMLから逃げるのではなく、むしろYAML好きになりたいと思うようになり、YAMLに関して個人的にハマったことや勘違いしていたことを中心にまとめました。

## YAMLとは？
YAMLとは、配列・マップのデータを表現するテキストフォーマットです。
人が感覚的に読みやすいことを考えて作られているのが特徴です。


## 配列
- 要素は「-」で始まり、**スペースを開けて**値を書く
- 並列する要素は、頭位置をそろえて**縦に書く**

```yaml:YAML
- A
- B
- C
```

```javascript:JSON
[
    "A",
    "B",
    "C"
]
```


## マップ
- 要素の後に「:」を書き、**スペースを開けて**値を書く
- 並列する要素は、頭位置をそろえて**縦に書く**

```yaml:YAML
a: A
b: B
c: C
```

```javascript:JSON
{
    a: "A",
    b: "B",
    c: "C"
}
```

## コメント・区切り
- 「#」以降がコメント。どこでも書ける
- 「---」で区切り

```yaml:YAML
- A # comment
# comment
- B
- C

---
- D
- E
- F
```

```javascript:JSON
[
    "A",
    "B",
    "C"
]

[
    "D",
    "E",
    "F"
]
```

## 値を次の行にずらせる
- 要素の値は次の行に書くことができる
- 値はインデントして要素の位置より下にしないといけない
  - 一部例外があるが特殊な場合なので省略

### 例１
```yaml:YAML
-
    A
- B
- C
```

```javascript:JSON
[
    "A",
    "B",
    "C"
]
```

### 例２
```yaml:YAML
a:
    A
b: B
c: C
```

```javascript:JSON
{
    a: "A",
    b: "B",
    c: "C"
}
```


## 入れ子
- 配列・マップをインデントで入れ子にできる
- 上記「値を次の行にずらせる」の応用とも言える

```yaml:YAML
# 配列 -> 配列
-
    - A
    - B
- C

# 配列 -> マップ
-
    a: A
    b: B
- C

# マップ -> 配列
a:
    - A
    - B
c: C

# マップ -> マップ
a:
    b: B
    c: C
d: D
```

```javascript:JSON
[
    ["A", "B"],
    "C"
]

[
    {a: "A", b: "B"},
    "C"
]

{
    a: ["A", "B"],
    c: "C"
}

{
    a: {b: "B", c: "C"},
    d: "D"
}
```

## インデントが超重要
- 並列する要素はインデントの頭位置を揃える
- インデントの絶対位置は関係なく、各要素が周りと比較して、自分よりインデントが上か下か同じかで、自分がどこに属するかがきまる

深さに変わらず、下記の「A, B」と「C, D」は同じ位置になる。

```yaml:YAML
-
        - A
        - B
-
    - C
    - D
```


```javascript:JSON
[
    [
        "A",
        "B"
    ],
    [
        "C",
        "D"
    ],
]
```


１文字ずれただけで意味が違ってくる。下記は構文エラー

```yaml:YAML
-
   - a
    - b
-
    - c
   - d
```

## インライン表記
- 最初に示したとおり、要素の直後に値を書ける。これをインライン表記と呼ぶ
- 要素の後に改行して、次の行以降に書くのをネクストライン表記と呼ぶ

```yaml:YAML
- A    # インライン表記
-
    B    # ネクストライン表記

---
a: A    # インライン表記
b:
    B    # ネクストライン表記
```

```javascript:JSON
[
    "A",
    "B"
]

{
    a: "A",
    b: "B"
}
```

マップのインライン表記は、**要素の値が直値（スカラー）の時のみ**可能

```yaml:YAML
# これはOK
a: A

# これはNG
a: b: B

# これもNG
a: - A
```

配列のインライン表記は、配列・マップを値にすることも可能（使ってるの見たことないけど…）（並列する要素を書く時は、頭の位置をそろえる。それにより、同じ要素だと判別される）

```yaml:YAML
# これはOK
- A

# これもOK
- a: A

# これもOK
- - A

# 応用
- - A
  - B
  - - - c: C
        d: D
    - E
```

```javascript:JSON
[
    "A"
]

[
    { a: "A" }
]

[
    [ "A" ]
]

[
    [
        "A",
        "B",
        [
            [
                { c: "C", d: "D" }
            ],
            "E"
        ]
    ]
]
```

### インライン表記とネクストライン表記の両方を書くとおかしくなる

下記は構文エラー

```yaml:YAML
a: A
    b: B
```

下記は意図していない値になる

```yaml:YAML
- A
    - B
```

```javascript:JSON
["A - B"]
```

### インライン表記で値が何もない時はnullになる。(nullが省略されている)
```yaml:YAML
-     # nullが隠れている
- B

---
a:     # nullが隠れている
b: B
```

```javascript:JSON
[
    null,
    "B"
]

{
    a: null,
    b: "B"
}
```

nullは明示的に書いてもいい

```yaml:YAML
- null
- B

---
a: null
b: B
```

## フロースタイル
- そこだけJSON形式で埋め込められるモード
- 配列は「[]」でくくり、マップは「{}」でくくり、要素は「,」で区切る
- JSONなので、改行・インデントは気にしなくていい。普段JSONを書くのと同じ感覚で書ける

```yaml:YAML
- [A, B, C]
- a:
    {
        b: "B",
        c: "C"
    }
```

```javascript:JSON
[
    ["A", "B", "C"], 
    {
        a: {b: "B", c: "C"}
    }
]
```

## ハマったポイントおさらい
- 向きは縦横どちらでもよくはない。必ず縦に並べる
  - 配列を「- a -b -c」のようには書けない
- 並列する要素は、頭の位置を必ずそろえる。（そろっていないと別の要素とみなされる）
- インデント位置は重要。絶対位置（インデントの深さ）は重要でなく、相対位置が重要
- マップは直値以外はインライン表記できない
- **インライン表記とネクストライン表記は同時に使ってはいけない**
  - インライン表記をすると、そこで要素の値が確定するので、続けてその要素の値を設定しようとするネクストライン表記を入れるとおかしくなってしまう。
  - （厳密には使っていけないことはないが、多くの場合意図した使い方ではない）
- nullは省略される
  - 多くの場合、ミスによる意図しないnullが挿入されている

## 参考情報
- https://yaml.org/
- https://magazine.rubyist.net/articles/0009/0009-YAML.html

## 元記事
- [YAML嫌いを克服する](https://www.kwbtblog.com/entry/2019/03/27/130027)