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 T.