escaping ruby values in hash - ruby

I'm trying to use the values of other variable when declaring a ruby hash. Those values are now being escaped as I expected. How can I fix this?
variables
ipa_url, name, version and bundle-identifier
code
data = {
plist: {
dict: {
key: 'items',
array: {
dict: {
key: %w('assets','metadata'),
array: {
dict: [{ key: %w('kind','url'),
string: %w('software-package',
"#{ipa_url") },
{ key: %w('kind','url'),
string: %w('display-image',"#{icon_url.to_s}") },
{ key: %w('kind','url'),
string: %w('full-size-image',
"#{icon_url}") }],
dict: { key: %w('bundle-identifier','bundle-version',
'kind','title'),
string: %w("#{bundle-identifier}","#{version}",
'software',"#{name}")
}
}
}
}
}
}
}

The %w identifier is used to created an array out of a space delimited text:
%w(this is a test)
# => ["this", "is", "a", "test"]
If you want to use string interpolation there, you should use %W instead:
variable = 'test'
%W(this is a #{variable})
# => ["this", "is", "a", "test"]

zenspider goes over this in detail but for SO purposes, here's the breakdown:
%q(no interpolation)
[6] pry(main)> hey
=> "hello"
[7] pry(main)> hash = { 'hi' => %q("#{hey}", 'how are you') }
=> {"hi"=>"\"\#{hey}\", 'how are you'"}
%Q(interpolation and backslashes)
[8] pry(main)> hash = { 'hi' => %Q("#{hey}", 'how are you') }
=> {"hi"=>"\"hello\", 'how are you'"}
%(interpolation and backslashes)
[9] pry(main)> hash = { 'hi' => %("#{hey}", 'how are you') }
=> {"hi"=>"\"hello\", 'how are you'"}
%W(interpolation) as Uri showed:
[7] pry(main)> hash = { 'hi' => %W(#{hey} how are you) }
=> {"hi"=>["hello", "how", "are", "you"]}

Related

How do I assign part of a hash to another variable?

Trying to assign part of a has to another variable. I have a hash. Something like:
hash = {
"cupcake" => {
"a" => 1
},
"muffin" => {
"b" => 2
}
}
When I do something like:
cupcake = hash["cupcake"]
cupcake is nil after this code.
If you want string keys you have to use this syntax
hash = {
"cupcake" => {
"a" => 1
},
"muffin" => {
"b" => 2
}
}
Syntax with colons is for symbol keys
hash = {
cupcake: {
a: 1
},
muffin: {
b: 2
}
}
cupcake = hash[:cupcake]

iterate through nested hashes using conditionals in Ruby

I am trying to build a new_hash from this hash:
languages = {
:oo => {
:ruby => {
:type => "interpreted"
},
:javascript => {
:type => "interpreted"
},
:python => {
:type => "interpreted"
}
},
:functional => {
:clojure => {
:type => "compiled"
},
:erlang => {
:type => "compiled"
},
:javascript => {
:type => "interpreted"
}
}
}
and the desired result is:
{
:ruby => {
:type => "interpreted",
:style => [:oo]
},
:javascript => {
:type => "interpreted",
:style => [:oo, :functional]
},
:python => {
:type => "interpreted",
:style => [:oo]
},
:clojure => {
:type => "compiled",
:style => [:functional]
},
:erlang => {
:type => "compiled",
:style => [:functional]
}
}
Here is what I've done so far:
def reformat_languages(languages)
new_hash = {}
languages.each do |k, v|
v.each do |k1, v1|
new_hash[k1] = v1
new_hash[k1][:style] = []
new_hash[k1][:style] << k
end
end
new_hash
end
unfortunately, I cannot get the desired result. I understand that when the iteration arrives at the second javascript key, it re-writes over the first iteration giving me:
:javascript => {
:type => "interpreted",
:style => [:functional]
}
instead of:
:javascript => {
:type => "interpreted",
:style => [:oo, :functional]
}
Here is a link of a repl.it where I you can see the code in action: https://repl.it/BebC
I know I need to use a conditional, but I am not really sure where and on what to use it. If somebody could help me getting the desired result and explain a little bit why it works the way it works.
You can use something like
h = {}
languages.each do |k, v| # oo or func
v.each do |k1, v1| # ruby/python
if h[k1]
h[k1][:style] << k
else
h[k1] = {type: v1[:type], style: [k]}
end
end
end
It checks to see that h is defined, and if so, appends to its array. Otherwise it defines the entire hash with your type and a style array of size 1.
There is too much unconditional overwriting going on in your code. Should be something like this instead:
new_hash[k1] ||= {} # init to empty hash
new_hash[k1][:type] = v1[:type]
new_hash[k1][:style] ||= [] # make sure array exists
new_hash[k1][:style] << k
Instead of replacing entire new_hash[k1], you should change individual parts of it.
This is not an answer (so please no upvotes). Rather, it is an extended comment to help you understand the code #Martin suggested. (I see you are new to SO and quite possibly to Ruby as well.) Salting code with puts statements, as I have done, is often quite helpful, even after you become experienced with the language.
languages = {
:oo => {
:ruby => {
:type => "interpreted"
},
:javascript => {
:type => "interpreted"
}
},
:functional => {
:clojure => {
:type => "compiled"
},
:javascript => {
:type => "interpreted"
}
}
}
h = {}
languages.each do |k, v| # oo or func
puts "k=#{k}, v=#{v}"
v.each do |k1, v1| # ruby/python
puts " k1=#{k1}, v1=#{v1}"
if h[k1]
puts " h[#{k1}]=#{h[k1]} (truthy)"
h[k1][:style] << k
puts " h after h[#{k1}][:style] << #{k}: #{h}"
else
puts " h[#{k1}].nil?=true (falsy)"
h[k1] = {type: v1[:type], style: [k]}
puts " h after h[#{k1}] = {type: v1[:type], style: #{k}}: #{h}"
end
end
end
prints:
k=oo, v={:ruby=>{:type=>"interpreted"}, :javascript=>{:type=>"interpreted"}}
k1=ruby, v1={:type=>"interpreted"}
h[ruby].nil?=true (falsy)
h after h[ruby] = {type: v1[:type], :style: oo}:
{:ruby=>{:type=>"interpreted", :style=>[:oo]}}
k1=javascript, v1={:type=>"interpreted"}
h[javascript].nil?=true (falsy)
h after h[javascript] = {type: v1[:type], :style: oo}:
{:ruby=>{:type=>"interpreted", :style=>[:oo]},
:javascript=>{:type=>"interpreted", :style=>[:oo]}}
k=functional, v={:clojure=>{:type=>"compiled"}, :javascript=>{:type=>"interpreted"}}
k1=clojure, v1={:type=>"compiled"}
h[clojure].nil?=true (falsy)
h after h[clojure] = {type: v1[:type], :style: functional}:
{:ruby=>{:type=>"interpreted", :style=>[:oo]},
:javascript=>{:type=>"interpreted", :style=>[:oo]},
:clojure=>{:type=>"compiled", :style=>[:functional]}}
k1=javascript, v1={:type=>"interpreted"}
h[javascript]={:type=>"interpreted", :style=>[:oo]} (truthy)
h after h[javascript][:style] << functional:
{:ruby=>{:type=>"interpreted", :style=>[:oo]},
:javascript=>{:type=>"interpreted", :style=>[:oo, :functional]},
:clojure=>{:type=>"compiled", :style=>[:functional]}}
and returns:
#=> {:oo =>{:ruby=>{:type=>"interpreted"},
# :javascript=>{:type=>"interpreted"}},
# :functional=>{:clojure=>{:type=>"compiled"},
# :javascript=>{:type=>"interpreted"}}}
You are overwriting the hashes generated which is leading to the unexpected behavior you mentioned. The following piece of code does what you need. Its just a slightly modified version of your code.
def reformat_languages(languages)
new_hash = {}
languages.each do |k, v|
v.each do |k1, v1|
new_hash[k1] ||= v1 #ensures we do not overwrite the already generated language hash
new_hash[k1][:style] ||= [] #protecting against re-initialization of the style array
new_hash[k1][:style] << k
end
end
new_hash
end

Populating a hash from an array

I have this array:
params[:types] = [type1, type2, type3...]
I would like to populate my hash the following way using the above array:
params[:hash] = {
"type1" => {
something: something
},
"type2" => {
something: something
},
}
Using a for loop like for index in i ...params[:types] just populates the hash with the last value in the array.
You can use the each_with_object method to do this:
params = {}
params[:types] = ["type1", "type2", "type3"]
params[:types].each_with_object({}) { |k, h| h[k] = { "something" => "something" } }
That last line will return:
=> {"type1"=>{"something"=>"something"}, "type2"=>{"something"=>"something"}, "type3"=>{"something"=>"something"}}
Here is a code snippet example that does what you need.
hash = {}
array.each do |a|
hash[a.to_s] = { "something" => "something" }
end
output:
hash
=> {
"type1" => {
"something" => "something"
},
"type2" => {
"something" => "something"
},
"type3" => {
"something" => "something"
}
}
You could do this:
params = { types: ["type1", "type2", "type3"] }
Hash[params[:types].product([{"something" => "something"}])]
#=> {"type1"=>{"something"=>"something"},
# "type2"=>{"something"=>"something"},
# "type3"=>{"something"=>"something"}}
or with Ruby 2.1,
params[:types].product([{"something" => "something"}]).to_h
If you want a different hash for each element of params[:types]:
hashes = [{ "something1"=>"something1" }, { "something2"=>"something2" },
{ "something3"=>"something3" }]
then
Hash[params[:types].zip(hashes)]
#=> {"type1"=>{"something1"=>"something1"},
# "type2"=>{"something2"=>"something2"},
# "type3"=>{"something3"=>"something3"}}

Split an array of hashes in two based on the value of a key

How can split this array of hashes in two based on the value of the ate key?
array = [
{ name: "Gad", ate: true },
{ name: "Lad", ate: false },
{ name: "Bad", ate: true },
{ name: "Sad", ate: false }
]
Example output
array_1 = [
{ name: "Gad", ate: true },
{ name: "Bad", ate: true }
]
array_2 = [
{ name: "Lad", ate: false },
{ name: "Sad", ate: false }
]
Use the Enumerable#partition method:
array.partition { |x| x[:ate] }
# => [[{:name=>"Gad", :ate=>true}, {:name=>"Bad", :ate=>true}],
# [{:name=>"Lad", :ate=>false}, {:name=>"Sad", :ate=>false}]]
Or:
array_1, array_2 = array.partition { |x| x[:ate] }
array_1
# => [{:name=>"Gad", :ate=>true}, {:name=>"Bad", :ate=>true}]
array_2
# => [{:name=>"Lad", :ate=>false}, {:name=>"Sad", :ate=>false}]
array_one, array_two = *array.group_by { |x| x[:ate] }.map(&:last)
=> array_one
=> # [{:name=>"Gad", :ate=>true}, {:name=>"Bad", :ate=>true}]
=> array_two
=> # [{:name=>"Lad", :ate=>false}, {:name=>"Sad", :ate=>false}]
thx #CarySwoveland
I can't compete with partition, but here's another way:
trues = array.select { |h| h[:ate] }
falses = array - trues

Ruby convert array to nested hash

I have the following:
value = 42
array = ["this","is","a","test"]
how can I convert that to get this
{ "this" => { "is" => { "a" => { "test" => 42 } } } }
the array is always flat.
Thank you!
Try this:
array.reverse.inject(value) { |assigned_value, key| { key => assigned_value } }
#=> {"this"=>{"is"=>{"a"=>{"test"=>42}}}}

Resources