On Jun 15, 2006, at 9:40 PM, Elliot Temple wrote:

> http://blog.hasmanythrough.com/articles/read/8
>
> this link suggests a way to hack Symbol to allow
>
> [1, 2, 3].map(&:to_s)   # => ["1", "2", "3"]
>
> my question is how to change the hack to work correctly for other  
> methods. details of the problem are below:
>
> it doesn't work for reversing arrays:
>
> curi-g5:~ curi$ ruby -v
> ruby 1.8.4 (2005-12-24) [powerpc-darwin8.5.0]
>
> irb(main):017:0> class Symbol
> irb(main):018:1>   def to_proc
> irb(main):019:2>     Proc.new { |obj, *args| obj.send(self, *args) }
> irb(main):020:2>   end
> irb(main):021:1> end
> => nil
> irb(main):022:0> [[1,2,3], [4,5,6], [7,8,9]].map {|i| i.reverse}
> => [[3, 2, 1], [6, 5, 4], [9, 8, 7]]
>
> irb(main):023:0> [[1,2,3], [4,5,6], [7,8,9]].map &:reverse
> NoMethodError: undefined method `reverse' for 1:Fixnum
>         from (irb):19:in `send'
>         from (irb):19:in `to_proc'
>         from (irb):23
>         from (null):0
>
>
> the problem is that *args is capturing part of the array. here's  
> the same thing happening without the Symbol hack involved:
>
> irb(main):024:0> [[1,2,3], [4,5,6], [7,8,9]].map {|i, *args|  
> i.reverse}
> NoMethodError: undefined method `reverse' for 1:Fixnum
>         from (irb):24
>         from (irb):24
>         from (null):0
>
>
> so how should the Symbol hack be redone to work properly?
>
> just removing *args is no good. here is an example that needs *args:
>
> irb(main):027:0> class Fixnum
> irb(main):028:1> def foo x
> irb(main):029:2> self+x
> irb(main):030:2> end
> irb(main):031:1> end
> => nil
> irb(main):032:0> { 1=>2, 3=>4}.map &:foo
> => [3, 7]
>
>
> so to illustrate what happens without *args: it solves one problem  
> while creating another:
>
> irb(main):039:0> class Symbol
> irb(main):040:1>   def to_proc
> irb(main):041:2>     Proc.new { |obj| obj.send(self) }
> irb(main):042:2>   end
> irb(main):043:1> end
> => nil
> irb(main):044:0> [[1,2,3], [4,5,6], [7,8,9]].map &:reverse  # works  
> now!
> => [[3, 2, 1], [6, 5, 4], [9, 8, 7]]
>
> irb(main):045:0> { 1=>2, 3=>4}.map &:foo  # breaks now!
> NoMethodError: undefined method `foo' for [1, 2]:Array
>         from (irb):41:in `send'
>         from (irb):41:in `to_proc'
>         from (irb):45:in `map'
>         from (irb):45
>         from :0
>
>
> -- Elliot Temple
> http://www.curi.us/blog/
>
>
>
>

Yeah I don't believe it's possible to have this work both ways.

You could do

class Symbol
   def unary_meth
     lambda { |obj| obj.send(self) }
   end

   def nary_meth
     lambda { |obj, *args| obj.send(self, *args) }
   end
end

[[1,2,3], [4,5,6]].map &:reverse.unary_meth

{ 1=2, 3=>4 }.map &:foo.nary_meth

This is one of those cases where you can't have your cake and eat it  
too.