One of the greatest Ruby mysteries for me has always been the idiomatic Symbol#to_proc which is usually used to cast a symbol to a block usually passed to some enumerator. More concretely, it’s common to see code like this:

class Integer def increment self + 1 end end [ 1 , 2 , 3 ]. map ( & :increment ) #=> [2, 3, 4]

This winds up just being short-hand for something like:

[ 1 , 2 , 3 ]. map { | n | n . increment }

The &:increment syntax is doing two things. First, it is calling Symbol#to_proc which turns the symbol into a proc, or an anonymous function (more on this in a second). Next it treats the resulting Proc as a “block”. In the above code that block is then passed to Array#map where it is executed.

Let’s dig into Symbol#to_proc a bit to figure out what’s actually going on under the hood. In the following code we take the :size symbol and will procify it. Then we’ll apply it to two objects to see what happens:

fn = :size . to_proc #=> #<Proc:...> fn . call ([ 1 , 2 , 3 ]) #=> 3 fn . call ({ name: 'josh' , food: 'pizza' }) #=> 2

So from this example we can see that calling Symbol#to_proc winds up resulting in a something similar to

Proc . new { | receiver | receiver . send ( :size ) }

What if our method can take arguments? For example, let’s say we have a name method that can take the :formal option.

class Person def name ( & block ) block_given? ? 'Mr. Josh' : 'Josh' end end person = Person . new fn = :name . to_proc #=> #<Proc:...> fn . call person #=> 'Josh' fn . call person , formal: true #=> 'Mr. Josh'

Nice, so the proc that is generated can take arguments (blocks too!).

Let’s talk about a practical application now. I was writing some code today where I wanted to create a list of symbols representing methods which I would then enumerate over using Object#public_send to make dynamic calls. Explicitly:

class Person def name 'josh' end def favorite_food 'pizza' end def dog_name 'penny' end end person = Person . new [ :name , :favorite_food , :dog_name ]. map do | sym | person . public_send ( sym ) end #=> ['josh', 'pizza', 'penny']

That was working great for a long time, however then things started to get more complex and I needed to pass arguments to my methods. For example, I wanted to have Person#favorite_food take a :vegetable option. That throws a wrench in things because I can’t really pass arguments on these dynamic calls very easily without doing a branch (e.g. if Symbol... elsif Proc ).

class Person def name 'josh' end def favorite_food ( vegetable: false ) vegetable ? 'broccoli' : 'pizza' end def dog_name 'penny' end end person = Person . new [ :name , :favorite_food , :dog_name , -> { person . favorite_food ( vegetable: true ) } ]. map do | sym_or_proc | case sym_or_proc when Symbol person . public_send ( sym_or_proc ) when Proc sym_or_proc . call end end #=> ['josh', 'pizza', 'penny', 'broccoli']

Or so I thought. As we learned above, Symbol#to_proc creates a proc that takes as an argument the receiver that we want to pass the symbol to as a message. Well, what if we just replace the :favorite_food symbol in our array with a proc that will take the receiver we want to use and pass arguments along. Proc#to_proc just returns the same proc so this should allow us to still use duck-typing to keep things elegant:

class Person def name 'josh' end def favorite_food ( vegetable: false ) vegetable ? 'broccoli' : 'pizza' end def dog_name 'penny' end end person = Person . new [ :name , :favorite_food , :dog_name , -> ( person ) { person . favorite_food ( vegetable: true ) } ]. map do | procable | fn = procable . to_proc fn . call ( person ) end #=> ['josh', 'pizza', 'penny', 'broccoli']

In the above example we use the “stabby-lambda” syntax to define our proc (TL;DR lambdas are a type of Proc ). Since both Proc and Symbol respond to :to_proc then we just call that to normalize the argument into something we can handle generically.