この記事は、Notion AIに対して
- 問題と解決策の概要
- 例示用のコード
を渡して生成した実験的な記事になります。
TL;DR
- YAMLファイルを読み込む際にエイリアスを利用すると同じオブジェクトが参照されるため、YAMLファイルを作成するとエイリアスが展開されないことがある
- 一度JSON文字列にしてから再度Hash化することで別オブジェクトとしてオブジェクトが作成されるため、エイリアスを展開したYAMLファイルを作成できる
背景
YAMLは、人間が読み書きしやすいマークアップ言語の一つであり、設定ファイルなどに利用されることが多いです。 エイリアスとは、同一のオブジェクトを複数の場所で参照するための機能です。 設定ファイルで共通する設定がある場合、エイリアスを使うことで重複を避けることができます。
RubyでYAMLファイルを読み込んで再度YAMLとして書き込む場合、同じオブジェクトが参照されるため、エイリアスが展開されないことがあります。 以下は、その問題が発生するコードの例です。
require 'yaml' content = <<~YAML aliases: - &auth auth: username: test password: test staging: <<: *auth production: <<: *auth YAML config = YAML.safe_load content, aliases: true File.write 'config.yaml', YAML.dump(config)
同じオブジェクトが参照されるため、エイリアスが展開されていません。 以下は、その出力結果の例です。
# config.yaml --- aliases: - auth: &1 username: test password: test staging: *1 production: *1
エイリアスが展開されていないことがわかります。 オブジェクトIDをコードで確認してみると、どれも同じIDが返ってくることがわかります。
puts "aliases.auth: #{config['aliases'][0]['auth'].object_id}" puts "staging.auth: #{config['staging']['auth'].object_id}" puts "production.auth: #{config['production']['auth'].object_id}" # => aliases.auth: 2378771560 # => staging.auth: 2378771560 # => production.auth: 2378771560
解決方法
この問題を解決するためには、Hashを一度JSON文字列にし、JSON.parseで再度Hash化したものを、YAML.dumpすることで、エイリアスを展開したYAMLファイルを作成することができます。
以下は、その方法を示した例です。
require 'yaml' require 'json' content = <<~YAML aliases: - &auth auth: username: test password: test staging: <<: *auth production: <<: *auth YAML yaml_config = YAML.safe_load content, aliases: true config = JSON.parse yaml_config.to_json File.write 'expand_config.yaml', YAML.dump(config)
以下は、その出力結果の例です。
# expand_config.yaml --- aliases: - auth: username: test password: test production: auth: username: test password: test staging: auth: username: test password: test
この方法により、同じオブジェクトが参照される問題を回避することができます。