1

Somehow, the webservice I am using savon to deal with returns this response

 {:do_deal_response=>{:do_deal_result=>"Code=000&CardNumber=0000&CardDate=12/18&PayDate=02/01/2017&BusinessName=בדיקות&Terminal=0962317010&ActionMethod=עסקה טלפונית&DealID=5349614&DealType=אשראי רגיל&DealTypeOut=עסקת חובה רגילה 0000000&OkNumber=0000000&DealDate=06/12/2016 11:00:14&PayNumber=&TotalSum=111&FirstPay=&CardName=ויזה כ.א.ל&CardNameID=2&AuthNum=0000000&DealNumber=06370507&ParamJ=J4&ErrorDesc=עסקה תקינה.&Currency=שקלים&CurrencyID=1&Manpik=ויזה כ.א.ל&ManpikID=2&Mutag=ויזה כ.א.ל&MutagID=2", :@xmlns=>"http://tempuri.org/"}} 

accessing @response[:do_deal_response][:do_deal_result] obviously returns the string

"Code=000&CardNumber=0000&CardDate=12/18&PayDate=02/01/2017&BusinessName=בדיקות&Terminal=0962317010&ActionMethod=עסקה טלפונית&DealID=5349614&DealType=אשראי רגיל&DealTypeOut=עסקת חובה רגילה 0000000&OkNumber=0000000&DealDate=06/12/2016 11:00:14&PayNumber=&TotalSum=111&FirstPay=&CardName=ויזה כ.א.ל&CardNameID=2&AuthNum=0000000&DealNumber=06370507&ParamJ=J4&ErrorDesc=עסקה תקינה.&Currency=שקלים&CurrencyID=1&Manpik=ויזה כ.א.ל&ManpikID=2&Mutag=ויזה כ.א.ל&MutagID=2" 

I want to be able to access this string as a hash with with symbols like:

results[:code] = "000"
Kamal G'ool
  • 171
  • 2
  • 13
  • Possible duplicate of [Parse a string as if it were a querystring in Ruby on Rails](http://stackoverflow.com/questions/2772778/parse-a-string-as-if-it-were-a-querystring-in-ruby-on-rails) – Wand Maker Dec 06 '16 at 09:35

2 Answers2

2

Instead of manually parsing, you can use the following:

require 'cgi'

parsed = CGI.parse(@response[:do_deal_response][:do_deal_result])
parsed['Code']
#=> ["000"]

Since this accepts multiple values for each key values are always wrapped in an array. If that bothers you, you can do one more transformation step with map (or map_values if you use Rails):

parsed.map { |k, v| [k.underscore.symbolize, v.size == 1 ? v.first : v] }.to_h
#=> => {:code=>"000", :card_number=>"0000", :ard_date=>"12/18", :pay_date=>"02/01/2017",...

This will only unwrap arrays with one element, everything else will stay in an array.

Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
1

Stand-alone solution

This code could help you. It just splits the string around &, split every part around = and saves them as key and value in a Hash :

response = {:do_deal_response=>{:do_deal_result=>"Code=000&CardNumber=0000&CardDate=12/18&PayDate=02/01/2017&BusinessName=בדיקות&Terminal=0962317010&ActionMethod=עסקה טלפונית&DealID=5349614&DealType=אשראי רגיל&DealTypeOut=עסקת חובה רגילה 0000000&OkNumber=0000000&DealDate=06/12/2016 11:00:14&PayNumber=&TotalSum=111&FirstPay=&CardName=ויזה כ.א.ל&CardNameID=2&AuthNum=0000000&DealNumber=06370507&ParamJ=J4&ErrorDesc=עסקה תקינה.&Currency=שקלים&CurrencyID=1&Manpik=ויזה כ.א.ל&ManpikID=2&Mutag=ויזה כ.א.ל&MutagID=2", :@xmlns=>"http://tempuri.org/"}} 

deal_result = response[:do_deal_response][:do_deal_result]

class String
  def underscore
    self.gsub(/::/, '/').
    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
    gsub(/([a-z\d])([A-Z])/,'\1_\2').
    tr("-", "_").
    downcase
  end
end

results = deal_result.split('&').each_with_object({}) do |string, h|
  key, value = string.split('=')
  h[key.underscore.to_sym] = value
end

puts results
#=> {:code=>"000", :card_number=>"0000", :card_date=>"12/18", :pay_date=>"02/01/2017", :business_name=>"בדיקות", :terminal=>"0962317010", :action_method=>"עסקה טלפונית", :deal_id=>"5349614", :deal_type=>"אשראי רגיל", :deal_type_out=>"עסקת חובה רגילה 0000000", :ok_number=>"0000000", :deal_date=>"06/12/2016 11:00:14", :pay_number=>nil, :total_sum=>"111", :first_pay=>nil, :card_name=>"ויזה כ.א.ל", :card_name_id=>"2", :auth_num=>"0000000", :deal_number=>"06370507", :param_j=>"J4", :error_desc=>"עסקה תקינה.", :currency=>"שקלים", :currency_id=>"1", :manpik=>"ויזה כ.א.ל", :manpik_id=>"2", :mutag=>"ויזה כ.א.ל", :mutag_id=>"2"}

With Rack

If you have Rack installed :

require 'rack'
puts Rack::Utils.parse_nested_query(deal_result).map { |k, v| [k.underscore.to_sym, v] }.to_h

Both answers match exactly the structure you were looking for : snakecase symbol for key and non Array values.

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124