garythegoat
garythegoat

Reputation: 1587

Symbol#to_proc with custom methods

I like how in Ruby you can pass methods as blocks like so using Symbol#to_proc:

[1.0, 2.0, 3.0].map(&:to_i)
#=> [1, 2, 3]

I can also define my own lambda, times_two, and pass it as a block as well:

times_two = ->(x) {x * 2}

[1, 2, 3].map(&times_two)
#=> [2, 4, 6]

Though I seemingly cannot pass times_two as a symbol:

[1, 2, 3].map(&:times_two)
#=> ArgumentError: wrong number of arguments (0 for 1)

However when I try to do the same with a method I get an error:

def times_three(x)
  x * 3
end

[1, 2, 3].map(&times_three)
#=> ArgumentError: wrong number of arguments (0 for 1)

[1, 2, 3].map(&:times_three)
#=> ArgumentError: wrong number of arguments (0 for 1)

I'm guessing I can't do this because times_three is a method, not a Proc.

So how can you define custom methods so that they can be used in the Symbol#to_proc fashion like to_i in the first example above?

For example, how can I do this?

[1, 2, 3].map(&:times_three)
#=> [3, 6, 9]

EDIT: I watched the video posted below and apparently you can get close to Symbol#to_proc using the method method:

def times_three(x)
  x * 3
end

t_three = method(:times_three)
[1, 2, 3].map(&t_three)
#=> [3, 6, 9]

However, it's not quite Symbol#to_proc:

[1, 2, 3].map(&:t_three)
#=> NoMethodError: undefined method `t_three' for 1:FixNum

Upvotes: 5

Views: 1405

Answers (3)

rubycademy.com
rubycademy.com

Reputation: 529

You can do this:

[1, 2, 3].map &method(:t_three)

Here is an excellent resource to learn more about this technique.

Upvotes: 0

SteveTurczyn
SteveTurczyn

Reputation: 36860

class Integer
  def times_three
    return self * 3
  end
end

Now, because times_three is now a method of the Integer class, you can do symbol to proc...

[1, 2, 3].map(&:times_three)

If you want to access a method that isn't part of the object's class but acts on an object, you need to pass the object as an argument to the method...

def times_three(x)
  x * 3
end

[1, 2, 3].map{|i| times_three(i) }

the symbol to proc needs to use the object as a receiver.

[1, 2, 3].map(&:some_action)

is equivalent to

[1, 2, 3].map{|i| i.some_action}

Upvotes: 5

doesterr
doesterr

Reputation: 3965

You would have to define times_three on Integer or Numeric.

Symbol to Proc explained by Peter Cooper: https://www.youtube.com/watch?v=aISNtCAZlMg

Upvotes: 2

Related Questions