Kyle Brumm Kyle Brumm - 7 months ago 8
Ruby Question

How to use a string description to access data from a hash-within-hash structure?

I have the following:

data_spec['data'] = "some.awesome.values"

data_path = ""
data_spec['data'].split('.').each do |level|
data_path = "#{data_path}['#{level}']"
end

data = "site.data#{data_path}"


At this point,
data
equals a string:
"site.data['some']['awesome']['values']"


What I need help with is using the string to get the value of:
site.data['some']['awesome']['values']


site.data
has the following value:

{
"some" => {
"awesome" => {
"values" => [
{
"things" => "Stuff",
"stuff" => "Things",
},
{
"more_things" => "More Stuff",
"more_stuff" => "More Things",
}
]
}
}
}


Any help is greatly appreciated. Thanks!

Answer

You could do as tadman suggested and use site.data.dig('some', 'awesome', values') if you are using ruby 2.3.0 (which is awesome and I didn't even know existed). This is probably your best choice. But if you really want to write the code yourself read below.

You were on the right track, the best way to do this is:

data_spec['data'] = "some.awesome.values"

data = nil
data_spec['data'].split('.').each do |level|
  if data.nil?
    data = site.data[level]
  else
    data = data[level]
  end
end

To understand why this works first you need to understand that site.data['some']['awesome']['values'] is the same as saying: first get some then inside that get awesome then inside that get values. So our first step is retrieving the some. Since we don't have that first level yet we get it from site.data and save it to a variable data. Once we have that we just get each level after that from data and save it to data, allowing us to get deeper and deeper into the hash.

So using your example data would initally look like this:

        {"awesome" => {  
            "values" => [  
                {  
                    "things" => "Stuff",
                    "stuff" => "Things",
                },
                {  
                    "more_things" => "More Stuff",
                    "more_stuff" => "More Things",
                }
            ]
        }
    }

Then this:

        {"values" => [  
            {  
                "things" => "Stuff",
                "stuff" => "Things",
            },
            {  
                "more_things" => "More Stuff",
                "more_stuff" => "More Things",
            }
        ]
    }

and finally output like this:

        [  
            {  
                "things" => "Stuff",
                "stuff" => "Things",
            },
            {  
                "more_things" => "More Stuff",
                "more_stuff" => "More Things",
            }
        ]
Comments