From: robb+ruby@... Date: 2020-02-17T01:30:31+00:00 Subject: [ruby-core:97176] [Ruby master Feature#15563] #dig that throws an exception if an key doesn't exist Issue #15563 has been updated by robb (Robb Shecter). matz (Yukihiro Matsumoto) wrote in #note-4: > And with whatever name, we need the real-world use-case for a new method. Here is another real-world use-case, from my public.law apps which parses JSON: ``` def insert_subparts(for_id:, with_map:) sub_documents = JSON.parse(File.read("#{for_id}.json")).fetch('result').fetch('documents').fetch('documents').fetch('items') insert_sub_documents from_tree: sub_documents, under_parent: with_map.fetch(for_id) end ``` I'm sure you can see why I've created syntactic/semantic sugar for all these `#fetch` invocations. ---------------------------------------- Feature #15563: #dig that throws an exception if an key doesn't exist https://bugs.ruby-lang.org/issues/15563#change-84282 * Author: 3limin4t0r (Johan Wentholt) * Status: Open * Priority: Normal ---------------------------------------- Ruby 2.3.0 introduced `#dig` for *Array*, *Hash* and *Struct*. Both *Array* and *Hash* have `#fetch` which does the same as `#[]`, but instead of returning the default value an exception is raised (unless a second argument or block is given). *Hash* also has `#fetch_values` which does the same as `#values_at`, raising an exception if an key is missing. For `#dig` there is no such option. My proposal is to add a method which does the same as `#dig`, but instead of using the `#[]` accessor it uses `#fetch`. This method would look something like this: ```Ruby module Traversable def traverse(key, *others) value = fetch(key) return value if others.empty? if value.respond_to?(__method__, true) value.send(__method__, *others) else raise TypeError, "#{value.class} does not have ##{__method__} method" end end end Array.include(Traversable) Hash.include(Traversable) ``` The exception raised is taken from `#dig` (`[1].dig(0, 1) #=> TypeError: Integer does not have #dig method`). ```Ruby yaml = YAML.load_file('some_file.yml') # this change is meant to make chaining #fetch calls more easy yaml.fetch('foo').fetch('bar').fetch('baz') # would be replaced with yaml.traverse('foo', 'bar', 'baz') ``` I'm curious to hear what you guys think about the idea as a whole and the method name. -- https://bugs.ruby-lang.org/ Unsubscribe: