to_json in Ruby without quotes around keys - ruby

The following two lines produce the same output:
1.9.3p327 :015 > {:key=>1234}.to_json
=> "{\"key\":1234}"
1.9.3p327 :016 > {"key"=>1234}.to_json
=> "{\"key\":1234}"
Which is the following json:
{
"key" : 1234
}
How can I get it to produce "{key:1234}"?

The output you want to achieve is not JSON. It is illegal. It seems kind of obvious that the JSON library will produce JSON output not something which is not JSON.
If you want to output something which is not JSON you need to use a library which is not JSON. In this particular case, it looks like you made up the output format, so you'll probably have to write the library yourself.

The other poster is correct about it not being valid JSON. I just wanted to copy a ruby object from my console into my code using colons instead of hash rockets
In this context you can use: https://github.com/awesome-print/awesome_print
ap({key: 1234}, ruby19_syntax: true, index: false)

Related

How can I convert this CSV to JSON with Ruby?

I am trying to convert a CSV file to JSON using Ruby. I am very, very, green when it comes to working with Ruby (or any language for that matter) so the answers may need to be dumbed down for me. Putting it in JSON seems like the most reasonable solution to me because I understand how to work with JSON when assigning variables equal to the attributes that come in the response. If there is a better way to do it, feel free to teach me.
My CSV is in the following format:
Header1,Header,Header3
ValueX,ValueY,ValueZ
I would like to be able to use the data to say something along the lines of this:
For each ValueX in Row 1 after the headers, check if valueZ is > ValueY. If yes, do this, if no do that. I understand how to do the if statement, just now how to parse out my information into variables/arrays.
Any ideas here?
require 'csv'
require 'json'
rows = []
CSV.foreach('a.csv', headers: true, converters: :all) do |row|
rows << row.to_hash
end
puts rows.to_json
# => [{"Header1":"ValueX","Header":"ValueY","Header3":"ValueZ"}]
Here is a first pointer:
require 'csv'
data = CSV.read('your_file.csv', { :col_sep => ',' }
Now you should have the data in data; you can test in irb.
I don't entirely understand the question:
if z > y
# do this
else
# do that
end
For JSON, you should be able to do JSON.parse().
I am not sure what target format JSON requires, probably a Hash.
You can populate your hash with the dataset from the CVS:
hash = Hash.new
hash[key_goes_here] = value_here

What's an efficient way (without parsing and re-encoding) to put a string representing JSON into a Ruby hash?

I have a JSON string which has been generated by Jbuilder:
json = "{name: 'Peter', email: 'peter#stackoverflow.com'}"
This is currently a string. However I want to combine it into a new hash (ideally in Ruby) before finally outputting it as JSON.
i.e.
output = {result: :success, data: json}
However if I convert this to JSON the json value gets double-encoded such that it's sent as a string:
output.to_json
#=> "{\"result\":\"success\",\"data\":\"{name: 'Peter', email: 'peter#stackoverflow.com'}\"}"
Now I could parse the JSON into a Ruby hash and then re-output it but that seems like a big fat waste of parsing when what I'd really like to do is to say "hey, this node is already JSON, don't re-encode it already!".
Is there any equivalent to the raw() method Rails has in views? i.e.
output = {result: :success, data: raw(json)}
so that the json evaluation of this then becomes:
output.to_json
#=> "{\"result\":\"success\",\"data\": {\"name\":\"Peter\",\"email\":\"peter#stackoverflow.com\"}"
Here’s a way you can do this, it’s a bit of a hack but you might find it useful.
First restating the problem:
# Note the quotes, your example isn't actually valid
json = "{\"name\": \"Peter\", \"email\": \"peter#stackoverflow.com\"}"
output = {result: :success, data: json}
# Without changing anything
puts JSON.generate(output)
This results in the following, where the value of data is a single string:
{"result":"success","data":"{\"name\": \"Peter\", \"email\": \"peter#stackoverflow.com\"}"}
The json gem uses a to_json method that is added to all objects to convert them to json, so the simplest fix would be to replace that method on objects you want to behave differently:
# As before
json = "{\"name\": \"Peter\", \"email\": \"peter#stackoverflow.com\"}"
# Replace to_json on the singleton object
def json.to_json *args
self
end
output = {result: :success, data: json}
# Generate the output (output.to_json gives the same result)
puts JSON.generate(output)
This creates the following, where the data value is now itself a hash, as desired:
{"result":"success","data":{"name": "Peter", "email": "peter#stackoverflow.com"}}
A cleaner way to do this, to avoid manipulating singletons in your code could be to create a subclass of string that has this behaviour:
class JsonSafeString < String
def to_json *args
self
end
end
You can now create a JsonSafeString when you want the contents included directly in a JSON object:
json = "{\"name\": \"Peter\", \"email\": \"peter#stackoverflow.com\"}"
output = {result: :success, data: JsonSafeString.new(json)}
puts JSON.generate(output)
The result is the same as above:
{"result":"success","data":{"name": "Peter", "email": "peter#stackoverflow.com"}}
You could wrap the call to JsonSafeString.new in a method like raw_json if you wanted.
Obviously this leaves the task of ensuring your string is valid to you – the main point of using a library for this is the user doesn’t have to concern themselves with things like whether to use single or double quotes, so you could be vulnerable to generating invalid JSON if you’re not careful. Also this is just a quick hack, there are probably a load of things I haven’t considered. In particular I haven’t taken character encodings into account, so watch out.
This doesn't address your question, but may help you avoid it altogether...
Do you really need to generate your json variable into JSON before adding it to the hash? Jbuilder can generate a hash just as easily as a JSON string, e.g.:
hash = Jbuilder.new do |json|
json.name 'Peter'
json.email 'peter#stackoverflow.com'
end.attributes!
# => {"name"=>"Peter", "email"=>"peter#stackoverflow.com"}
output = {result: :success, data: hash}
eval will put it out as raw code.
eval "{name: 'Peter', email: 'peter#stackoverflow.com'}"
=> {:name=>"Peter", :email=>"peter#stackoverflow.com"}
And the results.
output = {result: :success, data: eval("{name: 'Peter', email: 'peter#stackoverflow.com'}") }
=> {:result=>:success, :data=>{:name=>"Peter", :email=>"peter#stackoverflow.com"}}
And to string
output.to_s
=> "{:result=>:success, :data=>{:name=>\"Peter\", :email=>\"peter#stackoverflow.com\"}}"
And JSON
require 'json'
=> true
output.to_json
=> "{\"result\":\"success\",\"data\":{\"name\":\"Peter\",\"email\":\"peter#stackoverflow.com\"}}"

Reading a JSON file from Ruby (on Mac OS X)

I'm not a Ruby coder, but I do need to read a Json file and access to nodes using such a language.
I did my homework, but I'm not able to finish them because of my lack of knowledge I hope you can compensate.
Let's start with my sample Json file.
{
"app": [{
"name":"test",
"ip_address": "172.90.90.90"
}],
"mysql": [{
"server_password": "root",
"dbName":"dbname"
}],
"phpmyadmin": [{
"app_username": "root",
"app_password": "root"
}]
}
And this is the little code fragment I put together to read the file.
require 'json'
data = JSON.parse(File.read("data.json"))
Now, as long as I do something like
print data[0]
or
print data["app"]
everything is fine, but if I try to access the subnode "app"."name" no matter the format or the parenthesis I sue, I always get a system exception. I was expecting as the most reasonable way to do this something like data["app"]["name"] but it is clearly not the case.
I'm testing this using ruby compiler on a Mac Os X which, and Ruby version should be the latest as far as I can understand (ruby 2.0.0p247)
Can you please help me out?
Thanks and have an happy new year start.
The reason is because data["app"] is an array:
1.9.3p484 :001 > require 'json'
=> true
1.9.3p484 :002 > data = JSON.parse(File.read("/Users/example/Desktop/json.json"))
=> {"app"=>[{"name"=>"test", "ip_address"=>"172.90.90.90"}], "mysql"=>[{"server_password"=>"root", "dbName"=>"dbname"}], "phpmyadmin"=>[{"app_username"=>"root", "app_password"=>"root"}]}
1.9.3p484 :003 > print data["app"]
[{"name"=>"test", "ip_address"=>"172.90.90.90"}]
If you do data["app"].first["name"], you'll get what you want:
1.9.3p484 :004 > print data["app"].first["name"]
test
In your sample data, app contains an Array, so you need to access it as such:
data["app"][0]["name"]

TypeError: can't convert Builder::XmlMarkup to Array

I'm having issues with getting access to the raw xml from a Builder::XmlMarkup object.
irb> xml = Builder::XmlMarkup.new(:target => '')
=> <pretty_inspect/>
irb> xml.foo("bar")
=> "<pretty_inspect/><foo>bar</foo>"
irb> puts xml
TypeError: can't convert Builder::XmlMarkup to Array (Builder::XmlMarkup#to_ary gives String)
from (pry):122:in `puts'
In a script where I'm using Builder to create the XML, I'm passing #xml to a POST:
response = HTTParty.post(API_ENDPOINT, :body => #xml)
This gives the same error:
TypeError (can't convert Builder::XmlMarkup to Array (Builder::XmlMarkup#to_ary gives String)):
Of course, if I do #xml.to_xml, it doesn't return an error, but it adds </to_xml> to the xml, meaning it isn't actually converting the XML object to xml. That's not what I want.
So how can I get access access to the xml so that I can pass it to my post without it adding extra nodes to my xml?
Edit: possible solution
Doing #xml.target! seems to resolve the issue, but I'm not sure I understand why.
response = HTTParty.post(API_ENDPOINT, :body => #xml.target!)
Perhaps someone can help me understand what is happening here.
Using
puts xml
is outputting the Builder::XmlMarkup object and hence give the error
Using
puts xml.target!
outputs the current xml string, which is what you want

How to get to_json work on BSON::Code object as well in mongo-ruby-driver

I am trying 'mongo-ruby-driver' for some project. It's working fine except when I call to_json on mongo object. It gives well formed json but it's not converting BSON::Code into readable value i resulting JSON.
Instead of showing code text, it show something like
#<BSON::Code:0x00000100af6fa8>
Did anyone tried it. Any help id highly appreciated.
UPDATE
here is some code snippet:
#records is variable that contains Array of MongoDB documents in hash.
#records.to_json
When I call to_json on it it gives everything as expected. except for the key that contain BSON::Code (means javascript code). for example consider following doc:
{
"_id" : "contains",
"value" : function( obj, target ) { return obj.indexOf(target) != -1; };
}
Querying same doc from ruby gives output like:
{
"_id"=>"contains",
"value"=><BSON::Code:2160165280 #data="function( obj, target ) { return obj.indexOf(target) != -1; };" #scope="{}">
}
and calling to_json on this gives following:
{"_id":"contains","value":"#<BSON::Code:0x00000100b54658>"}
this is what the problem is. Instead of getting actual code for 'value' key I am getting ruby object as string.
Calling code method on BSON::Code we can get it converted into code. But for that I need to loop mongo docs, check values for each key, calling code on it if it is an object of BSON::Code and then assigning it back to key. And at last we can call to_json on it. But I dont want this much overhead. I need to_json itself should take care of it.
The serializer that is iterating over the attributes of the objects in the array is probably calling the to_s method which would cause the output you are seeing.
You can either monkey patch the BSON::Code class to include a to_s method which calls inspect (the method that produces the output you want) or modify the serializer to detect when it encounters a BSON::Code instance and call inspect on it rather than to_s.
The code to mokey patch the BSON::Code class would look like this:
module BSON
class Code
def to_s
inspect
end
end
end
This would have the same behavior as inspect. If you just wanted the code you could monkey patch this in:
module BSON
class Code
def to_s
#code
end
end
end
I might make this the default behavior for to_s in the driver but for now just include that in your code and it should work like a champ.
Which Mongo object, do you mean the module? If you could, please post the code and what you are trying to do.
The only to_json I see in the driver is BSON::ObjectId#to_json which (from the docs) is described as a method that does the following:
Convert to MongoDB extended JSON format. Since JSON includes type information, but lacks an ObjectId type, this JSON format encodes the type using an $oid key.
I get the same results when I use it:
1.9.3-p0 :001 > require 'mongo'
=> true
1.9.3-p0 :002 > BSON::ObjectId
=> BSON::ObjectId
1.9.3-p0 :003 > BSON::ObjectId.new()
=> BSON::ObjectId('4f17350eadd361e91d000001')
1.9.3-p0 :004 > BSON::ObjectId.new().to_json
=> "{\"$oid\": \"4f173512add361e91d000002\"}"
BSON ( http://bsonspec.org/ ) is a binary representation of JSON ( http://www.json.org/ ) . JSON is not meant to be used to describe functions, as it is meant to be portable. Functions in this manner are not portable to other systems. So there is no way to serialize it. There is some hacks defined here that may get you what you need, but ultimately, BSON/JSON may be a weird tool for the job if your trying to serialize functions.

Resources