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.