2009/7/8 David A. Black <dblack / rubypal.com>

> Hi --
>
>
> On Wed, 8 Jul 2009, James Coglan wrote:
>
>  2009/7/8 Max Williams <toastkid.williams / gmail.com>
>>
>>  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