From: James Coglan Date: 2009-07-08T20:39:08+09:00 Subject: Re: Symbol#to_proc with arguments --001636988a0bb468bb046e302f68 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit 2009/7/8 David A. Black > Hi -- > > > On Wed, 8 Jul 2009, James Coglan wrote: > > 2009/7/8 Max Williams >> >> hey folks >>> >>> I've often wondered if i can use Symbol#to_proc with arguments - reading >>> Dave Thomas's explanation on this page >>> http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html it >>> looks like i would be able to do this: >>> >>> array = %w(apple banana peach plum pear) >>>>> >>>> => ["apple", "banana", "peach", "plum", "pear"] >>> >>>> array.collect(&:split, 'l') >>>>> >>>> SyntaxError: compile error >>> (irb):12: syntax error, unexpected ',', expecting ')' >>> array.collect(&:split, 'l') >>> ^ >>> (irb):12: syntax error, unexpected ')', expecting $end >>> from (irb):12 >>> >>> But it fails as you can see. Trying to fully grasp what's going on with >>> Symbol#to_proc makes my head hurt a little bit (it is only 9.16am here) >>> and i'm clearly not getting it. Can anyone explain? >>> >> >> >> >> The block argument (prefixed with '&') must be the last argument in the >> list >> when calling a method, so passing 'l' in your example is not valid syntax. >> You could rewrite Symbol#to_proc to take arguments, and call #to_proc >> explicitly when calling #collect. >> >> class Symbol >> def to_proc(*args) >> lambda { |o| o.__send__(self, *args) } >> end >> end >> >> %w[apple banana peach plum pear].collect &:split.to_proc('l') >> #=> [["app", "e"], ["banana"], ["peach"], ["p", "um"], ["pear"]] >> > > That's going to be incomprehensible, except by guesswork, to anyone > who doesn't know that you've modified Symbol. It also undoes whatever > benefit you might get from the &obj idiom automatically calling > #to_proc. I'd just do: > > array.map {|e| e.split('l') } I wouldn't say it's incomprehensible since it maintains the existing semantics of Symbol#to_proc. The explicit block version is shorter though, and will likely perform better. No real reason to second-guess Ruby on this. If you really want to > modify Symbol, creating an entirely new method would probably be > better: > > array.map(&:split.to_argument_accepting_proc('l')) The real problem here is that a Symbol contains a single piece of information, whereas we want to build a Proc from several pieces of information. So, an alternative: class Array def to_proc lambda { |o| o.__send__(first, *self[1..-1]) } end end %w[apple banana peach plum pear].collect &[:split, 'l'] #=> [["app", "e"], ["banana"], ["peach"], ["p", "um"], ["pear"]] It's still not a huge saving over the explicit block, but I think it's worth knowing how you can manipulate the language for times when it becomes *really* useful. -- James Coglan http://jcoglan.com --001636988a0bb468bb046e302f68--