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


概要

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

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

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で検索することで調べられますが、以下のような形で記載された文章のことだと思っていてください。

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

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

このように

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

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

ERBとは

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

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

Railsに入る前にしっておきたいERBとActiveRecordのこと

私の記事の宣伝でした…。いえ、これもまたGoogleで検索するときっといい解説が出てくれるはずです。

ざっくり言うと

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

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

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

だと

僕の名前はMKSAVAです。

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

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

本題

ではいきなり本題ですが、以下がタイトルにある処理ができる 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 という名前で作成をしました。

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.rbexample.ymlexample.rbは全て同じディレクトリにある前提です。

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"]
  • 実際に動かした結果はこちらです
$ ls
example.rb      example.yml     yaml_client.rb
$ ruby example.rb 
# 名前空間なし
Hello Yaml
NEKO
Dog
A store
# 名前空間あり
Develop YAML
NEKO
Dog
A store

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

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

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

まとめ

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

最後に

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

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