How to convert Ruby protobuf Message to JSON while preserving the case used in the proto? - ruby

When you convert a Protobuf Message in Ruby to JSON using to_json it converts all fieldnames to camelCase.
e.g. with protobuf message Person as
message Person {
string name = 1;
int32 id = 2;
string email_address = 3;
and Person in Ruby as
person = Person.new(:name => "Bob",
:id => 1,
:email_address => "foo#bar.com")
Serialized to JSON
person.to_json
>>> {"name":"Bob","id":"1","emailAddress":"foo#bar.com"}
the field email_address gets serialized in camelCase instead of snake case as it is in the proto
How can you serialize it with the original proto fieldnames?
I tried converting it to a Ruby Hash (with .to_h) at first since it preserves field names, but ran into a different issue. Fields with double values will be rendered as a Hash like price: {"value": 10.0"} instead of price: 10.0.

Buried deep in the source code is the answer.
There is an option in to_json to preserve the case used in the proto by passing in preserve_proto_fieldnames: true
e.g. person.to_json({preserve_proto_fieldnames: true})
Unfortunately this doesn't seem to be elsewhere in the Ruby protobuf documentation

Related

How do I make protobuf case-insensitive?

I have a protobuf contract like this,
message Car{
string carId = 1;
}
I generate java classes from this contract and use it to parse JSON request.
Now if my JSON has "CarID" or "carid" then protobuf generated java classes don't recognize that field. How do I make it case-insensitive?
The protobuff descriptor (.proto) are case insensitive. If you try to compile:
message Car{
string carId = 1;
string carid =2;
}
You will have the compilation error:
CARID_FIELD_NUMBER is already defined in ...
Also you have to know that for proto3, the JSON parser are dealing with lowerCamelCase. As stated on reference guide:
https://developers.google.com/protocol-buffers/docs/proto3#json
Use proto field name instead of lowerCamelCase name: By default proto3
JSON printer should convert the field name to lowerCamelCase and use
that as the JSON name. An implementation may provide an option to use
proto field name as the JSON name instead. Proto3 JSON parsers are
required to accept both the converted lowerCamelCase name and the
proto field name.
From your parser point of view "carID" and "CarID" are the same, because it will automatically convert "CarID" to "carID". But "carId" and "carid" will always be different.

Hyphens in serialized JSON OpenStruct

I have a JSON object such as:
"c": {
"10-20": 9.0,
"0-10": 8.5,
"30-end": 5.085714285714286,
"20-30": 10.3
}
When I convert that JSON to a serialized object using:
JSON.parse(response.body, object_class: OpenStruct)
It gives me:
<OpenStruct 10-20=0, 0-10=8.5, 30-end=5.085714285714286, 20-30=10.3>
Naturally that can't be accessed with c.10-20 as I don't believe hyphens are valid class variable names. So, how do you access these values?
You can use square brackets like you would with a hash:
obj["10-20"]
#=> 0
Of course, if most of the keys are not valid method names anyway, then you might as well just use a hash and not bother with an OpenStruct.
Related documentation: OpenStruct#[]

Specific Values in Json Parse

I am having difficulty getting to specific values when I parse a JSON file in Ruby. My JSON is based off of this link https://www.mcdonalds.com/services/mcd/us/restaurantLocator?latitude=40.7217861&longitude=-74.00944709999999&radius=8045&maxResults=100&country=us&language=en-us
No matter what I try I cannot pull the values I want, which is the "addressLine1" field. I get the following error:
`[]': no implicit conversion of String into Integer (TypeError)
Code
require 'json'
file = File.read('MCD.json')
data_hash = JSON.parse(file)
print data_hash.keys
print "\n"
print data_hash['features']['addressLine1']
data_hash['features'] is an array. Depending on what do you actually need, you might either iterate over it, or call:
data_hash['features'].first['properties']['addressLine1']
Note 'properties' there, since addressLine1 is not a direct descendant of 'features' elements.

how do I parse out this URL-encoded string with a JSON array using Ruby?

When I use a webhook with Mandrill and post to my Iron Worker, I get the following Raw (this is from RequestBin, as well) -- I didn't include the whole payload, just an example:
puts payload =>
mandrill_events=%5B%7B%22event%22%3A%22inbound%22%2C%22msg%22%3A%7B%22dkim%22%3A%7B%22signed%22%3Atrue%2C%22valid%22%3Atrue%7D%2C%22email%22%3A%22kaya%40hellokaya.com%22%2C%22from_email%22%3A%22example.sender%40mandrillapp.com%22%2C%22headers%22%3A%7B%22Content-Type%22%3A%22multipart%5C%2Falternative%3B+boundary%3D%5C%22_av-7r7zDhHxVEAo2yMWasfuFw%5C%22%22%2C%22Date%22%3A%22Fri%2C+10+May+2013+19%3A28%3A20+%2B0000%22%2C%22Dkim-Signature%22%3A%5B%22v%3D1%3B+a%3Drsa-
I tried to extract the value of the parameter mandrill_events using:
puts params = CGI::parse(#payload) =>
{"mandrill_events"=>["[{\"event\":\"inbound\",\"msg\":{\"dkim\":{\"signed\":true,\"valid\":true},\"email\":\"kaya#hellokaya.com\",\"from_email\":\"example.sender#mandrillapp.com\",\"headers\":{\"Content-Type\":\"multipart\\/alternative; boundary=\\\"_av-7r7zDhHxVEAo2yMWasfuFw\\\"\",\"Date\":\"Fri, 10 May 2013 19:28:20 +0000\",\"Dkim-Signature\":[\"v=1; a=rsa-sha1; c=relaxed\\/relaxed; s=mandrill; d=mail115.us4.mandrillapp.com; h=From:Sender:Subject:List-Unsubscribe:To:Message-Id:Date:MIME-Version:Content-Type; i=example.sender#mail115.us4.mandrillapp.com;
Then I am stuck. I want to extract the email value in the JSON.array.
I thought to try the following;
puts json_params = JSON.parse(params)
But I am now feeling there must be a better way....
How can I extract the elements from the JSON array in this URL-encoded string?

Passing a hash where the keys are objects to JSON?

I am trying to pass a hash into Javascript via JSON where the keys are ruby objects, and the values are arrays of objects. The arrays of objects are transmitted just fine, but the key is being converted into a string of the class.
Here is an example:
[4] pry(#<User>)> x = find_all_sections.collect { |s| { s => s.find_all_events_id_and_title } }
=> [{#<Section id: 58, course_id: 12, section_number: 3, semester_id: 1>} =>
[{:id=>37, :title=>"Event 37"},
{:id=>40, :title=>"Event 40"},
{:id=>9, :title=>"Event 9"},
{:id=>10, :title=>"Event 10"},
{:id=>16, :title=>"Event 16"},
{:id=>38, :title=>"Event 38"}, etc...
The result of converting this to json is (you just have to look at the first few characters of the string to see that it's not the object, but the to_s of the object:
[11] pry(#<User>)> x.to_json
=> "[{\"#<Section:0x007fa475b52f68>\":[{\"id\":37,\"title\":\"Event 37\"},{\"id\":40,\"title\":\"Event 40\"},{\"id\":9,\"title\":\"Event 9\"},{\"id\":10,\"title\":\"Event 10\"},{\"id\":16,\"title\":\"Event 16\"},{\"id\":38,\"title\":\"Event 38\"},{\"id\":49,\"title\":\"Event 49\"},{\"id\":39,\"title\":\"Event 39\"},{\"id\":15,\"title\":\"Event 15\"},{\"id\":25,\"title\":\"Event 25\"},{\"id\":11,\"title\":\"Event 11\"},{\"id\":4,\"title\":\"Event 4\"},{\"id\":22,\"title\":\"Event 22\"},{\"id\":1,\"title\":\"Event 1\"},{\"id\":23,\"title\":\"Event 23\"},{\"id\":8,\"title\":\"Event 8\"},{\"id\":13,\"title\":\"Event 13\"},{\"id\":26,\"title\":\"Event 26\"},{\"id\":46,\"title\":\"Event 46\"},{\"id\":20,\"title\":\"Event 20\"},{\"id\":31,\"title\":\"Event 31\"},{\"id\":6,\"title\":\"Event 6\"},{\"id\":18,\"title\":\"Event 18\"},{\"id\":41,\"title\":\"Event 41\"},{\"id\":7,\"title\":\"Event 7\"},{\"id\":43,\"title\":\"Event 43\"},{\"id\":45,\"title\":\"Event 45\"},{\"id\":24,\"title\":\"Event 24\"},{\"id\":2,\"title\":\"Event 2\"},{\"id\":44,\"title\":\"Event 44\"},{\"id\":29,\"title\":\"Event 29\"},{\"id\":28,\"title\":\"Event 28\"},{\"id\":5,\"title\":\"Event 5\"},{\"id\":3,\"title\":\"Event 3\"},{\"id\":27,\"title\":\"Event 27\"}]},
How can I achieve the JSON data keeping the key's object intact?
You can't. Keys are always strings in JavaScript. Furthermore, the JSON spec says that keys must always have the form of a single, double-quoted string literal.

Resources