diff --git a/lib/rackstash/fields/hash.rb b/lib/rackstash/fields/hash.rb index 4084941..bdb8d6f 100644 --- a/lib/rackstash/fields/hash.rb +++ b/lib/rackstash/fields/hash.rb @@ -230,6 +230,34 @@ module Rackstash @raw.empty? end + # Returns a value from the hash for the given `key`. If the key can't be + # found, there are several options: With no other arguments, it will raise + # a `KeyError` exception; if `default` is given, then that value will be + # returned; if the optional code block is specified, then it will be + # called and its result returned. + # + # Note that neither `default` nor the block's return value are normalized + # before being returned. + # + # @param key [#to_s] the key name. We will always use it as a + # frozen UTF-8 String. + # @param default [Object] a value to return if there is no value at `key` + # in the hash + # @yield [key] if no value was set at `key`, no `default` value was given + # and a block was given, we call the block and return its value + # @yieldparam key [String] the hash key + # @return [Object] the current value of the field if present. If the key + # was not found, we return the `default` value or the value of the given + # block. + def fetch(key, default = UNDEFINED, &block) + key = utf8_encode(key) + if UNDEFINED.equal? default + @raw.fetch(key, &block) + else + @raw.fetch(key, default) + end + end + # @param key [String] The name of a key to check. This MUST be a correctly # encoded String in order to return valid results # @return [Boolean] `true` if the key is forbidden from being added diff --git a/spec/rackstash/fields/hash_spec.rb b/spec/rackstash/fields/hash_spec.rb index 526a8ec..fe01441 100644 --- a/spec/rackstash/fields/hash_spec.rb +++ b/spec/rackstash/fields/hash_spec.rb @@ -393,6 +393,45 @@ describe Rackstash::Fields::Hash do end end + describe '#fetch' do + it 'fetches an existing value' do + hash['key'] = 'value' + hash['nil'] = nil + + expect(hash.fetch('key')).to eql 'value' + expect(hash.fetch('nil')).to be_nil + end + + it 'normalizes keys' do + hash['42'] = 'value' + + expect(hash['42']).to eql 'value' + expect(hash[:'42']).to eql 'value' + expect(hash[42]).to eql 'value' + end + + it 'raises if the key does not exist' do + expect { hash.fetch('missing') }.to raise_error KeyError + end + + it 'returns the default value for a missing key' do + hash['key'] = 'value' + + expect(hash.fetch('key', :default)).to eql 'value' + expect(hash.fetch('missing', :default)).to eql :default + end + + it 'returns the block value for a missing key' do + hash['key'] = 'value' + called_with = [] + + expect(hash.fetch('key') { |key| called_with << key; :default }).to eql 'value' + expect(hash.fetch('missing') { |key| called_with << key; :default }).to eql :default + + expect(called_with).to eql ['missing'] + end + end + describe '#forbidden_key?' do let(:forbidden_keys) { ['forbidden', :foo] }