anquegi
anquegi

Reputation: 11532

Convert nested struct to JSON

I find the answer for the reverse but not for the way nested struct to JSON

Suppose that I have this ruby structs

Attributes = Struct.new :name, :preferredLanguage, :telephoneNumber, :timeZone
User = Struct.new :email, :service, :preferredLanguage, :attributes

I create the struct for Attributes

attributes = Attributes.new "Pedro", "es", "5555555", "Madrid"
 # => #<struct Attributes name="Pedro", preferredLanguage="es", telephoneNumber="5555555", timeZone="Madrid"> 
attributes.to_h.to_json
 # => "{\"name\":\"Pedro\",\"preferredLanguage\":\"es\",\"telephoneNumber\":\"5555555\",\"timeZone\":\"Madrid\"}" 
Oj.dump attributes
 # => "{\"^u\":[\"Attributes\",\"Pedro\",\"es\",\"5555555\",\"Madrid\"]}" 
Oj.dump attributes, mode: :compat
 # => "\"#<struct Attributes name=\\\"Pedro\\\", preferredLanguage=\\\"es\\\", telephoneNumber=\\\"5555555\\\", timeZone=\\\"Madrid\\\">\"" 

So it works well, except when I use the gem Oj, that I cannot remove the name of the object and get the same as with the to_h.to_json methods

But the problem comes when I use a nested Struct like User

user = User.new "[email protected]", "coolService", "es", attributes
 # => #<struct User email="[email protected]", service="coolService", preferredLanguage="es", attributes=#<struct Attributes name="Pedro", preferredLanguage="es", telephoneNumber="5555555", timeZone="Madrid">> 
user.to_h.to_json
 # => "{\"email\":\"[email protected]\",\"service\":\"coolService\",\"preferredLanguage\":\"es\",\"attributes\":\"#<struct Attributes name=\\\"Pedro\\\", preferredLanguage=\\\"es\\\", telephoneNumber=\\\"5555555\\\", timeZone=\\\"Madrid\\\">\"}" 
Oj.dump user, mode: :compat
 # => "\"#<struct User email=\\\"[email protected]\\\", service=\\\"coolService\\\", preferredLanguage=\\\"es\\\", attributes=#<struct Attributes name=\\\"Pedro\\\", preferredLanguage=\\\"es\\\", telephoneNumber=\\\"5555555\\\", timeZone=\\\"Madrid\\\">>\""

With the to_h.to_json I get the string of the attributes object, And with the oj, this is not a valid JSON. and also I have another question, there is any GSON, jackson library from java that works the same way in ruby

Upvotes: 0

Views: 836

Answers (1)

ndnenkov
ndnenkov

Reputation: 36110

If you were to use ActiveSupport (Rails), you would get this out of the box. As you seem to be using barebones Ruby, just do it recursively:

hashify = lambda do |struct|
  as_hash = struct.to_h
  struct_keys = as_hash.select { |_, v| v.is_a? Struct }.map(&:first)
  struct_keys.each { |key| as_hash[key] = hashify.(as_hash[key]) }
  as_hash
end

hashify.(user).to_json
  # => "{\"email\":\"[email protected]\",\"service\":\"coolService\",\"preferredLanguage\":\"es\",\"attributes\":{\"name\":\"Pedro\",\"preferredLanguage\":\"es\",\"telephoneNumber\":\"5555555\",\"timeZone\":\"Madrid\"}}"

As for GSON, there seems to be a wrapper for Ruby, but I don't think it's that widely used. Rails' monkey patched behaviour is good enough for 99.99% of possible uses. It also lets you define your custom serializers if you want to change it.

Upvotes: 1

Related Questions