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/