【技術備忘録①】YAML記法と不明点記録。

- 現在利用している言語や技術の記法や不明点等を記録していく記事第一弾。
- 「車輪の再発明はしない」という、名高い賢人技術者達が徹してきたことを、「ページ遷移解消」という理由だけで、自分の所に収める作業をし続ける技術者そっくりさん。
- 今回は、設定ファイル等で利用する「yaml」学習にあたっての記法とつまずき解消点を整理することにしよう。

## 概要
- 人間にとって、読みやすいデータ直列化の標準形式。
- フレームワークやツールでの設定ファイル記述や、データ保存の際に利用。
- [公式サイト](https://yaml.org/)
- その他、データ形式言語として、`XML`,`JSON`等がある。

## 特徴
### わかりやすさ
- 記述がシンプルかつ、人間が「読みやすい・書きやすい・理解しやすい」ように作られている。

### インデント表記
- データの構造を、インデント(字下げ)によって、組み立てることができる。

## 用語
- YAMLで使われる基本用語は下記。
    - スカラー
        - 値。文字列や数値、真偽値等。
    - シーケンス
        - 配列。
    - マッピング
        - 連想配列。ハッシュ。
    - アンカー
        - 変数。アドレス。
    - エイリアス
        - 別名。参照。ポインタ。

## 記法
### 準備
- YAMLは、様々な言語に対応しているが、今回は**Rubyを利用する。**
- 環境として、下記を使用。
    - ruby 2.6.0

### チュートリアル
- yamlのファイル拡張子は、「.yml」とする。
- 下記、サンプル。
- ※**今後yamlを出力するRubyファイルは、基本的に下記を使用。**

```ruby:test.rb
# yaml命令の扱い
require 'yaml'
# yamlファイルの読み込み
names = YAML.load_file('info.yml')
# yaml設定内容の出力
p names
```

```yaml:info.yml
# 「名前」の管理
- tanaka
- suzuki
- satou
```

- サンプルでの出力結果は、下記。

```shell
$ ruby test.rb

["tanaka", "suzuki", "satou"]
```

### 扱えるデータ形式
- YAMLでは、下記の3つがある。
    - **スカラー**
    - **シーケンス**
    - **マッピング**

#### 1. スカラー
- 値。
    - 文字列
    - 数値
    - 真偽値
    - NULL
    - 日付

- 下記、例。
    - ※型は自動判別

```yaml
# 文字列
- tanaka
# 数値
- 56
# 真偽値
# 記法として、「true/false」「yes/no」「on/off」があり、真偽値として扱われる。
- false
# null
# 記法として、「null」「~」がある。
- null
# 日付
- 2019-04-22
# 真偽値を文字列として扱う場合。
- 'false'
# 数値を文字列として扱う場合。
- '78'
```

- 下記、出力結果

```bash
$ ruby test.rb

["tanaka", 56, false, nil, #<Date: 2019-04-22 ((2458596j,0s,0n),+0s,2299161j)>, "false", "78"]
```


#### 2. シーケンス
- 配列
- 下記、例。

```yaml
# ブロックスタイル
- tanaka
- suzuki
- satou
```

- 下記、出力結果。

```bash
$ ruby test.rb

["tanaka", "suzuki", "satou"]
```

- 下記、その他書き方。

```yaml
# フロースタイル
[78,56,34]

# 入れ子構造
# ※1文字以上の空白必要。タブは使えない。
# ※入れ子の際、その前に何もつけない。
- tanaka
- 
  - suzuki
  - satou
- sakamoto
```

#### 3. マッピング
- 連想配列やハッシュ。
    - key,value型のデータ
- 下記、例。
- ※「:」の後の空白は必要。

```yaml
# ブロックスタイル
name: tanaka
age: 67
```

- 下記、出力結果。

```bash
$ ruby test.rb

{"name"=>"tanaka", "age"=>67}
```

- 下記、他の書き方。

```yaml
# フロースタイル
{ name: suzuki, age: 38 }

# 入れ子
name: satou
age: 
  first : 12
  second: 24
```

### 様々な構造の組み合わせ

#### シーケンスとマッピング
- シーケンスとマッピングを組み合わせて、構造を定義。
- 下記、「配列が値のハッシュ」

```yaml
# ブロックスタイル
name: 
  - tanaka
  - satou
  - suzuki
age: 
  - 56
  - 30
  - 35

# フロースタイル
name: [tanaka,satou]
age: [67,30]
```

- 下記、「ハッシュが値の配列」

```yaml
# ブロックスタイル
- name: tanaka
  age: 67
- name: satou
  age: 30
- name: suzuki
  age: 69
```

- 下記、出力結果

```bash
$ ruby test.rb

[{"name"=>"tanaka", "age"=>67}, {"name"=>"satou", "age"=>30}, {"name"=>"suzuki", "age"=>69}]
```

- 下記、他の書き方。

```yaml
# フロースタイル
- { name: tanaka, age: 67 }
- { name: satou, age: 30 }
```

### 改行データの扱い
- YAMLでは、改行は文字列として、扱われる場合がある。
- 下記の書き方では、一つの文字列になる。

```yaml
# 結果 : "I am Tanaka"

I
am
Tanaka
.
```

- 改行を含める場合、「|」という縦棒を加えた記述をする。
- 下記、例。

```yaml
# 結果 : ["I\nam\nTanaka\n.\n"]
- |
  I
  am
  Tanaka
  .

# 結果 : ["I\nam\nTanaka\n.\n\n"]
- |+
  I
  am
  Tanaka
  .

# 結果 : ["I\nam\nTanaka\n."]
- |-
  I
  am
  Tanaka
  .

```

- 下記、「途中の改行はスペース、最後の改行だけ保持」の場合。
- 「>」という、不等号を加える。

```yaml
# 結果 : ["I am Tanaka .\n"]
- >
  I
  am
  Tanaka
  .

# 結果 : ["I am Tanaka .\n\n"]
- >+
  I
  am
  Tanaka
  .

# 結果 : ["I am Tanaka ."]
- >-
  I
  am
  Tanaka
  .

```

### アンカーとエイリアス
- YAMLでは、アンカー(変数)とエイリアス(参照名、別名)をつけることができる。
- 下記、基本例。

```yaml
# アンカー定義は、「&」で行う。
- &name suzuki
# エイリアス利用定義は、「*」で行う。
- *name
- &age 89
- *age
```

- 下記、出力結果

```bash
$ ruby test.rb

["suzuki", "suzuki", 89, 89]
```

- 下記、「ハッシュ」にアンカーやエイリアスを利用した、複雑なデータ構造例。

```yaml
- &satou
  name: satou
  age: 89
- &suzuki
  name: suzuki
  age: 43
  roommate:
    - *satou
- name: siraishi
  age: 39
  roommate:
    - *satou
    - *suzuki
```

- 下記、出力結果

```bash
$ ruby test.rb

[{"name"=>"satou", "age"=>89}, {"name"=>"suzuki", "age"=>43, "roommate"=>[{"name"=>"satou", "age"=>89}]}, {"name"=>"siraishi", "age"=>39, "roommate"=>[{"name"=>"satou", "age"=>89}, {"name"=>"suzuki", "age"=>43, "roommate"=>[{"name"=>"satou", "age"=>89}]}]}]
```

### ハッシュのマージ
- YAMLでは、「<<」記号を用いることにより、ハッシュをマージ(反映)することができる。
- 下記、例。

```yaml
# 共通化するもの
common: &common
  user: mydb
  pass: mydbpass
# 環境毎の設定(開発)
devlopment: 
  dbname: devdb
  <<: *common  # 共通化部分のマージ(反映)
# 環境毎の設定(ステージング)
staging: 
  dbname: stgdb
  <<: *common
# 環境毎の設定(本番)
production: 
  dbname: prodb
  <<: *common
```

- 下記、出力結果。

```bash
$ ruby test.rb

{"common"=>{"user"=>"mydb", "pass"=>"mydbpass"}, "devlopment"=>{"dbname"=>"devdb", "user"=>"mydb", "pass"=>"mydbpass"}, "staging"=>{"dbname"=>"stgdb", "user"=>"mydb", "pass"=>"mydbpass"}, "production"=>{"dbname"=>"prodb", "user"=>"mydb", "pass"=>"mydbpass"}}
```

### データの区切り
- YAMLでは、一つのファイルで、複数のデータ群を用いることが一般的。
- その際は、下記の記号を用いる。
    - 「---」・・・データの始まり
    - 「...」・・・データの終わり
- 下記、例。
- ※複数のデータを扱うため、今までのRubyファイルは修正。

```yaml
# データ開始記号 : 「---」
# データ終了記号 : 「...」
---
- tanaka
- suzuki
- satou
...         # データ終了記号は省略できる。
---
- siraishi
- hashimoto
- matumura
...
```

```ruby:test.rb
require 'yaml'

# ファイル読み込みして、io変数に格納
File.open('info.yml') do |io|
  # 複数のデータ読み込みは、「load_stream」を利用。
  YAML.load_stream(io) do |d|
    p d
  end
end
```

- 下記、出力結果

```bash
$ ruby test.rb

["tanaka", "suzuki", "satou"]
["siraishi", "hashimoto", "matumura"]
```

#### 不明点
- **YAML.load_documents**の利用に関して
    - 学習サイト等では、`YAML.load_documents`を利用したデータ読み込み方法があるが、現在は非推奨らしい。
    - 代わりに、上記のように`YAML.load_stream`を利用。

### RubyからYAMLへの変換
- YAML記法を忘れた際に、Rubyの配列やハッシュを、YAML形式に変換してくれるものある。
- 変換の際には、Rubyファイルで、「to_yaml」というメソッドを利用。

```ruby:test.rb
require 'yaml'

member = [
    { 'name' => 'tanaka', 'age' => 78 },
    { 'name' => 'suzuki', 'age' => 69 }
]

puts member.to_yaml
```

- 下記、出力結果

```bash
$ ruby test.rb

---
- name: tanaka
  age: 78
- name: suzuki
  age: 69
```

## まとめ
- 今回は、YAML学習ということで、「簡単に設定が書けるなんて、先端的だな」という、歴史が意外にも古いことに気づかず、能天気になりながら記事を書く。
- 「この備忘録では、きちんと脳内脱出を防げるようにしよう」という、従来と同じ書き方で記事を書きながらの、迷走思考。
- 「こういう書き方で、数をこなしていけば、おのずと質も追いついてくるか」と、涼しげに気楽思考を巡らせることにしよう。

## 学習サイト
- [プログラマーのための YAML 入門 (初級編)](https://magazine.rubyist.net/articles/0009/0009-YAML.html)  
→こちらの記事を中心に学習しました。大変お世話になりました。
- [YAML 基本記法まとめ](https://qiita.com/tfrcm/items/5f8e4c5795ce41b214d1)  
→こちらの記事を参考にしました。大変お世話になりました。
- [ドットインストール - 3分動画でマスターする初心者向けプログラミング学習サイト](https://dotinstall.com/)  
→こちらで学習しました。大変お世話になりました。