将 Ruby 个散列键加入字符串

Join Ruby hash keys into string

我正在尝试使用 Chef 属性动态创建一个 Ruby 模板,但我不知道如何映射属性以按我需要的方式输出。

示例哈希:

a = { 
    "route" => { 
        "allocation" => {
            "recovery" => {
                "speed" => 5,
                "timeout" => "30s"
            },
            "converge" => {
                "timeout" => "1m"
            }
        }
    }
}

会变成:

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

感谢您的帮助。

我不知道 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"]] 

如果您的散列不够大而不会抛出堆栈溢出异常,您可以使用递归。我不知道你想达到什么目的,但这是你如何做到的例子:

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 

编辑:我是否完全误解了您的问题 - 所需的输出是一个字符串吗?亲。

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

对于任何想要转换具有多个级别的整个哈希的人来说,这是我最终使用的代码:

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