In Ruby, when you are putting yield
keyword inside any method(say #bar
), you are explicitly telling #bar
that, you will be using a block with the method #bar
. So yield
knows, inside the method block will be converted to a Proc
object, and yield
have to call that Proc
object.
Example :
def bar
yield
end
p bar { "hello" } # "hello"
p bar # bar': no block given (yield) (LocalJumpError)
In the
uniq_by
method, we did not do anything to handle block argument. How is the passed argument handled byuniq_by
method?
You did do, that is you put yield
. Once you will put this yield
, now method is very smart to know, what it supposed to so. In the line Messages.all.uniq_by { |h| h.body }
you are passing a block { |h| h.body }
, and inside the method definition of uniq_by
, that block has been converted to a Proc
object, and yield
does Proc#call
.
Proof:
def bar
p block_given? # true
yield
end
bar { "hello" } # "hello"
Better for understanding :
class Array
def uniq_by
seen = Set.new
select{ |x| seen.add?( yield( x ) ) }
end
end
is same as
class Array
def uniq_by
seen = Set.new
# Below you are telling uniq_by, you will be using a block with it
# by using `yield`.
select{ |x| var = yield(x); seen.add?(var) }
end
end
Read the doc of yield
Called from inside a method body, yields control to the code block (if any) supplied as part of the method call. If no code block has been supplied, calling
yield
raises an exception.yield
can take an argument; any values thus yielded are bound to the block's parameters. The value of a call toyield
is the value of the executed code block.