In trying to grasp the unary & operator in ruby, I ran across [Stupid Ruby Tricks: String#to_proc].
Therefore, I decided I had to further twist the language features to my own will.
Like many things in Ruby with duck-typing, the following syntax:
('a'..'z').map &:upcase
…makes use of the fact that Symbol has a #to_proc method, which means that the following call is an explicit version of the above call.
('a'..'z').map &:upcase.to_proc
If you wanted to allow for a shorthand notation for map, then you could add #to_proc to String, as follows:
class String
def to_proc
eval "Proc.new { |*args| args.first#{self} }"
end
end
This allows for the following call:
[1,2,3].map &'*2' # [2, 4, 6]
…which is equivalent to:
[1,2,3].map { |*args| args.first*2 } # note: no space
…But what if I wanted to specify a library function to have the Array members passed to? (Certainly, this is venturing deeper into solving a problem that doesn’t exist.) Also, what if I want to pass an Array for the arguments?
class String
def to_proc
# assume an initial word character is a library function, otherwise evaluate as before
if /^w/ =~ self
eval "Proc.new { |*args| #{self}(*args.first) }"
else
eval "Proc.new { |*args| args.first#{self} }"
end
end
The above code will expand an embedded Array into an argument list:
[[2,2],[9,3],[64,4]].map &'Math.log' # [1.0, 2.0, 3.0] [1.0, 2.0, 4.0].map &'Math.sqrt' # [1.0, 1.4142135623730951, 1.7320508075688772] [1,2,3].map &'*2' # [2, 4, 6] [[2,2],[9,3],[64,4], 4].map &'Math.log' # [1.0, 2.0, 3.0, 1.3862943611198906]