2008/8/21 Pe, Botp <botp / delmonte-phil.com>:
> From: Brian Ross [mailto:p.brian.ross / gmail.com]
> # I'd imagine that this would return map as a new hash with the
> # keys modified. Is there anything like collect! for hashes?
>
> the required pairings for hashes makes it fragile to implement a map/collect like feature similar to plain arrays.
>
> you can create one if you like. just be careful.
>
> eg, here is my simple-minded implementation,
>
> irb(main):084:0> class Hash
> irb(main):085:1> def map2
> irb(main):086:2>   h={}
> irb(main):087:2>   self.each do |k,v|
> irb(main):088:3*      kk,vv=yield(k,v)
> irb(main):089:3>      key = kk || k
> irb(main):090:3>      val = vv || v
> irb(main):091:3>      h[key] = val
> irb(main):092:3>   end
> irb(main):093:2>   h
> irb(main):094:2> end
> irb(main):095:1> end
> => nil

I'd like to use that bit for a small discussion if you allow. I
believe the implementation would be better off by not messing with
return values from the block because the changes lead to more complex
code and results may be surprising (i.e. if you relied on returning
nil or false and expected that to show up in the new Hash).  By having
the method do less things it becomes more flexible to use.

Another interesting question is which is the proper method for
creating the new Hash?  I can think at least of these as reasonable
solutions

h = {}
h = Hash.new(default)
h = Hash.new(&default_proc)
h = default_proc ? Hash.new(&default_proc) : Hash.new(default)
h = self.class.new
h = self.class.new(default)
h = self.class.new(&default_proc)
h = dup.clear

The solution might be to do

def map2(h = {})
  each do |k,v|
    k, v = yield k, v
    h[k] = v
  end
  h
end

i.e. allow the caller to decide where he wants the mapped data to go
while defaulting to the most straightforward case, a new Hash. This is
similar to what Enumerable#map does, i.e. it creates a new Array
regardless of the type at hand.

Kind regards

robert

-- 
use.inject do |as, often| as.you_can - without end