Passing block arguments in Ruby
Published at: 2024-11-15
in Ruby, we can pass block argument to an function by prefixing with an &
.
Symbol
a common example of the use of objects that implement to_proc
in Symbol.
["a", "b", "c"].map { |s| s.upcase } # => ["A", "B", "C"]
["a", "b", "c"].map(&:upcase) # => ["A", "B", "C"]
these two lines of code behave identically.
the reason this works is that Symbol
implements the to_proc
method. all it does was take the argument to this proc, and call the method whose name maches this symbol.
we’ll frequently see this syntax as a shortcut fot methods that take simple blocks like map
or sort_by
Make it simpler
we can pass usual do blocks to function, but some times we can make it more simple. let’s see an example.
numbers = 1..5
operator = gets
number = Integer(gets)
if operator.start_with?("t")
puts numbers.collect { |n| n * number }.join(", ")
else
puts numbers.collect { |n| n + number }.join(", ")
end
this code works, but ugly. we can refactor it like this below.
numbers = 1..5
operator = gets
number = Integer(gets)
if operator.start_with?("t")
calc = ->(n) { n * number }
else
calc = ->(n) { n + number }
end
puts numbers.map(&calc).join(", ")
in this version, we assign the correct block to a variable named calc
, then we pass calc to the method map
, prefixing it with &
but there’s a even shorter way to write this code. Ruby object have a method name called method
. which takes a symbol and returns the object’s method of the same name.
operators = get
number = Integer(gets)
method = number.method(operator.start_with?("t") ? :* : :+)
puts (1..5).map(&method).join(", ")
In this case, we’re using method
to grab the method named :+
or :*
based on the input and using the ampersand’s to_proc
powers to create a proc that calls that method.