Skip to content

Instantly share code, notes, and snippets.

@royratcliffe
Last active August 29, 2015 14:06
Show Gist options
  • Save royratcliffe/9d821711bd32443d9b08 to your computer and use it in GitHub Desktop.
Save royratcliffe/9d821711bd32443d9b08 to your computer and use it in GitHub Desktop.
Converts a hash to an OpenStruct along with all its nested hashes. The hash and all its sub-hashes become OpenStruct instances in the resulting structure.
require 'ostruct'
class OpenStruct
def self_and_field_pairs
each_pair.map { |field, _| [self, field] }
end
end
class Hash
# Converts a hash to an OpenStruct along with all its nested hashes. The hash
# and all its sub-hashes become OpenStruct instances in the resulting
# structure.
def to_ostruct
top_ostruct = OpenStruct.new(self)
stack = top_ostruct.self_and_field_pairs
until stack.empty?
ostruct, field = stack.pop
case value = ostruct[field]
when Hash
ostruct[field] = sub_ostruct = OpenStruct.new(value)
stack += sub_ostruct.self_and_field_pairs
when Array
# When the field is an array, iterate through all its elements
# replacing all hashes with OpenStruct instances and push the new
# structure's fields to the stack for nested inspection of hashes
# later.
value.each_with_index do |element, index|
case element
when Hash
value[index] = sub_ostruct = OpenStruct.new(element)
stack += sub_ostruct.self_and_field_pairs
end
end
end
end
top_ostruct
end
end
require 'minitest/autorun'
require_relative 'hash_to_ostruct'
class HashToOpenStructTest < Minitest::Test
def test_hash_to_ostruct
hash = {
alpha: 1,
bravo: 2,
charlie: 3,
delta: {
delta_1: {
xray: 'string1',
yankee: 'string2',
zulu: 'string3'
},
delta_2: [
:romeo,
:oscar,
{
yankee: 1.23
}
]
}
}
ostruct = hash.to_ostruct
assert_equal 1, ostruct.alpha
assert_equal 2, ostruct.bravo
assert_equal 3, ostruct.charlie
assert_equal 'string1', ostruct.delta.delta_1.xray
assert_equal 'string2', ostruct.delta.delta_1.yankee
assert_equal 'string3', ostruct.delta.delta_1.zulu
assert_includes ostruct.delta.delta_2, :romeo
assert_includes ostruct.delta.delta_2, :oscar
assert_equal 1.23, ostruct.delta.delta_2[2].yankee
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment