YAMLをRubyへ変換する時に困らなくなる記事

YAMLファイル内の"<<"とか"&"の仕様を理解していなかったので、YAMLからRubyオブジェクトにどのように変換されるのかQiitaにまとめました。

# YAML 1.1 構文早見表

構文は次URLのリファレンスカードが見やすいです。

http://www.yaml.org/refcard.html

このリファレンスカードからtagを除いた良く使われる構文を列挙します。

- コレクション
 -    '?' : キー
 -    ':' : 値
 -    '-' : 入れ子のエントリー
 -    ',' : インラインのセパレーター
 -    '[]' : インラインで配列
 -    '{}' : インラインのマップ
- 値
 -    '''' : シングルクオート。エスケープされていない値
 -    '"'  : ダブルクオート。エスケープされた値。※YAMLのエスケープ文字について ->（http://yaml.org/spec/current.html#id2517668)
 -    '|'  : ブロック
 -    '>'  : フォールド
 -    '-'  : chompする
 -    '+'  : chompしない
 -    1-9  : インデント数。chompと組み合わせ可 ('|2-', '>+1').
- エイリアス
 -    '&'  : アンカープロパティ
 -    '*'  : エイリアス
- その他
 -     '#' : コメント行
 -    '\`@' : \`と@は予約語
- スペシャルキー
 -    '='  : マップデフォルト値のキー。 -> http://yaml.org/type/value.html
 -    '<<' : 他マップとマージ。-> http://yaml.org/type/merge.html

# YAMLからRubyオブジェクトへの変換

## コレクション

```yaml:yaml
sequence: [ one, two, ]
mapping: { sky: blue, sea: green }
```

```rb:ruby
{
  "sequence" => [
    "one",
    "two"
  ],
   "mapping" => {
    "sky" => "blue",
    "sea" => "green"
  }
}
```

## ブロック

```yaml:yaml
block:
- one
- two : three
```

```rb:ruby
{"block"=>["one", {"two"=>"three"}]}
```

```yaml:yaml
- |
 literal
- >
 folded
```

```rb:ruby
["literal\n", "folded\n"]
```

## chomp

```yaml:yaml
strip: |-
  text
clip: |
  text
keep: |+
  text
```

```rb:ruby
{"strip"=>"text", "clip"=>"text\n", "keep"=>"text\n"}
```

## インデント数

```yaml:yaml内のspace2つ
- |
  hoge
```

```rb:ruby
["hoge\n"]
```

```yaml:yaml内でspace3つと指定してるけど実際には2つ
- |3
  hoge
```

```rb:ruby
Psych::SyntaxError: (<unknown>): did not find expected '-' indicator while parsing a block collection at line 2 column 1
```

## アンカープロパティとエイリアス

```yaml:yaml
anchored: !local &anchor value
alias: *anchor
```

```rb:ruby
{
  "anchored" => "value",
     "alias" => "value"
}
```

入れ子の関係での例

```yaml:yaml
a: &a
 aa: aa
b: *a
```

```rb:ruby
{
  "a" => {
    "aa" => "aa"
  },
  "b" => {
    "aa" => "aa"
  }
}
```

## コメントの記述例

```yaml:yaml
# Comment only.
```

```rb:ruby
```

## "=" の記述例

```yaml:yaml
link with:
  - = : library1.dll
    version: 1.2
  - = : library2.dll
    version: 2.3
```

```rb:ruby
{
  "link with" => [
    {
            "=" => "library1.dll",
      "version" => 1.2
    },
    {
            "=" => "library2.dll",
      "version" => 2.3
    }
  ]
}
```

## << の記述例

マップをマージした後にエントリーを追加する例

```yaml:yaml
a: &a
 aa: aa
b:
 <<: *a
 bb: bb
```

```rb:ruby
{
  "a" => {
    "aa" => "aa"
  },
  "b" => {
    "aa" => "aa",
    "bb" => "bb"
  }
}
```

リファレンス内サンプル(http://yaml.org/type/merge.html) の実行結果

```yaml:yaml
- &CENTER { x: 1, y: 2 }
- &LEFT { x: 0, y: 2 }
- &BIG { r: 10 }
- &SMALL { r: 1 }

# All the following maps are equal:

- # Explicit keys
  x: 1
  y: 2
  r: 10
  label: center/big

- # Merge one map
  << : *CENTER
  r: 10
  label: center/big

- # Merge multiple maps
  << : [ *CENTER, *BIG ]
  label: center/big

- # Override
  << : [ *BIG, *LEFT, *SMALL ]
  x: 1
  label: center/big
```

```rb:ruby
[
  {
    "x" => 1,
    "y" => 2
  },
  {
    "x" => 0,
    "y" => 2
  },
  {
    "r" => 10
  },
  {
    "r" => 1
  },
  {
        "x" => 1,
        "y" => 2,
        "r" => 10,
    "label" => "center/big"
  },
  {
        "x" => 1,
        "y" => 2,
        "r" => 10,
    "label" => "center/big"
  },
  {
        "r" => 10,
        "x" => 1,
        "y" => 2,
    "label" => "center/big"
  },
  {
        "r" => 10,
        "x" => 1,
        "y" => 2,
    "label" => "center/big"
  }
]
```

# 参考情報

- http://yaml.org/refcard.html
- http://yaml.org/spec/1.1/
- http://yaml.org/type/
- https://en.wikipedia.org/wiki/YAML

# さいごに

railsの長くなったi18n(lng.yml)に困っていたのですがアンカー(&)とエイリアス(*)とマップのマージ(<<)を使ってスッキリさせることが出来ました。

何かありましたらコメント欄にお願いします。