Hi --
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