RubyでERBが書かれたyamlをロードする

## 概要

本記事は初心者向け、もしくはぱっと結果だけを知りたい方向けの記事です。

`Ruby` の標準ライブラリである `yaml` と `erb` を使うことで、以下のような `Rails` などでよく見る `yaml + erb` の組み合わせを簡単に実現できます。(`Ruby` はすごい！)

```yaml:config/database.yml
development:
  adapter: mysql2
  database: sample_mksava_development
  pool: <%= ENV["MAV_POOL"] || 5 %>
  username: root
  password: <%= ENB["DB_PASSWORD"] %>
```

その方法を記載した実際のコードを載せているので誰かの参考やふとしたときに役立ってもらえれば嬉しいと思い本記事を掲載しました。
結果だけみたいという人は[本題](#本題)まで飛んでください。

## 要約

* `Ruby` では、 外部ライブラリ(`Gem`) を使わず、標準ライブラリのみで `Ruby` プログラム(`ERB`)が中に記載された `YAML` のロードができます。
* 本記事で紹介するクラスに処理をまとめているので、まるっとコピペしてそのまま使えます。
* 標準ライブラリだけで使えるので、 `Gem` が使えない、`OSS` の取り扱いが厳しくなって新規に `Gem` を入れるのが面倒、という環境でもさくっと動かせるのでぜひご利用ください。

## YAMLとは

`YAML` とは一言で言うと「読みやすくて書きやすい、構造化されたデータの記載ルール」です。

詳細やその生い立ちは[Googleで検索](https://www.google.com/search?q=yaml+%E3%81%A8%E3%81%AF)することで調べられますが、以下のような形で記載された文章のことだと思っていてください。

```yaml
animals:
  cats:
    tama: "たま"
    buchi: "ぶち"
    mochikichi: "もちきち"
  dogs:
    pochi: "ぽち"
    ryou: "りょう"
```

上記だと「動物たち(animals)」の中には「猫たち(cats)」「犬たち(dogs)」が含まれていて、「猫たち」には「たま(tama)」「ぶち(buchi)」「もちきち(mochikichi)」がいるんだー、というのがなんとなく分かります。

このように

`「動物たち」->「犬」「猫」->「犬の名前や猫の名前」`

というのが **構造化されたデータ** であり、こうしたデータを「読みやすくて書きやすい」のがyamlの特徴といえます！

## ERBとは

`ERB` とは一言で言うと「`Ruby(.rb)` じゃないファイルの中の好きなところで `Ruby` を実行できるよ」というすごいやつです。

以下の記事に簡単な使い方があるのでおすすめです。

[Railsに入る前にしっておきたいERBとActiveRecordのこと](https://qiita.com/mksava/items/dc34749268513fd75bf0#erb%E3%81%A8%E3%81%AF)

私の記事の宣伝でした…。いえ、これもまた[Googleで検索](https://www.google.com/search?q=ERB+%E3%81%A8%E3%81%AF)するときっといい解説が出てくれるはずです。

ざっくり言うと

* `<% %>` で囲まれたところにある `Ruby` のプログラムを実行してあげるよ
* `<%= %>` だと、記載されている場所を実行した結果に書き換えてあげるよ
* それ以外の部分はそのままにするよ

ということをしてくれます。

```erb
僕の名前は<%= "mksava".upcase %>です。
```

だと

```ruby
僕の名前はMKSAVAです。
```

という文字列にしてくれます。

すごいですね。 `ERB` 大好き。

## 本題

ではいきなり本題ですが、以下がタイトルにある処理ができる `Ruby` のクラスを記載したファイルになります。

```ruby:yaml_client.rb
# YAMLを利用するため標準ライブラリのyamlをロードする
require "yaml"
# ERBを利用するため標準ライブラリのerbをロードする
require "erb"

class YamlClient
  # YAMLファイルをロードし、ERBで展開を行ったHashを返す
  # @param [String] yaml_file_path YAMLファイルへのパス
  # @param [String] namespace 常に先頭でアクセスする値があれば指定する。Railsでもよく使われる例です。詳細はexample.ymlを参照ください。
  # @return [Hash] YAMLをHashへ変換したオブジェクト
  def load(yaml_file_path, namespace: "")
    # Yamlファイルをロードする
    yaml_body = File.read(yaml_file_path)
    # ERBを実行する
    yaml_body = ERB.new(yaml_body).result

    # 結果をYAMLとしてロードする
    yaml = YAML.load(yaml_body)

    # もし名前空間が渡されていれば設定する
    if namespace.to_s.empty?
      yaml
    else
      yaml[namespace.to_s]
    end
  end
end
```

### 使い方

まず読み込む対象の `yaml` ファイルを作ります。

ここでは `example.yml` という名前で作成をしました。

```yaml:example.yml
default: &default
  app_name: "Hello Yaml"
  systems:
    bool_v: true
    number_v: 1
    float_v: 1.2
    erb_string: <%= "neko".upcase %> #=> NEKO
    animals:
      - Dog
      - Cat
      - Bird
    stores:
      - name: "A store"
        address: "A-b-112"
      - name: "B store"
        address: "Sunmart-N-11"
development:
  <<: *default
  app_name: "Develop YAML"
```

そして以下のようにスクリプトを作ることで使用ができます。

※ここでは `example.rb` という名前でファイルを作成しました。
※`yaml_client.rb`、`example.yml`、`example.rb`は全て同じディレクトリにある前提です。

```ruby:example.rb
require_relative "./yaml_client"

yaml_client = YamlClient.new

# 名前空間なし
yaml = yaml_client.load("./example.yml")
puts yaml["default"]["app_name"]
puts yaml["default"]["systems"]["erb_string"]
puts yaml["default"]["systems"]["animals"][0]
puts yaml["default"]["systems"]["stores"][0]["name"]

# 名前空間あり
yaml = yaml_client.load("./example.yml", namespace: "development")
puts yaml["app_name"]
puts yaml["systems"]["erb_string"]
puts yaml["systems"]["animals"][0]
puts yaml["systems"]["stores"][0]["name"]
```

* 実際に動かした結果はこちらです

```shell
$ ls
example.rb      example.yml     yaml_client.rb
$ ruby example.rb 
# 名前空間なし
Hello Yaml
NEKO
Dog
A store
# 名前空間あり
Develop YAML
NEKO
Dog
A store
```

このように標準ライブラリだけで動くので、 `AWS` の `Lambda` でちょろっと動かしたいときや、わざわざ `Gemfile` を作ったりインストールするのが面倒だ、というときなどは、 `yaml_client.rb` の内容をそのままコピーして使ってください。

中級者の方であれば `ERB` の `trim mode` とかを修正したりして使ってもらっても大丈夫です！

この内容は以下から全てダウンロードもできます。

https://github.com/mksava/happy_ruby_codes/tree/main/%E6%A8%99%E6%BA%96%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE%E3%81%BF%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E9%9B%86/YAML%E3%82%92ERB%E6%9C%89%E3%81%A7%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B

## まとめ

* `YAML` は構造化されたデータを読みやすく書きやすく記載できるルールで記載された文章です
* `ERB` は `Ruby` のプログラムを `Ruby` 以外のファイルを実行できるすごいやつです
* `Gem` を使わず、標準ライブラリのみで `ERB` の記載された `YAML` をロードするクラスを作ったので参考にしたり好きに使ってください！
  * 注意: 同じことを実現できる便利な `Gem` はたくさんあるので、 `Gem` を使うにこしたことはないです！

## 最後に

以下に「もしかしたら誰かが幸せになるかもしれない」「痒い所に手が届くかもしれない」ちょっとした `Ruby` のサンプルコード集をまとめています。

他にもいろいろなサンプルも置いていたり、今後も増やしていきたいなと思っているので、もしよろしければぜひ見てみてください。

https://github.com/mksava/happy_ruby_codes