Change default decimal numbers parsing behavior - ruby-on-rails

I am getting the following response of a web service call:
response = "{\"price\":39.74000000000000198951966012828052043914794921875}"
Then I'm parsing it:
json = JSON.parse(response, {:symboize_names: true})
The result is:
json = {price: 39.74}
Then I tried from Rails console to check if it is happening because of JSON library, but simply I got the following result:
>> data = {:price => 39.74000000000000198951966012828052043914794921875}
{:price=>39.74}
So it's default behavior in Rails and I need to change it (on application level) to always parse decimal numbers as BigDecimal instead of float.
Ruby = 2.3.0
Rails = 4.2.4
Can anybody help?

The solution is a hack really, but I couldn't find any better
response = "{\"price\":39.74000000000000198951966012828052043914794921875}"
transformed_response = response.gsub(/\d+\.\d+/, '"\&"')
hash = JSON.parse(transformed_response , symboize_names: true})
The resulting hash will be
{ price: "39.74000000000000198951966012828052043914794921875" }
With which you can do something like this
hash.tap { |hash| hash[:price] = BigDecimal.new(hash[:price]) }

Related

Incorporate ruby parameters into string raises bad url error

Not sure what I'm doing here
def get_full_stats(id)
riot_url = 'https://na.api.pvp.net/api/lol/na/v1.3/stats/by-summoner/#{id}/ranked?api_key=mykey'
response = HTTParty.get(riot_url)
json = JSON.parse(response.body)
json
end
and in my show.html.erb I am calling the following
api = RiotApi.new
#info = api.get_full_stats(19380406)
the view is returning to me wrong number of arguments (1 for 0) for the #info = api.get_full_stats(19380406) line.
I tried casting the parameter as a string #info = api.get_full_stats('19380406') but still raises the same error.
What's going on here?
After restarting the server, it appears that I now have a URI::InvalidURIError Error instead.
You need to use double quotes for string interpolation to work. For example,
def get_full_stats(id)
riot_url = "https://na.api.pvp.net/api/lol/na/v1.3/stats/by-summoner/#{id}/ranked?api_key=mykey"
response = HTTParty.get(riot_url)
json = JSON.parse(response.body)
json
end

how to get the key value from the nested hash inside the array?

