Understanding Ruby blocks and the yield keyword
Letโs start by looking at a standard method definition:
def hello_world!
puts "hello world!!!!!"
"๐"
end
This looks like this under the hood:
define_singleton_method :hello_world! do
puts "hello world!!!!!"
"๐"
end
Letโs write our own fancy define_method
method. Note that because weโre in IRB, we need to define on main
, so we use define_singleton_method
:
def our_defined_method(name, &block)
define_singleton_method name do
block.call(name)
end
end
Where we yield
our explicit block
which is passed as a Proc
(&
).
our_defined_method(:hello_universe) do
puts "hello unverise!"
"๐"
end
> hello_universe
# hello unverise!"
"๐"
We can convert our method to a Proc
:
its_really_something = method(:hello_universe)
its_really_something.class # Method
its_really_something.call
# hello universe!
# => ๐
Now that weโve seen blocks, what do we do with them?
def blink
yield
1
end
blink { puts "I blinked." }
# I blinked
# => 1
blink do
puts "I blinked."
end
What about twice?
def blink_twice
yield
yield
2
end
blink { puts "I blinked" }
or,
def blink_times(num)
num.times do
yield
end
num
end
What if we want to send something to our block? We can yield it.
def vanilla_ice
yield "stop"
end
vanilla_ice { |msg| puts "#{msg} collaborate and listen "}
What if we want to capture it?
def favorite_string_method
fav = yield
puts "your favorite map method is #{fav}"
end
favorite_string_method { :to_s }
what if we want to apply our favorite string method?
def apply_favorite_method_to_array(array)
favorite_method = yield
array.map(&favorite_method)
end
apply_favorite_method_to_array([1,2,3]) { :to_s } # => ["1", "2", "3"]
or maybe even return our original yield into another yield:
def changed_my_mind
@favorite = yield
puts "My @favorite map method is #{@favorite}"
return yield @favorite
end
changed_my_mind { "thing" }.then { |fav| puts "Awe yeah it's #{fav} "}