On 6/2/06, Jamie Macey <jamie.macey / gmail.com> wrote:
> > Here's a sample YAML document to get you started:
> >
> >         ---
> >         foo: 1
> >         bar:
> >           baz: [1, 2, 3]
> >           quux: 42
> >           doctors:
> >             - William Hartnell
> >             - Patrick Troughton
> >             - Jon Pertwee
> >             - Tom Baker
> >             - Peter Davison
> >             - Colin Baker
> >             - Sylvester McCoy
> >             - Paul McGann
> >             - Christopher Eccleston
> >             - David Tennant
> >           a: {x: 1, y: 2, z: 3}
>
> Ahh, a nice, quick one.
>
> I had a 7 line method, that became 6 lines, that became 4 lines...
> became 2 really ugly lines if I can include and not count a helper
> method to turn mapped Hashes back into Hashes.
>
> My output, reformatted for prettiness (it also handles Ara's additions):
>
> #<OpenStruct
>   foo=1,
>   bar=#<OpenStruct
>     a=#<OpenStruct z=3, x=1, y=2>,
>     quux=42,
>     doctors=[
>       "William Hartnell",
>       "Patrick Troughton",
>       "Jon Pertwee",
>       "Tom Baker",
>       "Peter Davison",
>       "Colin Baker",
>       "Sylvester McCoy",
>       "Paul McGann",
>       "Christopher Eccleston",
>       "David Tennant"
>     ],
>     baz=[1, 2, 3]
>   >
> >
>
> - Jamie
>

I had two on the go - the clearest code of the ones from Friday (that
just does the simple case) is:

def hash_to_ostruct(hash)
  return hash unless hash.is_a? Hash
  values = {}
  hash.each { |key, value| values[key] = hash_to_ostruct(value) }
  OpenStruct.new(values)
end


To handle MenTaLguY's recursive output, I actually busted in to YAML
for ease of use.

def YAML.load_to_open_struct(yaml)
  hash_to_ostruct(load(yaml))
end

def YAML.hash_to_ostruct(data, memo = {})
  # short-circuit returns so body has less conditionals
  return data unless data.is_a? Hash
  return memo[data.object_id] if memo[data.object_id]

  # log current item in memo hash before recursing
  current = OpenStruct.new
  memo[data.object_id] = current

  # and then recursively populate the current object
  data.each do |key, value|
    current.send(key+'=', hash_to_ostruct(value, memo))
  end
  current
end


Interestingly enough, Facet's Hash#to_ostruct_recurse doesn't seem to
work (stack overflow) for the recursive sample.

- Jamie