Hash#dig_and_collect feedback

Hello Rubyist, I am new here and looking forward to talk Ruby!

I wrote this gem a while ago to make my job of collecting data from deeply nested hashes easier (i.e. the kind of hashes you might get back from the savon gem for example because they represent some underlying XML)

Do you have any feedback on it?
https://github.com/mottalrd/hash_dig_and_collect

I wrote about the rationale here
http://www.alfredo.motta.name/making-ruby-hashdig-even-more-awesome-introducing-hashdig_and_collect/

Here is an example where I want the latitude of all the addresses of a given client.
Thank you for your help,
have a nice day

client_with_many_addresses = {
  details: {
    first_name: "Florentino",
    last_name: "Perez"
  },
  addresses: [
    {
      type: "home",
      postcode: "SE1 9SG",
      street: "London Bridge St",
      number: 32,
      city: "London",
      location: {
        latitude: 51.504382,
        longitude: -0.086279
      }
    },
    {
      type: "office",
      postcode: "SW1A 1AA",
      street: "Buckingham Palace Road",
      number: nil,
      city: "London",
      location: {
        latitude: 51.5013673,
        longitude: -0.1440787
      }
    }
  ]
}

client_with_many_addresses.dig_and_collect(:addresses, :location, :latitude)
#=> [51.504382, 51.5013673]

···

--
Alfredo Motta, Ph.D. Software Engineering
About me: https://www.alfredo.motta.name<https://www.alfredo.motta.name/>
Linkedin: https://linkedin.com/in/alfredomotta

Hello Rubyist, I am new here and looking forward to talk Ruby!

Welcome!

I wrote this gem a while ago to make my job of collecting data from deeply
nested hashes easier (i.e. the kind of hashes you might get back from the
savon gem for example because they represent some underlying XML)

Do you have any feedback on it?
GitHub - mottalrd/hash_dig_and_collect: Inspired by Hash#dig this repo contains an implementation of Hash#dig_and_collect, an utility method to navigate even more complex nested hashes without messing up your code.

Disclaimer: I only had a very brief look at this.

+ Seems like a useful feature
- although if it's XML data there is Nokogiri with XPath and CSS expressions
o I would consider to not stuff everything into an Array but pass it
on to a block (e.g. path as first argument, value as second). That way
it could work for really large structures; you can even keep the
current behavior as default (see below).
o I would probably expand the concept to a generic object traversal
(i.e. additionally for a regular object use method names as keys).

module HashDigAndCollect
  def dig_and_collect *keys, &block
    return .tap {|res| dig_and_collect {|path, item| res << item} }
if block.nil?
    ...
  end
end

Kind regards

robert

···

On Sat, Oct 21, 2017 at 9:33 AM, Alfredo Motta <motta.lrd@hotmail.it> wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

Hi Robert,

that's really useful feedback thank you!

I would consider to not stuff everything into an Array but pass it on to a block (e.g. path as first argument, value as second). That way it could work for really large structures

Not sure I get this, do you have an example of a gem that does something similar for me to look it up?

Thank you, have a nice day

Hello Rubyist, I am new here and looking forward to talk Ruby!

Welcome!

I wrote this gem a while ago to make my job of collecting data from deeply
nested hashes easier (i.e. the kind of hashes you might get back from the
savon gem for example because they represent some underlying XML)

Do you have any feedback on it?
GitHub - mottalrd/hash_dig_and_collect: Inspired by Hash#dig this repo contains an implementation of Hash#dig_and_collect, an utility method to navigate even more complex nested hashes without messing up your code.

Disclaimer: I only had a very brief look at this.

+ Seems like a useful feature
- although if it's XML data there is Nokogiri with XPath and CSS expressions
o I would consider to not stuff everything into an Array but pass it
on to a block (e.g. path as first argument, value as second). That way
it could work for really large structures; you can even keep the
current behavior as default (see below).
o I would probably expand the concept to a generic object traversal
(i.e. additionally for a regular object use method names as keys).

module HashDigAndCollect
  def dig_and_collect *keys, &block
    return .tap {|res| dig_and_collect {|path, item| res << item} }
if block.nil?
    ...
  end
end

Kind regards

robert

···

On 23 October 2017 at 12:17, Robert Klemme <shortcutter@googlemail.com<mailto:shortcutter@googlemail.com>> wrote:
On Sat, Oct 21, 2017 at 9:33 AM, Alfredo Motta <motta.lrd@hotmail.it<mailto:motta.lrd@hotmail.it>> wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org<mailto:ruby-talk-request@ruby-lang.org>?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk&gt;

--
Alfredo Motta, Ph.D. Software Engineering
About me: https://www.alfredo.motta.name<https://www.alfredo.motta.name/&gt;
Linkedin: https://linkedin.com/in/alfredomotta

You just simply pass on every object to a block instead of stuffing it
into a collection. Here is a very silly example just to illustrate the
point:

#!/usr/bin/ruby

class Object
  def traverse(path = , &block)
    return .tap {|res| traverse {|path, item| res << item} } if block.nil?

    block[path, self]
    nil
  end
end

module Enumerable
  def traverse(path = , &block)
    return .tap {|res| traverse {|path, item| res << item} } if block.nil?

    each {|item| item.traverse(path, &block)}
    nil
  end
end

class Hash
  def traverse(path = , &block)
    return .tap {|res| traverse {|path, item| res << item} } if block.nil?

    each_pair {|key, item| item.traverse(path + [key], &block)}
    nil
  end
end

{
  foo: 123,
  bar: %w{a b c},
  baz: {
    hello: "world"
  }
}.traverse do |path, item|
  printf "path=%p : %p\n", path, item
end

This is in no way properly coded as you can see from the redundancy.

Cheers

robert

···

On Tue, Oct 24, 2017 at 3:40 PM, Alfredo Motta <motta.lrd@hotmail.it> wrote:

I would consider to not stuff everything into an Array but pass it on to a
block (e.g. path as first argument, value as second). That way it could work
for really large structures

Not sure I get this, do you have an example of a gem that does something
similar for me to look it up?

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/