Generating nested OpenStructs from JSON
If you’ve parsed JSON with Ruby, you’re undoubtedly familiar with the following code:
data = JSON.parse(File.read('path/to/my.json'))
This does exactly what you expect it to do. It reads the contents of path/to/my.json
as text, and parses that JSON data into a Ruby Hash, which is fine for many use cases. However, you may be drawn to OpenStruct as an alternative (for any number of reasons).
Lets try it out. OpenStruct’s initializer accepts a Hash, so we should simply be able to pass in data
.
require 'ostruct'
data = JSON.parse(File.read('path/to/my.json'))
struct = OpenStruct.new(data)
This will work just fine… if you don’t have nested objects. Consider the following JSON:
{
"name": "John Smith",
"age": 50,
"education": {
"school": "Stanford University",
"degree": "BS in Computer Science"
}
}
Running that through our previous code, we’d get an OpenStruct with the name
, age
, and education
keys set. name
would be a String, age
would be a FixNum, but education
? Well, we’d expect it to be an OpenStruct. But unfortunately, its a Hash. The OpenStruct initializer does not recursively convert nested Hashes to nested OpenStruct objects.
So, how do we get what we want? Enter object_class
. We can get the desired effect in less lines of code with the following:
require 'ostruct'
data = JSON.parse(File.read('path/to/my.json'), object_class: OpenStruct)
The object_class
option to JSON#parse
specifies the dictionary-like class to use as the Ruby representation of a JSON object. In this example I used OpenStruct
, but it can be a plain old Struct
, or even an ActiveSupport::HashWithIndifferentAccess
. You can also specify an array_class
, which is an Enumerable
like class that JSON
will use as the Ruby representation of a JSON array.