Symbol#to_proc with arguments

hey folks

I’ve often wondered if i can use Symbol#to_proc with arguments - reading
Dave T.'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?

2009/7/8 Max W. [email protected]

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”]]

Hi –

On Wed, 8 Jul 2009, James C. wrote:

=> [“apple”, “banana”, “peach”, “plum”, “pear”]
and i’m clearly not getting it. Can anyone explain?
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’) }

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’))

though either way I admit it doesn’t feel necessary or adviseable to
me.

David

Thanks guys.

I would automatically shy away from overriding to_proc as it seems like
the sort of thing that would slip a timebomb under my app :slight_smile:

I was just wondering if it was possible as is, not because it’s soooo
much work to write out a proper block, but simply out of curiosity. “No
you can’t” is a good enough answer for me.

What got me wondering actually was using a Ramaze based framework and
missing lots of nice ways that rails extends the core ruby classes (with
Symbol#to_proc being an example). Is it easy to just require all of
these gems/modules and get the same stuff back? I guess i should answer
my own question by just trying it, so feel free to just say “why not try
it and see?”. :slight_smile:

thanks again
max

2009/7/8 James C. [email protected]

Symbol#to_proc makes my head hurt a little bit (it is only 9.16am here)
explicitly when calling #collect.

and will likely perform better.
information. So, an alternative:

class Array
def to_proc
lambda { |o| o.send(first, *self[1…-1]) }
end
end

Silly me, this can actually be written simply as:

class Array
def to_proc
lambda { |o| o.send(*self) }
end
end

What got me wondering actually was using a Ramaze based framework and
missing lots of nice ways that rails extends the core ruby classes (with
Symbol#to_proc being an example). Is it easy to just require all of
these gems/modules and get the same stuff back? I guess i should answer
my own question by just trying it, so feel free to just say “why not try
it and see?”. :slight_smile:

require ‘active_support’

James C. wrote:

What got me wondering actually was using a Ramaze based framework and
missing lots of nice ways that rails extends the core ruby classes (with
Symbol#to_proc being an example). Is it easy to just require all of
these gems/modules and get the same stuff back? I guess i should answer
my own question by just trying it, so feel free to just say “why not try
it and see?”. :slight_smile:

require ‘active_support’

fantastic. thanks!

2009/7/8 David A. Black [email protected]

Dave T.'s explanation on this page
(irb):12: syntax error, unexpected ‘,’, expecting ‘)’

end

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.

On 7/8/09, Max W. [email protected] wrote:

missing lots of nice ways that rails extends the core ruby classes (with
Symbol#to_proc being an example). Is it easy to just require all of
these gems/modules and get the same stuff back? I guess i should answer
my own question by just trying it, so feel free to just say “why not try
it and see?”. :slight_smile:

I am sharing your laziness :wink: and you might want to check out Labrador
http://rubyforge.org/frs/?group_id=3824&release_id=33008 which will
allow you to do things like:

irb(main):001:0> %w{ a,b c,d e,f }.map( :split, “,” )
=> [[“a”, “b”], [“c”, “d”], [“e”, “f”]]

They idea was not to change #to_proc but to enhance the Enumerable
behavior.
But please be warned about Labrador it is not actively maintained.
However you might find some inspiration in the source.

Maybe Facets does some of the things you want, it is a very stable
package.
http://facets.rubyforge.org/

HTH
Robert


Toutes les grandes personnes ont d’abord été des enfants, mais peu
d’entre elles s’en souviennent.

All adults have been children first, but not many remember.

[Antoine de Saint-Exupéry]

Hi –

On Wed, 8 Jul 2009, James C. wrote:

class Symbol
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.

I don’t think that’s right. The existing semantics don’t include any
arguments. So my reaction would be: isn’t that going to raise an
exception? Then I’d have to figure out that you’d probably overridden
then method.

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.

Just rename your override of #to_proc to #to_proc_with_args (or
whatever). It will still work the same. (You’re dispensing with the
automatic calling of #to_proc anyway.)

So, an alternative:

class Array
def to_proc
lambda { |o| o.send(first, *self[1…-1]) }

That doesn’t differ from send(*self), does it?

David