2010/2/28 Glenn Ritz <glenn_ritz / yahoo.com>:
> Robert Klemme wrote:
>> 2010/2/24 Xavier Noria <fxn / hashref.com>:
>>>>>
>>>> {'en' => {'A' => Fixnum, 'B' => {'C' => Fixnum, 'D' => String }}
>>>  newh[k] = v.is_a?(Hash) ? classify_values(v) : v.class
>>> end
>>> newh
>>> end
>>>
>>> p classify_values({'en' => {'A' => 1, 'B' => {'C' => 3, 'D' => 'four' }}})
>>
>> I would do it a tad differently:
>>
>> def classify(o)
>>  case o
>>  when Hash
>>   h = {}
>>   o.each {|k,v| h[k] = classify(v)}
>>   h
>>  else
>>   o.class
>>  end
>> end
>>
>> Advantage is that you can stuff anything in the method while your
>> variant requires the argument to be a Hash. The difference may seem
>> subtle but if you add more collection types for special treatment,
>> you'll will notice a difference in effort to implement it. I can
>> simply do
>>
>> def classify(o)
>>  case o
>>  when Hash
>>   h = {}
>>   o.each {|k,v| h[k] = classify(v)}
>>   h
>>  when Array
>>   o.map {|v| classify(v)}
>>  else
>>   o.class
>>  end
>> end
>>
>> while you need to do a more complicated code change.
>>
>> Kind regards
>>
>> robert
>
> Thanks, this is very helpful.
>
> I am trying to adapt this a bit, but with no luck so far.
>
> What I'd like to do is to start with a hash and have the above code be
> additive.
>
> In other words, if I have the following code:
>
> h0 = {}
> h1 = {'en' => {'A' => 5, 'B' => { 'C' => 'xxx', 'D' => { 'E' => 4 }}}}
> h2 = {'en' => {'F' => 'yyy'}}
>
>
> I'd like to be able to call the classify method like this:
>
> puts h0.classify(h1).classify(h2).inspect
>
> And get the following result:
>
> {'en' => {'A' => Fixnum, 'B' => { 'C' => String, 'D' => { 'E' => Fixnum
> }}, 'F' => String }}
>
> So I figured it would be something like this:
>
> class Hash
> def classify(o)
>  case o
>  when Hash
>   h = self
>   o.each {|k,v| h[k] = classify(v)}
>   h
>  when Array
>   o.map {|v| classify(v)}
>  else
>   o.class
>  end
> end
> end
>
> But this is probably wrong in a few ways. Any suggestions would be
> appreciated.

I would separate this in two steps:

1. merge Hashes intelligently (i.e. with a bit more logic than
Hash#merge default behavior).

2. classify.

So this would probably be something like

class Hash
  def merge_deep!(hs)
    merge! hs do |key,old_val,new_val|
      case old_val
      when Hash
        old_val.merge_deep! new_val
      else
        new_val
      end
    end
  end
end

see
http://www.ruby-doc.org/ruby-1.9/classes/Hash.html#M000406

Kind regards

robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/