diff --git a/array.c b/array.c index 159dc8f..22b53f6 100644 --- a/array.c +++ b/array.c @@ -5533,15 +5533,25 @@ rb_ary_any_p(VALUE ary) /* * call-seq: - * ary.dig(idx, ...) -> object + * ary.dig(index, indexes...) -> object * - * Extracts the nested array value specified by the sequence of idx - * objects. + * Extracts a nested value by navigating the given +index+ + * (and indexes, recursively). This is useful for navigating + * parsed JSON or other nested data. Nested data may be any + * object that implements the +dig+ method. * - * a = [[1, [2, 3]]] + * Returns the nested value, or nil if an index/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. * - * a.dig(0, 1, 1) #=> 3 - * a.dig(0, 0, 0) #=> nil + * ary = [[:A, [:B, {first: "Pat", last: "Jones"}]] + * + * ary.dig(0, 1, 0) #=> :B + * ary.dig(0, 0, 0) #=> nil + * ary.dig(0, 1, :first) #=> nil + * ary.dig(0, 1, 1, :first) #=> "Pat" + * + * See Hash#dig for more information. */ VALUE diff --git a/hash.c b/hash.c index 717a548..9d82b2c 100644 --- a/hash.c +++ b/hash.c @@ -2693,15 +2693,53 @@ rb_hash_any_p(VALUE hash) /* * call-seq: - * hsh.dig(key, ...) -> object + * hsh.dig(key, keys...) -> object * - * Extracts the nested hash value specified by the sequence of key - * objects. + * 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. * - * h = { foo: {bar: {baz: 1}}} + * Calls the +[]+ operator to look up the key so that + * subclasses may provide their own implementation. * - * h.dig(:foo, :bar, :baz) #=> 1 - * h.dig(:foo, :zot) #=> nil + * 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" */ VALUE