Search code examples
rubyhashhash-of-hashes

What is the most ruby-ish way of accessing nested hash values at arbitrary depths?


Given a hash such as:

AppConfig = {
  'service' => {
    'key' => 'abcdefg',
    'secret' => 'secret_abcdefg'
  },
  'other' => {
    'service' => {
      'key' => 'cred_abcdefg',
      'secret' => 'cred_secret_abcdefg'
    }
  }
}

I need a function to return service/key in some cases and other/service/key in other cases. A straightforward way is to pass in the hash and an array of keys, like so:

def val_for(hash, array_of_key_names)
  h = hash
  array_of_key_names.each { |k| h = h[k] }
  h
end

So that this call results in 'cred_secret_abcdefg':

val_for(AppConfig, %w[other service secret])

It seems like there should be a better way than what I've written in val_for().


Solution

  • def val_for(hash, keys)
      keys.reduce(hash) { |h, key| h[key] }
    end
    

    This will raise an exception if some intermediate key is not found. Note also that this is completely equivalent to keys.reduce(hash, :[]), but this may very well confuse some readers, I'd use the block.