I'm trying to create a Ruby template on the fly with Chef attributes but I can't figure out how to map the attributes to output the way I need.
Example Hash:
a = {
"route" => {
"allocation" => {
"recovery" => {
"speed" => 5,
"timeout" => "30s"
},
"converge" => {
"timeout" => "1m"
}
}
}
}
Would turn into:
route.allocation.recovery.speed: 5
route.allocation.recovery.timeout: 30s
route.allocation.converge.timeout: 1m
Thanks for the help.
You can use recursion if your hash is not large enough to throw stack overflow exception. I don't know what are you trying to achieve, but this is example of how you can do it:
a = {
"route" => {
"allocation" => {
"recovery" => {
"speed" => 5,
"timeout" => "30s"
},
"converge" => {
"timeout" => "1m"
}
}
}
}
def show hash, current_path = ''
hash.each do |k,v|
if v.respond_to?(:each)
current_path += "#{k}."
show v, current_path
else
puts "#{current_path}#{k} : #{v}"
end
end
end
show a
Output:
route.allocation.recovery.speed : 5
route.allocation.recovery.timeout : 30s
route.allocation.recovery.converge.timeout : 1m
I don't know Rails but I'm guessing that the following requires only a small tweak to give the result you want:
@result = []
def arrayify(obj, so_far=[])
if obj.is_a? Hash
obj.each { |k,v| arrayify(v, so_far+[k]) }
else
@result << (so_far+[obj])
end
end
arrayify(a)
@result
#=> [["route", "allocation", "recovery", "speed", 5],
# ["route", "allocation", "recovery", "timeout", "30s"],
# ["route", "allocation", "converge", "timeout", "1m"]]
EDIT: Did I completely misread your question - is the desired output a string? Oh dear.
I think this is a really good use case for OpenStruct :
require 'ostruct'
def build_structs(a)
struct = OpenStruct.new
a.each do |k, v|
if v.is_a? Hash
struct[k] = build_structs(v)
else
return OpenStruct.new(a)
end
end
struct
end
structs = build_structs(a)
output:
[2] pry(main)> structs.route.allocation.recovery.speed
=> 5
For anyone wanting to convert an entire hash with multi levels then here is the code I ended up using:
confHash = {
'elasticsearch' => {
'config' => {
'discovery' => {
'zen' => {
'ping' => {
'multicast' => {
'enabled' => false
},
'unicast' => {
'hosts' => ['127.0.0.1']
}
}
}
}
}
}
}
def generate_config( hash, path = [], config = [] )
hash.each do |k, v|
if v.is_a? Hash
path << k
generate_config( v, path, config )
else
path << k
if v.is_a? String
v = "\"#{v}\""
end
config << "#{path.join('.')}: #{v}"
end
path.pop
end
return config
end
puts generate_config(confHash['elasticsearch']['config'])
# discovery.zen.ping.multicast.enabled: false
# discovery.zen.ping.unicast.hosts: ["127.0.0.1"]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.