--NcGNjYRALciT9AJugFG
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

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 ); 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 )nd
          os
        end
        
Once again, however, memoization wins.

-mental

--NcGNjYRALciT9AJugFG
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQBEgyKzSuZBmZzm14ERAsH5AKC0LGvFBz7lZYNq6j7gxFzjcUka1wCguHUl
aa5GGbiurDeN43S9jbz6k4E
Xa -----END PGP SIGNATURE----- --NcGNjYRALciT9AJugFG--