将Ruby哈希键连接成字符串

3

我正在尝试使用Chef属性动态创建一个 Ruby 模板,但是我无法弄清如何将属性映射到所需的输出方式。

示例哈希:

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

感谢您的帮助。
4个回答

4
如果哈希表的大小不够大而导致抛出栈溢出异常,您可以使用递归。我不知道您试图实现什么,但以下是一个示例,演示如何使用递归:
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

输出:

route.allocation.recovery.speed : 5 
route.allocation.recovery.timeout : 30s
route.allocation.recovery.converge.timeout : 1m 

这看起来不错。使用下面建议的 if v.is_a? Hash 代替 if v.respond_to? 是否更好? - jarsever

1

如果您想转换一个具有多个级别的完整哈希表,那么这是我最终使用的代码:

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"]

1
我不了解Rails,但我猜想以下内容只需要进行小的调整即可得到您想要的结果:
@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"]] 

1

编辑:我是否完全误读了你的问题-所需输出是字符串?哦,亲爱的。

我认为这是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)

输出:

[2] pry(main)> structs.route.allocation.recovery.speed
=> 5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接