Как преобразовать хэш в структуру в ruby?
Учитывая это:
h = { :a => 1, :b => 2 }
Мне нужна такая структура, что:
s.a == 1
s.b == 2
Как преобразовать хэш в структуру в ruby?
Учитывая это:
h = { :a => 1, :b => 2 }
Мне нужна такая структура, что:
s.a == 1
s.b == 2
Если это не обязательно должно быть Struct
и вместо этого может быть OpenStruct
:
pry(main)> require 'ostruct'
pry(main)> s = OpenStruct.new(h)
=> #<OpenStruct a=1, b=2>
pry(main)> puts s.a, s.b
1
2
Если у вас уже определена структура, и вы хотите создать экземпляр экземпляра с хешем:
Person = Struct.new(:first_name, :last_name, :age)
person_hash = { first_name: "Foo", last_name: "Bar", age: 29 }
person = Person.new(*person_hash.values_at(*Person.members))
=> #<struct Person first_name="Foo", last_name="Bar", age=29>
Так как порядок ключей Hash гарантирован в Ruby 1.9 +:
Struct.new(*h.keys).new(*h.values)
Следующее создает структуру из хэша надежным способом (поскольку хэш-порядок не гарантируется в ruby):
s = Struct.new(*(k = h.keys)).new(*h.values_at(*k))
Имея Hash#to_struct
вполне практично:
class Hash
def to_struct
Struct.new(*keys).new(*values)
end
end
И некоторые примеры:
>> { a: 1, b: 2 }.to_struct
=> #<struct a=1, b=2>
>> { a: 1, b: 2 }.to_struct.a
=> 1
>> { a: 1, b: 2 }.to_struct.b
=> 2
>> { a: 1, b: 2 }.to_struct.c
NoMethodError: undefined method `c` for #<struct a=1, b=2>
Deep to_struct
, который работает с массивами:
class Array
def to_struct
map { |value| value.respond_to?(:to_struct) ? value.to_struct : value }
end
end
class Hash
def to_struct
Struct.new(*keys).new(*values.to_struct)
end
end
Здесь приведен пример сопоставления значений с правильным порядком Struct:
require 'securerandom'
Message = Struct.new(:to, :from, :message, :invitee)
message_params = {from: "[email protected]", to: "[email protected]",
invitee: SecureRandom.uuid, message: "hello"}
if Message.members.sort == message_params.keys.sort
# Do something with the return struct object here
Message.new *Message.members.map {|k| message_params[k] }
else
raise "Invalid keys for Message"
end
require 'ds_hash'
data = {a: {b: 123 }}.to_struct
data.a.b == 123 # true
data.a == {b: 123 } # true