Liquid ファイルを用いて Embulk の設定ファイルを DRY に書く

Liquid

Liquid の公式サイトはこちらです。

Embulk

Embulk の公式サイトはこちらです。この記事では Embulk そのものについては扱いません。

Embulk の設定ファイルとして Liquid を用いる

Embulk の設定ファイルは YAML で書かれます。加えて、「YAML を include 可能にした拡張形式である*1 Liquid という形式」にも対応しています。

ここでは Liquid を用いて Embulk の設定ファイルをどのように書けばいいのかを記していきます。

原則

まず原則をいくつか書き連ねます。

  • Liquid ファイルの中身の書式は YAML そのものである
  • Liquid ファイルは多段に include することはできない*2
  • したがって設定ファイル群の構成は次のとおりになる
    • 「全ての Liquid ファイルが include される親ファイル(include 先となるファイル)」が一つある
    • 上記のファイル以外は include されるファイル(子ファイル)になる
  • 「親ファイル」も「子ファイル」も Liquid ファイルである
  • Liquid ファイルの拡張子は .yml.liquid である
    • つまり全てのファイルの拡張子は .yml.liquid である
  • 「子ファイル」のファイル名の先頭には _(アンダーバー、アンダースコア)を付与する
    • 「親ファイル」のファイル名には命名規則はない
  • 「子ファイル」の場所はサブディレクトリ内でもよい
    • include の際に指定すればよい
    • ただし自分より下位のディレクトリでなければいけない*3

include するときの規則

Liquid ファイルを include する際の規則は次のとおりです。

  • include したいファイル名*4{%%} で囲む
    • ただし、囲まれるファイル名は以下の規則に従う
      • 拡張子*5は省略する
      • ファイル名の先頭の _(アンダーバー、アンダースコア)は省略する
  • include 命令を記述する際は YAML のインデントに則って記載する*6
    • include 命令そのもの*7インデントをせずに記述し、include されるファイル(「子ファイル」)にてインデントを行う*8

具体例

上記までの内容を踏まえ、具体的な例を見ていきます。

「親ファイル」の内容

まず、全てのファイルのファイル名が以下のとおりであるとします。

  • parent.yml.liquid
  • _input.yml.liquid
  • _diff.yml.liquid
  • _output.yml.liquid

parent.yml.liquid が「親ファイル」で、それ以外のファイルは parent.yml.liquid に include されます。したがって、parent.yml.liquid の内容は以下のようになります。

{% include 'input' %}
{% include 'diff' %}

{% include 'output' %}
  table: my_table

ここで、{% include 'diff' %} はインデントをした上で include されていることと、「table: my_table」という項目が直書きで追加されていることは大切なところです。

{% include 'input' %}{% include 'diff' %} の内容

{% include 'input' %}{% include 'diff' %} の部分を見てみます。それぞれのファイルの中身は次のとおりです。

_input.yml.liquid
in:
  type: file
  path_prefix: this_is_prefix_
  file_ext: csv
  parser:
    stop_on_invalid_record: true
    charset: UTF-8
    newline: LF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    skip_header_lines: 1
    columns:
    - {name: id, type: long}
    - {name: name, type: string}
    - {name: age, type: long}
    - {name: birth_day, type: timestamp, format: '%Y-%m-%d'}
_diff.yml.liquid

_diff.yml.liquid の中身を見てみます。このファイルは -c オプションによって生成されるものを想定しています

一行だけなので分かりづらいですが、冒頭に半角スペースが 2つ 空いています(インデントされています)。

  last_row: 12345

さて、_input.yml.liquid_diff.yml.liquid の二つのファイルがもし YAML に直書きされていたとすると、以下のようになります。_diff.yml.liquid がインデントされて(冒頭に半角スペースが 2つ 空けて)書かれていたことが、統合結果にそのまま反映されることがポイントです。

in:
  type: file
  path_prefix: this_is_prefix_
  file_ext: csv
  parser:
    stop_on_invalid_record: true
    charset: UTF-8
    newline: LF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    skip_header_lines: 1
    columns:
    - {name: id, type: long}
    - {name: name, type: string}
    - {name: age, type: long}
    - {name: birth_day, type: timestamp, format: '%Y-%m-%d'}
  last_row: 12345

{% include 'output' %} の内容と table: my_table の部分

{% include 'output' %} の中身は次のとおりです。

_output.yml.liquid
out:
  type: mysql
  host: 192.168.0.1
  port: 3306
  user: username
  password: password
  database: db_name
  mode: merge

「親ファイル」に直書きしている記述がある

「親ファイル」である parent.yml.liquid には、{% include 'output' %} の記述の下に、インデントをした上で table: my_table という直書きした記述があります。

この場合は直書きした内容がそのまま反映されます。繰り返しますが、インデントに注意して下さい。{% include 'output' %} の include と、table: my_table の直書きとを併せた記述は以下の記述と同じになります。

out:
  type: mysql
  host: 192.168.0.1
  port: 3306
  user: username
  password: password
  database: db_name
  mode: merge
  table: my_table

全ての Liquid ファイルが include された内容

上記までの内容に従い、4つの Liquid ファイルを併せたファイルの内容は、以下の内容(YAMLファイル)になります。

in:
  type: file
  path_prefix: this_is_prefix_
  file_ext: csv
  parser:
    stop_on_invalid_record: true
    charset: UTF-8
    newline: LF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    skip_header_lines: 1
    columns:
    - {name: id, type: long}
    - {name: name, type: string}
    - {name: age, type: long}
    - {name: birth_day, type: timestamp, format: '%Y-%m-%d'}
  last_row: 12345

out:
  type: mysql
  host: 192.168.0.1
  port: 3306
  user: username
  password: password
  database: db_name
  mode: merge
  table: my_table

Liquid をうまく使って DRY に設定ファイルを書く

これで Liquid を用いて Embulk の設定ファイルを書けるようになりました。Liquid ファイルの内容を任意の場所に「挟み込める」ようになったわけです。

Embulk を本格的に使い始めると、同じ記述や似たような記述が各所で発生すると思います。その際は Liquid をうまく使って DRY なコード構成にしたいですね。

*1:という表現は正確ではないと思いますが

*2:はず。これが一番悩んだところ

*3:はず。これもハマった

*4:「子ファイル」のファイル名

*5:.yml.liqud

*6:重要です

*7:<% include 'foooo' %>

*8:後述の具体例で挙げる "_diff.yml.liquid" のケース

Powered by はてなブログ