Skip to content

Instantly share code, notes, and snippets.

@mrk21
Last active March 9, 2024 10:49
Show Gist options
  • Save mrk21/3c6f29aa91659dcaf45eefba11f866a3 to your computer and use it in GitHub Desktop.
Save mrk21/3c6f29aa91659dcaf45eefba11f866a3 to your computer and use it in GitHub Desktop.
Define a method liked `ENV.fetch()` which returns specified default value even when a value of specified key was empty string. see: https://mrk21.hatenablog.com/entry/2024/03/09/190844
class << ENV
# This method behavior is almost same as `ENV.fetch()`, but it returns default value even when the value was empty string.
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
require_relative './env'
RSpec.describe ENV do
before do
described_class['__DUMMY_FOR_TEST1'] = '1'
described_class['__DUMMY_FOR_TEST3'] = ''
end
after do
described_class.delete('__DUMMY_FOR_TEST1')
described_class.delete('__DUMMY_FOR_TEST3')
end
describe '.fetch2(key, default, &block)' do
context 'existed `key`' do
let(:key) { '__DUMMY_FOR_TEST1' }
context 'did not specify neither `default` nor `block`' do
it 'returns value of `key`' do
expect(described_class.fetch2(key)).to eq '1'
end
end
context 'specified `default`' do
it 'returns value of `key`' do
expect(described_class.fetch2(key, '2')).to eq '1'
end
end
context 'specified `block`' do
it 'returns value of `key`' do
expect(described_class.fetch2(key) { '3' }).to eq '1'
described_class.fetch2(key) { |k| expect(k).to eq key }
end
end
context 'specified `default` with `block`' do
it 'outputs warn, and it returns value of `key`' do
expect do
expect(described_class.fetch2(key, '2') { '3' }).to eq '1'
end.to output(%r{env.rb:\d+: warning: block supersedes default value argument\n}).to_stderr
described_class.fetch2(key, '2') { |k| expect(k).to eq key }
end
end
end
context 'did not exist `key`' do
let(:key) { '__DUMMY_FOR_TEST2' }
context 'did not specify neither `default` nor `block`' do
it 'raises exception' do
expect { described_class.fetch2(key) }.to raise_error(KeyError, 'key not found: "%s"' % key)
end
end
context 'specified `default`' do
it 'returns `default`' do
expect(described_class.fetch2(key, '2')).to eq '2'
end
end
context 'specified `block`' do
it 'returns return value of `block`' do
expect(described_class.fetch2(key) { '3' }).to eq '3'
described_class.fetch2(key) { |k| expect(k).to eq key }
end
end
context 'specified `default` with `block`' do
it 'outputs warn, and it returns return value of `block`' do
expect do
expect(described_class.fetch2(key, '2') { '3' }).to eq '3'
end.to output(%r{env.rb:\d+: warning: block supersedes default value argument\n}).to_stderr
described_class.fetch2(key, '2') { |k| expect(k).to eq key }
end
end
end
context 'existed `key`, but the value was empty string' do
let(:key) { '__DUMMY_FOR_TEST3' }
context 'did not specify neither `default` nor `block`' do
it 'raises exception' do
expect { described_class.fetch2(key) }.to raise_error(KeyError, 'key not found: "%s"' % key)
end
end
context 'specified `default`' do
it 'returns `default`' do
expect(described_class.fetch2(key, '2')).to eq '2'
end
end
context 'specified `block`' do
it 'returns return value of `block`' do
expect(described_class.fetch2(key) { '3' }).to eq '3'
described_class.fetch2(key) { |k| expect(k).to eq key }
end
end
context 'specified `default` with `block`' do
it 'outputs warn, and it returns return value of `block`' do
expect do
expect(described_class.fetch2(key, '2') { '3' }).to eq '3'
end.to output(%r{env.rb:\d+: warning: block supersedes default value argument\n}).to_stderr
described_class.fetch2(key, '2') { |k| expect(k).to eq key }
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment