# \[SOLUTION\] Hash to OpenStruct (#81)

**URL:** <https://www.ruby-forum.com/t/solution-hash-to-openstruct-81/62436>\
**Category:** Ruby\
**Created:** [June 4, 2006, 8:14pm UTC](https://www.ruby-forum.com/t/solution-hash-to-openstruct-81/62436 "2006-06-04T20:14:20Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![MenTaLguY](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/439d5e/32.png) [@MenTaLguY](https://www.ruby-forum.com/u/MenTaLguY)\
**Post date:** [June 4, 2006, 8:14pm UTC](https://www.ruby-forum.com/t/solution-hash-to-openstruct-81/62436/1 "2006-06-04T20:14:20Z")

</div>

I’ve got three.

ATTEMPT #1

My first attempt was pretty simple:

```
    require 'ostruct'

    def hashes_to_openstructs( obj )
      return obj unless Hash === obj
      OpenStruct.new( Hash[
        *obj.inject( [] ) { |a, (k, v)| a.push k, 

```

hashes\_to\_openstructs( v ) }  
] )  
end

The main idea here was to build the OpenStruct all at once, rather than  
resorting to a bunch of Object#send( “#{name}=”, value ) calls. To do  
this, however, we end up going from a hash, to a sequence of pairs, to a  
flat array of alternating keys and values, back to a hash, and then  
finally to an OpenStruct.

ATTEMPT #2:

Then I got bored and decided I’d deal with the case of a self-recursive  
hash. My first attempt used lazy.rb  
( [http://moonbase.rydia.net/software/lazy.rb](http://moonbase.rydia.net/software/lazy.rb) ); I simply made the above  
hashes\_to\_openstructs() function lazy (by wrapping its innards in  
promise {}), then memoized it using a hash:

```
    require 'ostruct'
    require 'lazy'

    def hashes_to_openstructs( obj, memo={} )
      return obj unless Hash === obj
      memo[obj.object_id] ||= promise {
        OpenStruct.new( Hash[
          *obj.inject( [] ) { |a, (k, v)|
            a.push k, hashes_to_openstructs( v, memo )
          }
        ] )
      }
    end

```

ATTEMPT #3:

While that’s sort of clever, I couldn’t help but think there was a  
simpler solution. It involved building the OpenStruct incrementally,  
using the same Object#send calls I’d been hoping to avoid.

```
    def hashes_to_openstructs( obj, memo={} )
      return obj unless Hash === obj
      os = memo[obj] = OpenStruct.new
      obj.each do |k, v|
        os.send( "#{k}=", memo[v] || hashes_to_openstructs( v, memo 

```

) )  
end  
os  
end

Once again, however, memoization wins.

-mental

---

<div class="post-metadata">

**Author:** ![MenTaLguY](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/439d5e/32.png) [@MenTaLguY](https://www.ruby-forum.com/u/MenTaLguY)\
**Post date:** [June 5, 2006, 6:09pm UTC](https://www.ruby-forum.com/t/solution-hash-to-openstruct-81/62436/2 "2006-06-05T18:09:53Z")

</div>

My solution isn’t quite as robust as mental’s (particularly, no  
support for self-reference), but here it is:

class Object  
def to\_openstruct  
self  
end  
end

class Array  
def to\_openstruct  
map{ |el| el.to\_openstruct }  
end  
end

class Hash  
def to\_openstruct  
mapped = {}  
each{ |key,value| mapped[key] = value.to\_openstruct }  
OpenStruct.new(mapped)  
end  
end

module YAML  
def self.load\_openstruct(source)  
self.load(source).to\_openstruct  
end  
end

Usage is simply:

require ‘to\_openstruct’  
p YAML.load\_openstruct(File.read(“sample.yml”)

Jacob F.
