diff --git a/lib/rackstash/fields/hash.rb b/lib/rackstash/fields/hash.rb index de469e1..8ae21c1 100644 --- a/lib/rackstash/fields/hash.rb +++ b/lib/rackstash/fields/hash.rb @@ -451,6 +451,10 @@ module Rackstash # # @param key [#to_s] the field name. When setting the field, this name # will be normalized as a frozen UTF-8 string. + # @param force [Boolean] if `true`, we overwrite existing values for + # conflicting keys but raise an `ArgumentError` when trying to set a + # forbidden key. If `false`, we silently ignore values for existing or + # forbidden keys. # # @yield [key] if the key doesn't exist yet, we call the block and use its # return value as the value to insert at `key` @@ -462,11 +466,15 @@ module Rackstash # @return [Object, nil] The return value of the block or `nil` if no # insertion happened. Note that `nil` is also a valid value to insert # into the hash. - def set(key) + def set(key, force: true) key = utf8_encode(key) - return if forbidden_key?(key) - return unless @raw[key].nil? + if force + raise ArgumentError, "Forbidden field #{key}" if forbidden_key?(key) + else + return if forbidden_key?(key) + return unless @raw[key].nil? + end @raw[key] = normalize(yield(key)) end diff --git a/spec/rackstash/fields/hash_spec.rb b/spec/rackstash/fields/hash_spec.rb index 0369da7..0dd08ce 100644 --- a/spec/rackstash/fields/hash_spec.rb +++ b/spec/rackstash/fields/hash_spec.rb @@ -92,10 +92,10 @@ describe Rackstash::Fields::Hash do expect(hash['key']).to eql 'value' end - context 'with forbidden fields' do + context 'with forbidden_keys' do let(:forbidden_keys) { ['forbidden', :foo, 42] } - it 'denies setting a forbidden field' do + it 'denies setting a forbidden key' do expect { hash[:forbidden] = 'value' }.to raise_error ArgumentError expect { hash['forbidden'] = 'value' }.to raise_error ArgumentError @@ -106,7 +106,7 @@ describe Rackstash::Fields::Hash do expect { hash[:'42'] = 'value' }.to raise_error ArgumentError end - it 'returns nil when accessing forbidden fields' do + it 'returns nil when accessing forbidden keys' do expect(hash['forbidden']).to be_nil expect(hash[:foo]).to be_nil @@ -683,27 +683,50 @@ describe Rackstash::Fields::Hash do expect(hash['symbol']).to eql 'value' end - it 'ignores forbidden keys' do - forbidden_keys << 'forbidden' + context 'with force: false' do + it 'ignores forbidden keys' do + forbidden_keys << 'forbidden' - expect { |b| hash.set(:forbidden, &b) }.not_to yield_control - expect { |b| hash.set('forbidden', &b) }.not_to yield_control + expect { |b| hash.set(:forbidden, force: false, &b) }.not_to yield_control + expect { |b| hash.set('forbidden', force: false, &b) }.not_to yield_control - expect(hash['forbidden']).to be_nil + expect(hash['forbidden']).to be_nil + end + + it 'ignores existing keys' do + hash['key'] = 'value' + + expect { |b| hash.set(:key, force: false, &b) }.not_to yield_control + expect { |b| hash.set('key', force: false, &b) }.not_to yield_control + + expect(hash['key']).to eql 'value' + end + + it 'overwrites nil value' do + hash['nil'] = nil + expect { |b| hash.set('nil', force: false, &b) }.to yield_control + end end - it 'ignores existing keys' do - hash['key'] = 'value' + context 'with force: true' do + it 'denies setting a forbidden key' do + forbidden_keys << 'forbidden' - expect { |b| hash.set(:key, &b) }.not_to yield_control - expect { |b| hash.set('key', &b) }.not_to yield_control + expect { hash.set(:forbidden, force: true) { 'value' } }.to raise_error ArgumentError + expect { hash.set('forbidden', force: true) { 'value' } }.to raise_error ArgumentError - expect(hash['key']).to eql 'value' - end + expect(hash['forbidden']).to be_nil + end - it 'overwrites nil value' do - hash['nil'] = nil - expect { |b| hash.set('nil', &b) }.to yield_control + it 'overwrites existing keys' do + hash['key'] = 'value' + + expect(hash.set(:key, force: true) { 'new_symbol' }).to eql 'new_symbol' + expect(hash['key']).to eql 'new_symbol' + + expect(hash.set('key', force: true) { 'new_string' }).to eql 'new_string' + expect(hash['key']).to eql 'new_string' + end end end