I am new to Ruby and have been stuck at this for a while now. I am getting a JSON responses as mentioned below and aim to search for the substring where the value of its substring is something as specified by me.
For example, I am getting the response below:
{
"00:00:00:CC:00:CC": {
"family": "lladdr"
},
"10.0.0.20": {
"family": "inet",
"prefixlen": "24",
"netmask": "255.255.255.0",
"broadcast": "10.0.0.255",
"scope": "Global"
},
"ff00::f00:00ff:fff0:00f0": {
"family": "inet6",
"prefixlen": "64",
"scope": "Link",
"tags": []
}
}
I need to get the value of the parent where the key family
has a value equal to inet
. In this case, I just want 10.0.0.20
as output when family equals inet.
I went through multiple questions here, and Google did not help. I understand that I will need to parse the JSON using JSON.parse
, and then use maybe find or select to get my answer, but I was not able to get it working.
I am not sure if there is any other way I can do this like you would do in Bash using grep or awk. One hack might be to use something like foo.[46..54]
which will output the IP, but again I believe that would be a bad way of solving this.
Assuming that your Hash is already stored in response using JSON#parse, one way to solve the problem is to invert the Hash with the Hash#invert method. For example:
# Return an Array of IPv4, then pop the last/only String value.
response.invert.select { |h| h.values.include? 'inet' }.values.pop
#=> "10.0.0.20"
This is quick and simple, and it works with your provided data. However, there are some minor caveats.
Assumes there is only one IPv4 address in the response Hash. If you have more than one key with inet
as a value, don't use pop
and deal with the resulting Array as you see fit. For example:
response.invert.select { |h| h.values.include? 'inet' }.values
#=> ["10.0.0.20"]
It assumes the key for each top-level JSON object is an IP address. We're not really validating anything.
It works for the JSON you have, but isn't solving for arbitrarily nested or varied data structures. If you have different kinds of inputs, consider it "some assembly required."
If you have no inet
family, then {}.values.pop
may return nil. Make sure you plan for that in your application.
None of these are show-stoppers for your particular use case, but they are certainly worth keeping in mind. Your mileage may vary.