Rubyには、指定された環境変数の値を読み込み、存在しなければデフォルト値を返すENV.fetch()
というメソッドがある。Railsなどでは設定ファイルで環境変数から値を読み込むのによく使う。
config/database.yml:
default: &default pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
しかし、たとえば指定された環境変数が空文字列だったりすると、デフォルト値ではなく空文字列が返されてしまう。
HOGE='' ruby -e 'puts ENV.fetch("HOGE"){1}' #=>
これは direnv の .envrc
や Docker Compose の compose.yaml
で環境変数を指定していたりすると起きがちである。
.envrc:
export HOGE=
compose.yaml:
services: app: environment: HOGE: ${HOGE}
なので、空文字列の時もデフォルト値が参照されるようにENV
をモンキーパッチして、新たにENV.fetch2()
というENV.fetch()
とほぼ同様の動作をするメソッドを実装する。
lib/env.rb:
class << ENV # 基本的な動作は`ENV.fetch()`と同様だが、空文字列のときもデフォルト値を返すようにする def fetch2(*args, &block) key, default = args value = fetch(*args, &block) return value if value != '' raise KeyError, format('key not found: "%s"', key) if args.size == 1 && !block warn('block supersedes default value argument', uplevel: 1) if args.size == 2 && block block ? yield(key) : default end end
HOGE='' ruby -r ./lib/env.rb -e 'puts ENV.fetch2("HOGE"){1}' #=> 1
これで問題を解決できた。なお、空文字列の時はデフォルト値ではなく空文字列が返ってきてほしい時があるので、ENV.fetch()
をオーバーライドするのはやめた方がよい。
Gist: https://gist.github.com/mrk21/3c6f29aa91659dcaf45eefba11f866a3
環境
- Ruby: 3.2.2