From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-2.8 required=3.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, FORGED_GMAIL_RCVD,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, SPF_PASS shortcircuit=no autolearn=no autolearn_force=no version=3.4.2 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id 7DF7B20248 for ; Tue, 12 Mar 2019 21:56:10 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 87466120FCB; Wed, 13 Mar 2019 06:56:06 +0900 (JST) Received: from o1678916x28.outbound-mail.sendgrid.net (o1678916x28.outbound-mail.sendgrid.net [167.89.16.28]) by neon.ruby-lang.org (Postfix) with ESMTPS id 0A429120FF1 for ; Wed, 13 Mar 2019 06:56:02 +0900 (JST) Received: by filter0139p3las1.sendgrid.net with SMTP id filter0139p3las1-27757-5C882AF2-1D 2019-03-12 21:56:02.519730663 +0000 UTC m=+80678.853732324 Received: from herokuapp.com (unknown [54.196.67.112]) by ismtpd0046p1mdw1.sendgrid.net (SG) with ESMTP id cGPnMdeHQySCh8Dw4uM2jQ for ; Tue, 12 Mar 2019 21:56:02.292 +0000 (UTC) Date: Tue, 12 Mar 2019 21:56:02 +0000 (UTC) From: walerian.sobczak@gmail.com Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 67246 X-Redmine-Project: ruby-trunk X-Redmine-Issue-Id: 15563 X-Redmine-Issue-Author: 3limin4t0r X-Redmine-Sender: walerian X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-SG-EID: =?us-ascii?Q?IQK5kgMqp9RwrIpJu62gtJm+JhiTSdnCivr13epEwiWlJdlaGoagye2aRksrs=2F?= =?us-ascii?Q?Q+Uz0DueQPkFmp5gLrETD9aYoy2Mp0T2dQqgN5h?= =?us-ascii?Q?+PqbxVWISwcvV2b+6+zFRhoCGyPUvcRSfQ4pEOk?= =?us-ascii?Q?h34c7qnYqKaQmE84vERbvtwV9GGlp1OAEj7hZuM?= =?us-ascii?Q?liEa4B6M1UwzwgBrrfZ5AO9VakTMT6u238g=3D=3D?= To: ruby-core@ruby-lang.org X-ML-Name: ruby-core X-Mail-Count: 91795 Subject: [ruby-core:91795] [Ruby trunk Feature#15563] #dig that throws an exception if an key doesn't exist X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" Issue #15563 has been updated by walerian (Walerian Sobczak). I would suggest `#retrieve`. It's just a **stronger** `#fetch`, and the dictionary definition reflects its meaning: > retrieve (verb) > 1. get or bring (something) back from somewhere > 2. find or extract The name is still short and simple, but also idiomatic and meaningful at the same time. ``` ruby config = YAML.load_file('config.yml') # so instead of this: config.fetch('production').fetch('environment').fetch('SECRET_KEY_BASE') # we would have: config.retrieve('production', 'environment', 'SECRET_KEY_BASE') ``` ---------------------------------------- Feature #15563: #dig that throws an exception if an key doesn't exist https://bugs.ruby-lang.org/issues/15563#change-77069 * Author: 3limin4t0r (Johan Wentholt) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- 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 DigWithException def dig_e(key, *others) value = fetch(key) return value if value.nil? || 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(DigWithException) Hash.include(DigWithException) ``` The exception raised is also taken from `#dig` (`[1].dig(0, 1) #=> TypeError: Integer does not have #dig method`). I personally have my issues with the name `#dig_e`, but I haven't found a better name yet. There are also a few other things that I haven't thought out yet. 1. Should this method be able to accept a block which, will be passed to the `#fetch` call and recursive `#dig_e` calls? ```Ruby module DigWithException def dig_e(key, *others, &block) value = fetch(key, &block) return value if value.nil? || others.empty? if value.respond_to?(__method__, true) value.send(__method__, *others, &block) else raise TypeError, "#{value.class} does not have ##{__method__} method" end end end Array.include(DigWithException) Hash.include(DigWithException) ``` 2. I currently kept the code compatible with the `#dig` description. > Extracts the nested value specified by the sequence of *key* objects by calling `dig` at each step, returning `nil` if any intermediate step is `nil`. However, with this new version of the method one could consider dropping the *"returning `nil` if any intermediate step is `nil`"* part, since this would be the more strict version. ```Ruby module DigWithException def dig_e(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(DigWithException) Hash.include(DigWithException) ``` I'm curious to hear what you guys think about the idea as a whole, the method name and the two points described above. -- https://bugs.ruby-lang.org/