Issue #11762 has been updated by Colin Kelley.

File 11762.patch added

Here is my suggested documentation on how `Hash#dig` should behave as part of a general `dig` protocol.  The patch includes equivalent changes to the documentation for `Array#dig`.

~~~
 * Extracts a nested value by navigating the given +key+
 * (and keys, recursively).  This is useful for navigating
 * parsed JSON or other nested data.  Nested data may be any
 * object that implements the +dig+ method.
 *
 * Calls the +[]+ operator to look up the key so that
 * subclasses may provide their own implementation.
 *
 * Returns the nested value, or nil if a key is not found
 * at any level, or if a nested key navigates to an object that
 * does not implement +dig+.  Does not raise exceptions.
 *
 *  == The dig Protocol
 *
 * The +dig+ method behaves like this at each level:
 *
 *    def dig(key, *keys)
 *      value = self[key] rescue nil
 *      if keys.empty? || value.nil?
 *        value
 *      elsif value.respond_to?(:dig)
 *        value.dig(*keys)
 *      else
 *        nil
 *      end
 *    end
 *
 *  == Example Usage
 *
 *    Address = Struct.new(:street, :city, :state, :country)
 *
 *    hash = {ceo: {name: "Pat", email: "pat / example.com"},
 *            managers: [
 *                {name: "Jose", email: "jose / example.com"},
 *                {name: "Sally", email: "sally / example.com"}
 *                {name: "Bob", email: "bob / example.com"}
 *            ],
 *            office: Address.new("9 Oak St", "New York", "NY", "USA")
 *           }
 *
 *    hash.dig(:ceo, :name)           #=> "Pat"
 *    hash.dig(:ceo, 0, :email)       #=> nil
 *    hash.dig(:managers, 1, :name)   #=> "Sally"
 *    hash.dig(:managers, :name)      #=> nil
 *    hash.dig(:office, :city)        #=> "New York"
~~~

This example is designed to call attention to the common case where you intended to access a hash but an array was there:

~~~
 *    hash.dig(:managers, :name)      #=> nil
~~~

I feel the `dig` method would be much less useful if a surprise as shown above were to raise an exception. (That would force a rescue wrapper. Furthermore, note that the exception would be of limited value since it would be ambiguous as to what level it occurred at.)

----------------------------------------
Bug #11762: Array#dig can raise TypeError: no implicit conversion of Symbol/String into Integer
https://bugs.ruby-lang.org/issues/11762#change-55340

* Author: Colin Kelley
* Status: Open
* Priority: Normal
* Assignee: Yukihiro Matsumoto
* ruby -v: 2.3.0-preview1
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
If you try to `dig` in an Array using a symbol or string, a `TypeError` exception will be raised:

irb> ['zero', 'one', 'two'].dig(:first)
TypeError: no implicit conversion of Symbol into Integer
    from (irb):1:in `dig'
    from (irb):1

I think it should return `nil` in this case.  The most typical use case for `dig` is to dig through parsed JSON and either find the result we expected or else `nil`.  Wouldn't it defeat the purpose of `dig` if we had to wrap calls to it in a `rescue` to handle the case that an Array was present where we expected a Hash?

Can we clarify the desired behavior for this case, then update the documentation and tests to reflect that?

---Files--------------------------------
11762.patch (3.19 KB)


-- 
https://bugs.ruby-lang.org/