Hi --
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.
···
2009/7/8 David A. Black <dblack@rubypal.com>
On Wed, 8 Jul 2009, James Coglan wrote:
2009/7/8 Max Williams <toastkid.williams@gmail.com>
--
James Coglan
http://jcoglan.com