如何将 recursive/nested OpenStruct 对象转换为哈希
How to convert recursive/nested OpenStruct Object to Hash
我有一个 OpenStruct 对象,需要转换为 JSON 数据。
样本哈希(来自 RSPEC 助手):
def test_order
{
"id": 505311428702,
"email": "test@gmail.com",
"closed_at": "",
"discount_codes": {
"id": 507328175,
"text": "test"
}
}
end
我正在使用以下递归函数:
def to_recursive_ostruct(hash)
OpenStruct.new(hash.each_with_object({}) do |(key, val), memo|
memo[key] = val.is_a?(Hash) ? to_recursive_ostruct(val) : val
end)
end
对于前 to_recursive_ostruct(test_order),将 return:
<OpenStruct id=505311428702, email="test@gmail.com", closed_at="", ...>
转换后,使用OpenStructObject.marshal_dump:
{
:id=>505311428702, :email=>"test@gmail.com", :closed_at=>"",
discount_codes=>#<OpenStruct id=507328175, text= "test">}
}
OpenStructObject.marshal_dump 在第一级给我正确的数据,
我还想转换嵌套数据。
我真正需要的是这样的:
{:id=>505311428702, :email=>"test@gmail.com", :closed_at=>"", :discount_codes=>{:id=>507328175, :text=> "test"} }
请帮忙,提前致谢。
查看 docs。
您可以使用 OpenStruct#marshal_dump
:
openstruct_object.marshal_dump
OpenStruct#to_h
也可以:
openstruct_object.to_h
您可以将您的对象转换为散列,然后散列为 JSON:
openstruct_object.to_h.to_json
但看起来你想要的是一个 Hash 对象,而不是 JSON 对象。
要将深度 openstruct 转换为散列,您可以采用以下方法:
def deep_openstruct_to_hash(object)
object.each_pair.with_object({}) do |(key, value), hash|
hash[key] = value.is_a?(OpenStruct) ? deep_openstruct_to_hash(value) : value
end
end
然后:
openstruct_object = to_recursive_ostruct(test_order)
#=> #<OpenStruct id=505311428702, email="test@gmail.com", closed_at="", discount_codes=#<OpenStruct id=507328175, text="test">>
deep_openstruct_to_hash(openstruct_object)
# {
# :id=>505311428702,
# :email=>"test@gmail.com",
# :closed_at=>"",
# :discount_codes=>{
# :id=>507328175,
# :text=>"test"
# }
# }
也感谢这个gist:
也可以转换哈希数组。
def recursive_ostruct(object)
case object
when Hash
hash = {}; object.each{|k,v| hash[k] = recursive_ostruct(v)}
OpenStruct.new(hash)
when Array
object.map {|e| recursive_ostruct(e) }
else
object
end
end
在 Ruby 2.4+ 上,您可以将 transform_values
与猴子补丁中的递归函数一起使用。
class OpenStruct
def deep_to_h
to_h.transform_values do |v|
v.is_a?(OpenStruct) ? v.deep_to_h : v
end
end
end
或者如果你不想猴子补丁
def deep_to_h(obj)
obj.to_h.transform_values do |v|
v.is_a?(OpenStruct) ? deep_to_h(v) : v
end
end
在 @Andrey-Deineko、@owyongsk、@aldrien.h 完成的工作的基础上,这是一个处理数组的转换器。虽然 OP 并没有特别关注这一点,但其他人可能会发现它有帮助。
def openstruct_to_h(object)
object.to_h.transform_values do |value|
value.is_a?(OpenStruct) ? openstruct_to_h(value) : value.is_a?(Array) ? value.map{|v| v.is_a?(String) ? v : openstruct_to_h(v) } : value
end
end
# Example usage
open_struct_object = OpenStruct.new(paramtest: "ok", array_test: [OpenStruct.new(array_one: true), OpenStruct.new(array_two: false, nested_os: OpenStruct.new(works: 'maybe'))], os_test: OpenStruct.new(testy: "yup"))
openstruct_to_h(open_struct_object)
=> {:paramtest=>"ok", :array_test=>[{:array_one=>true}, {:array_two=>false, :nested_os=>{:works=>"maybe"}}], :os_test=>{:testy=>"yup"}}
我有一个 OpenStruct 对象,需要转换为 JSON 数据。
样本哈希(来自 RSPEC 助手):
def test_order
{
"id": 505311428702,
"email": "test@gmail.com",
"closed_at": "",
"discount_codes": {
"id": 507328175,
"text": "test"
}
}
end
我正在使用以下递归函数:
def to_recursive_ostruct(hash)
OpenStruct.new(hash.each_with_object({}) do |(key, val), memo|
memo[key] = val.is_a?(Hash) ? to_recursive_ostruct(val) : val
end)
end
对于前 to_recursive_ostruct(test_order),将 return:
<OpenStruct id=505311428702, email="test@gmail.com", closed_at="", ...>
转换后,使用OpenStructObject.marshal_dump:
{
:id=>505311428702, :email=>"test@gmail.com", :closed_at=>"",
discount_codes=>#<OpenStruct id=507328175, text= "test">}
}
OpenStructObject.marshal_dump 在第一级给我正确的数据,
我还想转换嵌套数据。
我真正需要的是这样的:
{:id=>505311428702, :email=>"test@gmail.com", :closed_at=>"", :discount_codes=>{:id=>507328175, :text=> "test"} }
请帮忙,提前致谢。
查看 docs。
您可以使用 OpenStruct#marshal_dump
:
openstruct_object.marshal_dump
OpenStruct#to_h
也可以:
openstruct_object.to_h
您可以将您的对象转换为散列,然后散列为 JSON:
openstruct_object.to_h.to_json
但看起来你想要的是一个 Hash 对象,而不是 JSON 对象。
要将深度 openstruct 转换为散列,您可以采用以下方法:
def deep_openstruct_to_hash(object)
object.each_pair.with_object({}) do |(key, value), hash|
hash[key] = value.is_a?(OpenStruct) ? deep_openstruct_to_hash(value) : value
end
end
然后:
openstruct_object = to_recursive_ostruct(test_order)
#=> #<OpenStruct id=505311428702, email="test@gmail.com", closed_at="", discount_codes=#<OpenStruct id=507328175, text="test">>
deep_openstruct_to_hash(openstruct_object)
# {
# :id=>505311428702,
# :email=>"test@gmail.com",
# :closed_at=>"",
# :discount_codes=>{
# :id=>507328175,
# :text=>"test"
# }
# }
也感谢这个gist: 也可以转换哈希数组。
def recursive_ostruct(object)
case object
when Hash
hash = {}; object.each{|k,v| hash[k] = recursive_ostruct(v)}
OpenStruct.new(hash)
when Array
object.map {|e| recursive_ostruct(e) }
else
object
end
end
在 Ruby 2.4+ 上,您可以将 transform_values
与猴子补丁中的递归函数一起使用。
class OpenStruct
def deep_to_h
to_h.transform_values do |v|
v.is_a?(OpenStruct) ? v.deep_to_h : v
end
end
end
或者如果你不想猴子补丁
def deep_to_h(obj)
obj.to_h.transform_values do |v|
v.is_a?(OpenStruct) ? deep_to_h(v) : v
end
end
在 @Andrey-Deineko、@owyongsk、@aldrien.h 完成的工作的基础上,这是一个处理数组的转换器。虽然 OP 并没有特别关注这一点,但其他人可能会发现它有帮助。
def openstruct_to_h(object)
object.to_h.transform_values do |value|
value.is_a?(OpenStruct) ? openstruct_to_h(value) : value.is_a?(Array) ? value.map{|v| v.is_a?(String) ? v : openstruct_to_h(v) } : value
end
end
# Example usage
open_struct_object = OpenStruct.new(paramtest: "ok", array_test: [OpenStruct.new(array_one: true), OpenStruct.new(array_two: false, nested_os: OpenStruct.new(works: 'maybe'))], os_test: OpenStruct.new(testy: "yup"))
openstruct_to_h(open_struct_object)
=> {:paramtest=>"ok", :array_test=>[{:array_one=>true}, {:array_two=>false, :nested_os=>{:works=>"maybe"}}], :os_test=>{:testy=>"yup"}}