How to change json response to string using ruby code - ruby

i am new with ruby code, so i have this response :
{
"data":[
{
"name":"Andy",
"user_type":0,
"info":"",
"user_info":null,
"new":false,
"active":false,
"cities":[
],
"visibility_settings":{
"general":false,
"product":false
}
}
]
}
how to change it to_string in ruby code, like this
"name":"Andy",
"user_type":"0",
"info":"",
"user_info":"null",
"new":"false",
"active":"false",
"cities":"[]",
"visibility_settings":{
"general":"false",
"product":"false"
}
because i want to compare it with my datatable :
| name | user_type | new | user_info |
| Andy | 1 | false | true |
and my script is like this :
And("response "jsonpath" filter "filter" have:") do |jpath, filter, table|
response = JsonPath.new("#{jpath}").on(#response).to_a.first
table = table.hashes
table.each do |data|
target = response.select { |resp| resp["#{filter}"] == data["#{filter}"] } data.each { |key, value| expect(data).to eq(target.first) }
end
end

Related

Merge Ruby nested hashes with same keys

I have several hashes in Ruby which have nested hashes inside of them an share very similar structure. They look something like this:
a = {
"year_1": {
"sub_type_a": {
"label1": value1
}
},
"year_2": {
"sub_type_a": {
"label2": value2
}
}
}
b = {
"year_1": {
"sub_type_a": {
"label3": value3
}
},
"year_2": {
"sub_type_a": {
"label4": value4
}
}
}
c = {
"year_1": {
"sub_type_a": {
"label5": value5
}
},
"year_2": {
"sub_type_a": {
"label6": value6
}
}
}
I want to combine them in one single hash which would have the nested data combined where possible without overwriting other values like this:
result = {
"year_1": {
"sub_type_a": {
"label1": value1,
"label3": value3,
"label5": value5
}
},
"year_2": {
"sub_type_a": {
"label2": value2,
"label4": value4,
"label6": value6
}
}
}
There could also be several sub types instead of just one but that's the general idea.
If I use the merge function it just overwrites the label-value data inside the sub_type hashes and I am left with only one record.
Is there a simple way to achieve this? I can write a function that iterates the hashes recursively and figure out inside what to add where but it feels like that there should be a simpler way.
Something similar.
Combine each_with_object, each and merge so you can iterate trough each hash and assign the merged values when they exist to a temporal new one:
[a, b, c].each_with_object({}) do |years_data, hash|
years_data.each do |year, data|
hash[year] = (hash[year] || {}).merge(data) { |_, oldval, newval| oldval.merge(newval) }
end
end
# {
# :year_1 => {
# :sub_type_a => {
# :label1 => :value1,
# :label3 => :value3,
# :label5 => :value5
# }
# },
# :year_2 => {
# :sub_type_a => {
# :label2 => :value2,
# :label4 => :value4,
# :label6 => :value6
# }
# }
# }
If you are using Rails (or ActiveSupport) you might want to look at deep_merge, which handles merging of nested hashes for you
We are given the following.
a = {:year_1=>{:sub_type_a=>{:label1=>"value1"}},
:year_2=>{:sub_type_a=>{:label2=>"value2"}}}
b = {:year_1=>{:sub_type_a=>{:label3=>"value3"}},
:year_2=>{:sub_type_a=>{:label4=>"value4"}}}
c = {:year_1=>{:sub_type_a=>{:label5=>"value5"}},
:year_2=>{:sub_type_a=>{:label6=>"value6"}}}
arr = [a, b, c]
We may construct the desired hash as follows.
arr.each_with_object({}) do |g,h|
g.each do |yr,v|
k,f = v.first
h.update(yr=>{ k=>f }) { |_,o,n| { k=>o[k].merge(n[k]) } }
end
end
#=> {:year_1=>{:sub_type_a=>{:label1=>"value1", :label3=>"value3",
# :label5=>"value5"}},
# :year_2=>{:sub_type_a=>{:label2=>"value2", :label4=>"value4",
# :label6=>"value6"}}}
This uses the form of Hash#update (a.k.a merge!) that employs a block to determine the values of keys that are present in both hashes being merged. See the link for an explanation of that block's three block variables. I've used an underscore (a valid local variable) for the first block variable, the common key, to signal to the reader that it is not used in the block calculation. That is a common convention.
For anyone interested in the gory detail of the calculations (the one sure-fire way to understand what's going on) I will execute the code with some puts statements added.
arr.each_with_object({}) do |g,h|
puts "g=#{g}"
puts "h=#{h}"
g.each do |yr,v|
puts " yr=#{yr}"
puts " v=#{v}"
k,f = v.first
puts " k=#{k}"
puts " f=#{f}"
puts " yr=>{ k=>f } = #{yr}=>#{v} = #{{ yr=>v }}"
h.update(yr=>{ k=>f }) do |_,o,n|
puts " _=#{_}"
puts " o=#{o}"
puts " n=#{n}"
puts " { k=>o[k].merge(n[k]) }"
puts " => { #{k}=>#{o[k]}.merge(#{n[k]}) }"
{ k=>o[k].merge(n[k]) }.tap { |e| puts " => #{e}" }
end
end
end
The following is displayed.
g={:year_1=>{:sub_type_a=>{:label1=>"value1"}},
:year_2=>{:sub_type_a=>{:label2=>"value2"}}}
h={}
yr=year_1
v={:sub_type_a=>{:label1=>"value1"}}
k=sub_type_a
f={:label1=>"value1"}
yr=>{ k=>f } = year_1=>{:sub_type_a=>{:label1=>"value1"}} =
{:year_1=>{:sub_type_a=>{:label1=>"value1"}}}
yr=year_2
v={:sub_type_a=>{:label2=>"value2"}}
k=sub_type_a
f={:label2=>"value2"}
yr=>{ k=>f } = year_2=>{:sub_type_a=>{:label2=>"value2"}} =
{:year_2=>{:sub_type_a=>{:label2=>"value2"}}}
g={:year_1=>{:sub_type_a=>{:label3=>"value3"}},
:year_2=>{:sub_type_a=>{:label4=>"value4"}}}
h={:year_1=>{:sub_type_a=>{:label1=>"value1"}},
:year_2=>{:sub_type_a=>{:label2=>"value2"}}}
yr=year_1
v={:sub_type_a=>{:label3=>"value3"}}
k=sub_type_a
f={:label3=>"value3"}
yr=>{ k=>f } = year_1=>{:sub_type_a=>{:label3=>"value3"}} =
{:year_1=>{:sub_type_a=>{:label3=>"value3"}}}
_=year_1
o={:sub_type_a=>{:label1=>"value1"}}
n={:sub_type_a=>{:label3=>"value3"}}
{ k=>o[k].merge(n[k]) }
=> { sub_type_a=>{:label1=>"value1"}.
merge({:label3=>"value3"}) }
=> {:sub_type_a=>{:label1=>"value1", :label3=>"value3"}}
yr=year_2
v={:sub_type_a=>{:label4=>"value4"}}
k=sub_type_a
f={:label4=>"value4"}
yr=>{ k=>f } = year_2=>{:sub_type_a=>{:label4=>"value4"}} =
{:year_2=>{:sub_type_a=>{:label4=>"value4"}}}
_=year_2
o={:sub_type_a=>{:label2=>"value2"}}
n={:sub_type_a=>{:label4=>"value4"}}
{ k=>o[k].merge(n[k]) }
=> { sub_type_a=>{:label2=>"value2"}.
merge({:label4=>"value4"}) }
=> {:sub_type_a=>{:label2=>"value2", :label4=>"value4"}}
g={:year_1=>{:sub_type_a=>{:label5=>"value5"}},
:year_2=>{:sub_type_a=>{:label6=>"value6"}}}
h={:year_1=>{:sub_type_a=>{:label1=>"value1", :label3=>"value3"}},
:year_2=>{:sub_type_a=>{:label2=>"value2", :label4=>"value4"}}}
yr=year_1
v={:sub_type_a=>{:label5=>"value5"}}
k=sub_type_a
f={:label5=>"value5"}
yr=>{ k=>f } = year_1=>{:sub_type_a=>{:label5=>"value5"}} =
{:year_1=>{:sub_type_a=>{:label5=>"value5"}}}
_=year_1
o={:sub_type_a=>{:label1=>"value1", :label3=>"value3"}}
n={:sub_type_a=>{:label5=>"value5"}}
{ k=>o[k].merge(n[k]) }
=> { sub_type_a=>{:label1=>"value1", :label3=>"value3"}.
merge({:label5=>"value5"}) }
=> {:sub_type_a=>{:label1=>"value1", :label3=>"value3",
:label5=>"value5"}}
yr=year_2
v={:sub_type_a=>{:label6=>"value6"}}
k=sub_type_a
f={:label6=>"value6"}
yr=>{ k=>f } = year_2=>{:sub_type_a=>{:label6=>"value6"}} =
{:year_2=>{:sub_type_a=>{:label6=>"value6"}}}
_=year_2
o={:sub_type_a=>{:label2=>"value2", :label4=>"value4"}}
n={:sub_type_a=>{:label6=>"value6"}}
{ k=>o[k].merge(n[k]) }
=> { sub_type_a=>{:label2=>"value2", :label4=>"value4"}.
merge({:label6=>"value6"}) }
=> {:sub_type_a=>{:label2=>"value2", :label4=>"value4",
:label6=>"value6"}}
=> {:year_1=>{:sub_type_a=>{:label1=>"value1", :label3=>"value3",
:label5=>"value5"}},
:year_2=>{:sub_type_a=>{:label2=>"value2", :label4=>"value4",
:label6=>"value6"}}}
Hash#merge takes an optional conflict resolution block, which will be called any time a key is present in both the subject and the parameter.
You can use this to e.g. recursively merge your hashes.

Can spock mock dynamic objects

As you can see, I tried to mock response dynamically.
underTest.getByTaskIds(taskIds) will pass a list of taskIds, inside the method I will invoke underTest.getByTaskId(taskId, channelId, false) separately.
But this won't work.
when:
def actual = underTest.getByTaskIds(taskIds)
then:
taskIds.forEach({ taskId ->
underTest.getByTaskId(taskId, channelId, false) >> mockResp.get(taskId)
})
actual.size() == expectedResultSize
where:
taskIds | mockResp | expectedResultSize
[] as Set<UUID> | [key: value] | 1
[UUID.randomUUID()] as Set<UUID> | [key: value] | 1
[UUID.randomUUID(), UUID.randomUUID()] as Set<UUID> | [key: value] | 2
Example
class UnderTest:
void taskId(id){
do something
}
void taskIds(ids)->
{
this.taskId(id)
}

Get values from nested hash

I have this Hash that I use store values and if the values are not found to get default values:
AMOUNT = {
EUR: {
eps: { AT: 1_00 },
safetypay: { PE: 15_000_00, CR: 5_000_00, BE: 15_000_00, },
przelewy24: 5_00,
qiwi: 5_00,
bcmc: { AT: 1_00, BE: 1_00 },
giropay: { DE: 1_00 },
ideal: { NL: 1_00 },
mybank: { IT: 1_00, FR: 1_00 },
},
CZK: {
trustpay: { CZ: 20_00 }
}
}.with_indifferent_access
I would like to get values based on the keys so I tried this:
def amount_for(payment_type, country, currency)
payment_amount = AMOUNT.dig(currency, payment_type, country) if payment_type.is_a?(Hash)
payment_amount ||= AMOUNT.dig(currency, payment_type)
payment_amount ||= 1
end
But I get for result not number but {"AT"=>100, "BE"=>100}. If I remove the check if payment_type.is_a?(Hash) I get exception Integer does not have #dig method (RuntimeError)
Do you know how I can solve this issue?
payment_type will be e.g. "AT" - it's the argument you pass into your function, it will never be a Hash.
This rewrite should do what you want:
def amount_for(payment_type, country = nil, currency = nil)
path = [payment_type, country, currency].compact
obj = AMOUNT
obj = obj[path.shift] while Hash === obj && !path.empty?
return obj || 1
end
Alternately, this is rather similar to the code you wrote:
def amount_for(payment_type, country = nil, currency = nil)
tmp = AMOUNT.dig(payment_type, country, currency)
return tmp if tmp
tmp = AMOUNT.dig(payment_type, country)
return tmp if tmp
tmp = AMOUNT.dig(payment_type)
return tmp if tmp
return 1
end

Building a data structure in Ruby

Am am trying to build a data structure by looping over an array.
This is what I have
a = ['a1', 'a2']
def func(name)
{name =>
{'key1'=> 'value2',
'key2'=> 'value2'
}
}
end
content = {'root'=>
a.each do | v |
func(v)
end
}
Which gives me
{"root"=>["a1","a2"]}
I am after this
{
"r"=> {
"a1"=> {
"key1"=> "value2",
"key2"=> "value2"
},
"a2"=> {
"key1"=> "value2",
"key2"=> "value2"
}
}
}
Can someone show me where I am going wrong?
You're using each, which only return the array itself. Instead of that, you need to use map:
content = { 'root' =>
a.map do | v |
func(v)
end
}
Or in a better syntax, since the block is one line:
content = {
'root' => a.map { |v| func(v) }
}
It still needs some refactoring but you will get the idea. If you use map it will return array and resulted "r" will be array and not hash.
{"r": a.each_with_object(Hash.new(0))
{ |h1, h2| h2[h1]={"key1"=>"value2", "key2"=>"value2"} }
}
it will return exactly
{:r=>{
"a1"=>{"key1"=>"value2", "key2"=>"value2"},
"a2"=>{"key1"=>"value2","key2"=>"value2"}
}
}

Merge two hashes on a particular value

I am checking whether the hash hash_volumes below has a key whose instance_id matches with a key of hash hash_instance.
hash_volumes = {
:"vol-d16d12b8" => {
:instance_id => "i-4e4ba679",
},
}
hash_instance = {
:"i-4e4ba679" => {
:arch => "x86_64",
},
}
If it does, then I need to merge it to the hash_instance. I find that vol-d16d12b8 matches with the instance i-4e4ba679 and hence I want to merge it with hash_instance so that the final hash_instance will look like below:
hash_instance = {
:"i-4e4ba679" => {
:arch => "x86_64",
:volume => "vol-d16d12b8" # this is new entry to `hash_instance`
},
}
I am not able to merge these two hashes as explained above. I suspect my if statement is wrong. Please take a look at my code below:
hash_volumes.each_key do |x|
hash_instance.each_key do |y|
if hash_volumes[x][:instance_id] == y ## I think this line is the problem
hash_instance[y][:volume] = x
end
end
end
hash_instance
Output:
{
:"i-4e4ba679" => {
:arch => "x86_64"
}
}
The code above gives hash_instance without adding volume to it. I tried as below, but none worked:
if hash_volumes[x][:instance_id] == "#{y}"
# => this if statement gives me syntax error
.....
if hash_volumes[x][:instance_id] =~ /"#{y}"/
# => this if statement does not make any changes to above output.
hash_volumes = {
:"vol-d16d12b8" => {
:instance_id => "i-4e4ba679",
},
}
hash_instance = {
:"i-4e4ba679" => {
:arch => "x86_64",
},
}
hash_volumes.each do |key, val|
id = val[:instance_id] #returns nil if the there is no :instance_id key
if id
id_as_sym = id.to_sym
if hash_instance.has_key? id_as_sym
hash_instance[id_as_sym][:volume] = id
end
end
end
--output:--
{:"i-4e4ba679"=>{:arch=>"x86_64", :volume=>"i-4e4ba679"}}
A simple implementation would be this:
hash_instance.each do |k1, v1|
next unless k = hash_volumes.find{|k2, v2| v2[:instance_id].to_sym == k1}
v1[:volume] = k.first
end

Resources