YAMLとは何か？ - いつもRailsの設定ファイルで出てくるやつの正体

※ _「[あなたがRails触る人なら見ておきたい「体系的な」豆知識](http://qiita.com/Yama-to/items/93cd8b3a8be67b09e353)」からの派生記事です。_

## yamlっていったい何者

- **`yaml ain't markup language`** の略
- 一般的な拡張子は `.yml`
- 構造化データの表現方法
- あくまでも仕様を表すため仕様を処理する実装が別途必要
- 以下の言語でyamlを使用した実装がサポートされている
  - Java
  - JavaScript
  - Perl
  - PHP
  - Python
  - Tcl
  - Ruby
  - XML

_※なお以下の説明ではrubyを使用します。_

## yamlの用途を端的に

- 各種設定ファイル
- データの保存・シリアライゼーション用
- データ交換用フォーマット
- ログファイル

## yamlの特徴を端的に

- 読みやすく・書きやすく・わかりやすいという特徴がある
- インデントを使ってデータの階層構造を表す
- 終了タグが存在しない
- データ構造をハッシュ・配列・スカラーの三種類で表す

_※例えばこんな感じで使う_

```input.yml
- d1
- d2
- d3
```

```output.rb
require 'yaml'

d = YAML.load_file('input.yml')
p d

# => ["d1", "d2", "d3"]
```

- 上のやつは配列になる
- rubyファイル内では `require`をつかってyamlを導入する

## yamlの書き方はよ

- 二種類の文法を主に使用する
  - シーケンス（配列形式でデータ構造を表す）
  - マッピング（ハッシュ形式でデータ構造を表す）
- コメントアウトはパウンド記号(`#`)
- 入れ子構造はインデントで表すが留意事項が二点
  - インデントにタブ記号は使えない
  - 多くの場合インデントは空白2文字で表す

---

### ■シーケンス(配列形式)の書き方

- シーケンス ＝ `-(空白)value`
- 空白は必須であり無いとエラーが起こる
- 値の無い行の後に字下げを使うと入れ子構造になる

```input.yml
- d1
- d2
- d3
#=> ["d1", "d2", "d3"]

- d1
-
  - x1
  - x2
- d3
#=> ["d1", ["x1", "x2"], "d3"]
```

---

### ■マッピング(ハッシュ形式)の書き方

- マッピング = `key:(空白)value`
- こちらも空白は必須であり無いとエラーが起こる
- 値の無い行の後に字下げを使うと入れ子構造になる

```input.yml
name : tomato
email: potato@gmail.com
#=> {"name"=>"tomato", "email"=>"potato@gmail.com"}

name  : tomato
emails:
  mainaddress: potato@gmail.com
  subaddress : jagaimo@gmail.com
#=> {"name"=>"tomato", "emails"=>{"mainaddress"=>"potato@gmail.com", "subaddress"=>"jagaimo@gmail.com"}}
```

---

### ■複雑なデータ構造を表したい時

- シーケンスとマッピングはお互いに入れ子構造にできる

```input.yml
# 配列の各値がハッシュ
- name : tomato
  email: tomato@gmail.com
- name : potato
  email: potato@gmail.com
#=> [{"name"=>"tomato", "email"=>"tomato@gmail.com"}, {"name"=>"potato", "email"=>"potato@gmail.com"}]

# ハッシュの各値が配列
names :
  - tomato1
  - tomato2
emails:
  - potato1@gmail.com
  - potato2@gmail.com
#=> {"names"=>["tomato1", "tomato2"], "emails"=>["potato1@gmail.com", "potato2@gmail.com"]}
```

---

### ■ブロックスタイルとフロースタイル

- シーケンスとマッピングには2種類の記法がある
- ブロックスタイル
	- これまで見てきたyaml固有の書き方
- フロースタイル
	- rubyに似通った書き方

```input.yml
# ブロックスタイル
- tomato
- potato
#=> ["tomato", "potato"]

name : apple
color: red
#=> {"name"=>"apple", "color"=>"red"}


# フロースタイル
[tomato, potato]
#=> ["tomato", "potato"]

{name: apple, color: red}
#=> {"name"=>"apple", "color"=>"red"}
```

- 2種類の書き方を併用することで複雑なデータ構造を表現できる

## yamlのデータ型を端的に

- データ型は自動で認識する
- 文字列っぽいものは文字列に、数値っぽいものは数値に
- 文字列に型変換する時にはダブルクォーテーション(`"`)で囲む

```input.yml
str    : tomato
int    : 45
float  : 5.21
bool1  : true
bool2  : false
blank  : null
date   : 2015-7-27

#=> {"str"=>"tomato", "int"=>45, "float"=>5.21, "bool1"=>true, "bool2"=>false, "blank"=>nil, "date"=>#<Date: 2015-07-27 ((2457231j,0s,0n),+0s,2299161j)>}


to_str1: "45"
to_str2: "true"

#=> {"to_str1"=>"45", "to_str2"=>"true"}
```

- 他にもキャスト(型変換)の方法はあるが詳しくは文末のリンクを参照されたい

## yamlでの改行表現のバリエーション

- yamlではテキストの改行は認識されずスペースに変換される

```input.yml
doc:
  aaa
  bbb
  ccc
#=> {"doc"=>"aaa bbb ccc"}
```

- 改行を認識させる方法は二種類ある

---
 
- 大なり(`>`)を用いて文章最後の改行のみを認識させる方法

```input.yml
doc: >
  aaa
  bbb
  ccc
#=> {"doc"=>"aaa bbb ccc\n"}
```

---

- パイプ(`|`)を用いて全ての改行を認識させる方法
- これらの文法はマッピングだけでなくシーケンスでも使える

```input.yml
doc: |
  aaa
  bbb
  ccc
#=> {"doc1"=>"aaa\nbbb\nccc\n"}

- |
  aaa
  bbb
  ccc
#=> ["aaa\nbbb\nccc"]
```

## yamlでの複数データ構造の併記方法

- 複数データの区切りを表す方法は二種類ある
- 例えば複数のシーケンスが意図せずひとつなぎになってしまう時に使える

```input.yml
- d1
- d2
- d3

- x1
- x2
#=> ["d1", "d2", "d3", "x1", "x2"]
```

---

- ピリオド×3つ(`...`)を使用して以降の読み込みを中止する場合
- デバッグ等で以降の操作を一時的に取りやめたいときに便利

```input.yml
- d1
- d2
- d3
...
- x1
- x2
#=> ["d1", "d2", "d3"]
```

---

- ハイフン×3つ(`---`)を使用してデータ区切りを示す場合
- 複数のデータのまとまりをつくることができる
- 複数のデータを読み込む際には呼び出し方法が若干異なる
- yamlのデータであることを示すために先頭に(`---`)を付与することもある

```output.rb
File.open('input.yml') do |io|
  YAML.load_documents(io) do |d|
    p d
  end
end
```

```input.yml
−−−
- d1
- d2
- d3
---
- x1
- x2
#=>
["d1", "d2", "d3"]
["x1", "x2"]
```

---

【アペンディックス】

- もっと実践的な知識がほしいよ、という方はこちら
- 参考リンク「[Rubyist Magazine: プログラマのためのYAML入門](http://magazine.rubyist.net/?0009-YAML#l0)」