处理嵌套散列以将所有值转换为字符串

Car*_*ham 4 ruby hash ruby-on-rails

我有以下代码,它采用散列并将所有值转换为字符串。

def stringify_values obj
  @values ||= obj.clone

  obj.each do |k, v|
    if v.is_a?(Hash)
      @values[k] = stringify_values(v)
    else
      @values[k] = v.to_s
    end
  end

  return @values
end
Run Code Online (Sandbox Code Playgroud)

所以给定以下哈希:

{
  post: {
    id: 123,
    text: 'foobar',
  }
}
Run Code Online (Sandbox Code Playgroud)

我得到以下YAML输出

--- &1
:post: *1
:id: '123'
:text: 'foobar'
Run Code Online (Sandbox Code Playgroud)

当我想要这个输出时

--- 
:post: 
  :id: '123'
  :text: 'foobar'
Run Code Online (Sandbox Code Playgroud)

看起来对象已被展平,然后被赋予了对自身的引用,这会导致我的规范中出现堆栈级别错误。

如何获得所需的输出?

Wan*_*ker 7

一个更简单的实现stringify_values可以是 - 假设它总是一个哈希。该函数利用Hash#deep_mergeActive Support Core Extensions 添加的方法 - 我们将哈希与其自身合并,以便在块中检查每个值并调用to_s它。

def stringify_values obj
  obj.deep_merge(obj) {|_,_,v| v.to_s}
end
Run Code Online (Sandbox Code Playgroud)

完整的工作样本:

require "yaml"
require "active_support/core_ext/hash"

def stringify_values obj
  obj.deep_merge(obj) {|_,_,v| v.to_s}
end

class Foo
    def to_s
        "I am Foo"
    end
end

h = {
  post: {
    id: 123,
    arr: [1,2,3],
    text: 'foobar',
    obj: { me: Foo.new}
  }
}

puts YAML.dump (stringify_values h)
#=> 
---
:post:
  :id: '123'
  :arr: "[1, 2, 3]"
  :text: foobar
  :obj:
    :me: I am Foo
Run Code Online (Sandbox Code Playgroud)

不确定当 value 是一个数组时的期望是什么,因为Array#to_s也会给你数组作为一个字符串,无论是否需要,你都可以决定并稍微调整一下解决方案。