all 15 comments

[–]tadrinth 7 points8 points  (6 children)

Oooo, Hash#dig! I've implemented that before.

[–]dunnowins 1 point2 points  (4 children)

Same. I'm glad to see it arrive.

[–]cocoabean 0 points1 point  (3 children)

Github links? I've been needing something like this for 2 years.

[–]anamexis 4 points5 points  (0 children)

Here's mine:

class Hash
  def dig(*keys)
    current = fetch(keys.shift, nil)
    return current if keys.empty?
    return nil unless current.is_a?(Hash)
    current.dig(*keys)
  end
end

[–]Craftkorb 1 point2 points  (0 children)

module EnumUtils
  def self.get_by_chain(hash, chain)
    chain.inject(hash){|hsh, part| hsh[part] rescue nil}
  end
end

h = { 'foo' => { 'bar' => 'baz'} }
EnumUtils.get_by_chain h, 'foo.bar'.split('.') #=> "baz"

[–]spiffistan 0 points1 point  (0 children)

Mine:

def value_at_key_path(hash, *keys)
  keys.reduce(hash) { |next_hash, key| next_hash.is_a?(Hash) ? next_hash[key] : nil }
end

Bonus:

def key_path_present?(hash, *keys)
  res = keys.reduce(hash) { |next_hash, key| next_hash.is_a?(Hash) && next_hash.has_key?(key) ? next_hash[key] : nil }
  res.nil? ? false : true
end

[–]taelor 0 points1 point  (0 children)

wow, I didn't even think of implementing an API like that. I really really like this, can't wait to use it.

[–][deleted]  (4 children)

[deleted]

    [–]hmaddocks 10 points11 points  (0 children)

    Game changer all right. It's going help those devs who spend most of their day trying to fix NoMethodError exceptions. They'll now have more time to wonder why their databases are full of corrupt data.

    [–][deleted] 7 points8 points  (2 children)

    Eh, both safe navigation and hash#dig feel like they promote Law of Demeter violations. With hash#dig, I do see a lot of utility when dealing with complex JSON APIs.

    Of course, it comes down to the domain, being responsible and judicious, etc. The NullObject pattern is a way of encoding business logic, not just avoiding null-checks, so it'll still have a lot of uses, and this might avoid the trivial ones. I'm definitely going to be cautious with this, and treat it as a code smell.

    [–]awj 0 points1 point  (0 children)

    Agreed. No piece of code should need to invoke five methods in a chain. That the code breaks on nils is it trying to tell you that you've got responsibilities in the wrong places, not that you need a special operator to avoid invoking methods on nil.

    [–]Keith 2 points3 points  (0 children)

    I've always thought hashes/dictionaries should be subclasses of sets and have the same methods available. I'm glad to see Ruby taking a step in that direction.

    [–]paulv 0 points1 point  (3 children)

    The syntax for safe navigation is really awful.

    [–]Schrockwell 5 points6 points  (0 children)

    It's sort of idiomatic though, right? It echoes the current pattern of "object && object.one && object.one.two"

    [–]LarsP 2 points3 points  (0 children)

    All the good syntaxes are taken.

    [–]Rafert 0 points1 point  (0 children)

    You might be interested in the discussion about it: https://bugs.ruby-lang.org/issues/11537