I have a array which is inside a hash. I want know the result of the student (pass/fail) using the following array. First I have to match them with particular standard and compare their marks with the hash pass and fails. And I want to get the key pass or fail based on their mark. How to achieve this using Ruby?
array = [
{
:standard =>1
:pass=>{:tamil=>30,:eng=>25,:math=>35},
:fail=>{:tamil=>10,:eng=>15,:maths=>20}
},
{
:standard =>2,
:pass=>{:tamil=>40,:eng=>35,:math=>45},
:fail=>{:tamil=>20,:eng=>25,:maths=>30}
}
]
#student is assumed to be defined
standard = array.select {|standard| standard[:standard] == #student.standard}
eng_pass = #student.eng_mark >= standard[:pass][:eng]
eng_fail = #student.eng_mark <= standard[:fail][:eng]
return [eng_pass, eng_fail, whatever_else_you_want]
So on and forth for various topics.
The syntax in reading values from this structure is something like:
array[0][:pass][:eng]
and accordingly you can do the comparison as usual in batch:
for i in 0..#students_array.length
num = # student's score
standard = # something like array[0][:pass][:eng]
if num > standard
# something like 'put "You passed!"'
end
end

how to get key/value from xpath string

I'm working on ruby on rails project and I have a string
cmd = "\"//div/table/tbody/tr/td/label[text()=\"Select Year\"]/preceding-sibling::*[1]\" = \"2014\""
I want to get key/value like this:
key: "//div/table/tbody/tr/td/label[text()=\"Select Year\"]/preceding-sibling::*[1]"
value: "2014"
The key is a xpath. I was using cmd.split("=") which is not correct. I think i can use regex to parse the string but don't know how. Please advice.
Thank you in advance!
using split will work for you .
2.1.1 :006 > cmd = '"//div/table/tbody/tr/td/label[text()=\"Select Year\"]/preceding-sibling::*[1]" = "2014"'
=> "\"//div/table/tbody/tr/td/label[text()=\\\"Select Year\\\"]/preceding-sibling::*[1]\" = \"2014\""
2.1.1 :007 > cmd.split(" = ")[0]
=> "\"//div/table/tbody/tr/td/label[text()=\\\"Select Year\\\"]/preceding-sibling::*[1]\""
2.1.1 :008 > cmd.split(" = ")[1]
=> "\"2014\""
save the first as key and the second as value.
Now, i got solution. See below:
my original string:
a = "\"//div/table/tbody/tr/td/label[text()=\\\"Select Year\\\"]/preceding-sibling::*[1]\" = \"2014\""
I'm using:
a.match('[\w\W]*\"[\s]*=')[0]
to get string:
"\"//div/table/tbody/tr/td/label[text()=\\\"Select Year\\\"]/preceding-sibling::*[1]\" ="
Then i can use substring to get the rest string.

Array values to keys?

I am parsing some XML to JSON and then serving this on http://floating-gorge-9520.herokuapp.com/currencies.
I want to display the data so the values for currency are the keys and the values for rate then become the values for the new currency data.
For example:
USD: 1
GBP: 0.5
What is the best way of doing this?
Using two currencies for simplicity:
require 'json'
a = [{"currency"=>"USD", "rate"=>"1.3707"},
{"currency"=>"JPY", "rate"=>"140.50"}]
Hash[a.map { |h| [h['currency'],h['rate'].to_f] }]
# => {"USD"=>1.3707, "JPY"=>140.5}
Just append a .to_json on the last statement to get the JSON string.
Check this out
require 'json'
a = {}
json = '[{"currency":"USD","rate":"1.3707"},{"currency":"JPY","rate":"140.50"},{"currency":"BGN","rate":"1.9558"},{"currency":"CZK","rate":"27.368"},{"currency":"DKK","rate":"7.4625"},{"currency":"GBP","rate":"0.82183"},{"currency":"HUF","rate":"311.89"},{"currency":"LTL","rate":"3.4528"},{"currency":"PLN","rate":"4.1661"},{"currency":"RON","rate":"4.5222"},{"currency":"SEK","rate":"8.9953"},{"currency":"CHF","rate":"1.2195"},{"currency":"NOK","rate":"8.3670"},{"currency":"HRK","rate":"7.6685"},{"currency":"RUB","rate":"49.0415"},{"currency":"TRY","rate":"3.0097"},{"currency":"AUD","rate":"1.5283"},{"currency":"BRL","rate":"3.2577"},{"currency":"CAD","rate":"1.5304"},{"currency":"CNY","rate":"8.3495"},{"currency":"HKD","rate":"10.6313"},{"currency":"IDR","rate":"16097.50"},{"currency":"ILS","rate":"4.8062"},{"currency":"INR","rate":"85.1580"},{"currency":"KRW","rate":"1469.53"},{"currency":"MXN","rate":"18.2348"},{"currency":"MYR","rate":"4.5158"},{"currency":"NZD","rate":"1.6558"},{"currency":"PHP","rate":"61.092"},{"currency":"SGD","rate":"1.7376"},{"currency":"THB","rate":"44.603"},{"currency":"ZAR","rate":"15.1355"}]';
JSON.parse(json).each { |x| a[x['currency']] = x['rate'] }
print a

Converting http_params to hash

I can obtain an array from the string
http_params="created_end_date=2013-02-28&created_start_date=2013-01-01&page_size=50&offset=0&order_id=0D1108211501118%0D%0A0D11108211501118%0D%0Ac%0D%0AD%0D%0ADK212071409743%0D%0AKK30109110100%0D%0AKK30111140300%0D%0AKK30111140400%0D%0AKK30115120100%0D%0AKK30115150100&page_number=1"
So I did myarray=http_params.split("&"):
myarray=["created_end_date=2013-02-28", "created_start_date=2013-01-01", "page_size=50", "offset=0", "order_id=0D1108211501118%0D%0A0D11108211501118%0D%0Ac%0D%0AD%0D%0ADK212071409743%0D%0AKK30109110100%0D%0AKK30111140300%0D%0AKK30111140400%0D%0AKK30115120100%0D%0AKK30115150100", "page_number=1"]
I need to convert this to a hash myhash, so that I can make a Rest Client post call for myhash.to_json. Basically it should be key,value pairs like:
{:created_end_date=>"2013-02-28",:created_start_date=>"2013-01-01"....}
I know that the inverse operation can be done like this:
http_params = myhash.map{|k,v| "#{k}=#{v}"}.join('&')
but I am unable to come up with neat code for this.
What's the best way I should go about this?
require 'cgi'
hash = CGI::parse http_params
Or you can use:
hash = Rack::Utils.parse_nested_query http_params
Which does not return the values as arrays.
With pure Ruby methods, you can convert your string into a Hash as follows:
"a=1&b=2".split('&').map { |h| Hash[*h.split("=")] }
=> [{"a"=>"1"}, {"b"=>"2"}]
A blog post how to operate on Ruby collections is here: http://thinkingonthinking.com/map-reduce-in-ruby/
To get symbols as keys, a small additional step is necessary:
"a=1&b=2".split('&').map { |h| hs = h.split("="); Hash[hs[0].to_sym, hs[1]] }
=> [{:a=>"1"}, {:b=>"2"}]
As last step, a merge of the inner Hash elements has to be done. This can be done like:
"a=1&b=2".split('&').map { |h| hs = h.split("="); Hash[hs[0].to_sym, hs[1]] }.inject({}) { |s, h| s.merge(h) }
=> {:a=>"1", :b=>"2"}

Resources