From: Daniel Berger Date: 2006-12-14T02:35:05+09:00 Subject: Re: map taking an argument (was: Re: join_with) dblack@wobblini.net wrote: > Hi -- > > On Wed, 6 Dec 2006, Martin DeMello wrote: > > > While golfing with the hex_ip thread, I realised that map takes no > > argument, and join takes no block, leaving a vacuum for a combined > > method: > > Your point about map re-raised a question that was in my head > recently. > > There was an RCR a while back, rejected by Matz, that asked for: > > enum.map(:m) > > to be the same as: > > enum.map {|e| e.m } > > It looks like Ruby >= 1.9 has this: > > enum.map(&:m) > > which strikes me as the same thing, functionally, but visually noisier > and semantically more obscure. > > I'm just wondering what the rationale is for rejecting the simple > version and introducing the less simple one. > > > David Good question. One guess is that they wanted a more generic approach, instead of manually handling specific methods. But that's a guess. This may have been implemented before, but here's something I've been toying with: module Enumerable # Returns the numeric total of the elements of +enum+. # Raises an error if any of the elements are non-numeric. # def sum total = 0 each{ |val| total += val } total end # Returns a new array containing the results of running # +block+ once for every element in the +enum+. Any symbols # passed as arguments are assumed to be methods, and will be # called on every element *before* being yielded to the block. # Non-symbols are assumed to be arguments to those methods. # # Examples: # # array = ['foo', 'bar'] # # array.map(:capitalize) => ['Foo', 'Bar'] # array.map(:+, 'x') => ['foox', 'barx'] # array.map(:+, 'y', :upcase) => ['FOOY', 'BARY'] # def map(*args) array = [] unless block_given? hash = {} key = nil args.each{ |arg| if arg.is_a?(Symbol) key = arg hash[key] = [] else hash[key] << arg end } each{ |obj| hash.each{ |sym, args| if args.empty? obj = obj.send(sym) else obj = obj.send(sym, *args) end } if block_given? yield obj else array << obj end } return array unless block_given? end end class Array # Returns a new array containing the results of running # +block+ once for every element in the +enum+. Any symbols # passed as arguments are assumed to be methods, and will be # called on every element *before* being yielded to the block. # Non-symbols are assumed to be arguments to those methods. # # Examples: # # array = ['foo', 'bar'] # # array.map(:capitalize) => ['Foo', 'Bar'] # array.map(:+, 'x') => ['foox', 'barx'] # array.map(:+, 'y', +upcase) => ['FOOY', 'BARY'] #-- # The Array class actually has its own implementation of # the +map+ method, hence the duplication. # def map(*args) array = [] unless block_given? hash = {} key = nil args.each{ |arg| if arg.is_a?(Symbol) key = arg hash[key] = [] else hash[key] << arg end } each{ |obj| hash.each{ |sym, args| if args.empty? obj = obj.send(sym) else obj = obj.send(sym, *args) end } if block_given? yield obj else array << obj end } return array unless block_given? end end