Digging into Ruby Hashes with dig_set and dig_fetch

Hash#dig is fun, but sometimes I want to be strict … so I use dig_fetch … and dig_set to set a value without running into nil / MethodMissing errors.

# before
hash.dig(:a, :b, :c) # any of these could be nil ...
hash.fetch(:a).fetch(:b).fetch(:a) # repetitive and only shows last key

# after
hash.dig_fetch(:a, :b, :a)


  Hash.class_eval do
    def dig_fetch(*keys, last, &block)
      block ||= ->(*) { raise KeyError, "key not found: #{(keys << last).inspect}" }
      before = (keys.any? ? dig(*keys) || {} : self)
      before.fetch(last, &block)
    end

    def dig_set(keys, value)
      raise ArgumentError, "No key given" if keys.empty?
      keys = keys.dup
      last = keys.pop
      failed = ->(*) { raise KeyError, "key not found: #{(keys << last).inspect}" }
      nested = keys.inject(self) { |h, k| h.fetch(k, &failed) }
      nested[last] = value
    end
  end

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s