100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Ruby

yield and block_given?

Understand how `yield` invokes an implicit block passed to a method, and how `block_given?` lets methods branch based on whether a block was supplied.

Methods & BlocksIntermediate8 min readJul 9, 2026
Analogies

yield and block_given?

The yield keyword is how a Ruby method invokes the block that was passed to it, without ever naming that block as a formal parameter. When a method body contains yield, calling that method with { ... } or do...end attached hands control to the block at the point yield appears, optionally passing values into the block and receiving back whatever the block evaluates to. block_given? is a companion method that returns true or false depending on whether the current method call actually received a block, letting you write methods that behave one way with a block and another way without one -- exactly how many Enumerable methods return an Enumerator when called without a block.

🏏

Cricket analogy: yield is like a captain handing the ball to whichever bowler is warmed up in the nets without naming them in the team sheet -- the moment yield is reached, control passes to that bowler's over; block_given? is like checking beforehand whether a bowler is actually available before handing over the ball, avoiding an empty over.

Basic yield mechanics

Calling yield transfers control to the attached block as if it were an inline call to that block; any arguments given to yield become the block's parameters, and the value the block evaluates to becomes the value of the yield expression itself. This is how methods like each or times hand each element or index to the caller's block one at a time.

🏏

Cricket analogy: Calling yield is like the umpire signaling 'over' and immediately handing the ball to the bowler marked in the lineup -- whatever figures that bowler returns (wickets, runs conceded) becomes the over's result, the same way each hands one delivery at a time to the block.

ruby
def three_times
  yield 1
  yield 2
  yield 3
end

three_times { |n| puts "Got #{n}" }

def transform(value)
  result = yield(value)
  "Transformed: #{result}"
end

transform(5) { |v| v * v }   # => "Transformed: 25"

Guarding with block_given?

Calling yield when no block was passed raises a LocalJumpError. block_given? prevents that by checking, before yielding, whether the caller actually attached a block. This pattern is extremely common in the standard library: methods like Array#each return an Enumerator (via enum_for or to_enum) when called without a block, so they can still be chained with .with_index, .lazy, or converted to an array later.

🏏

Cricket analogy: Calling yield with no bowler assigned is like an umpire calling for an over with an empty bowling attack -- a LocalJumpError-style breakdown; block_given? checks the lineup first, and Array#each returning an Enumerator without a block is like a scorer producing a blank scoresheet template ready to be filled and chained with .with_index later.

ruby
def process(items)
  return enum_for(:process, items) unless block_given?

  items.each { |item| yield item.upcase }
end

process(["a", "b"]) { |x| puts x }   # prints A, B
enum = process(["a", "b"])           # no block -> returns an Enumerator
enum.next                            # => "A"

You can also capture a block explicitly as a Proc by adding &block as the last parameter in the method signature, then call it with block.call instead of yield. This is slightly slower than yield but is necessary when you need to pass the block onward to another method or store it for later use.

yield and an explicit &block parameter both refer to the same block, but mixing them without care can be confusing -- e.g. defining def m(&block); yield; end works, but relying on both block_given? and block.nil? interchangeably can mask subtle bugs if someone explicitly passes &nil. Prefer one consistent style per method.

Passing multiple values and destructuring

When yield passes multiple values, the block can destructure them across multiple parameters, mirroring how each_pair or each_with_index hand back a key/value or element/index pair. If the block declares fewer parameters than yielded values, the extras are simply dropped; if it declares more, the missing ones become nil, following the same lenient arity rules as Procs.

🏏

Cricket analogy: When yield passes both a batter and their score, the block destructures them across two parameters, mirroring how each_pair hands back a name and average together; if the block only takes one parameter the score is simply dropped, and if it declares an extra one, it's just nil, like an unused column on the scorecard.

ruby
def each_coordinate
  yield 0, 0
  yield 1, 2
  yield 3, 4
end

each_coordinate { |x, y| puts "(#{x}, #{y})" }
  • yield invokes the block implicitly attached to the current method call, passing arguments and returning the block's result.
  • Calling yield when no block was given raises LocalJumpError -- guard with block_given? first.
  • enum_for(:method_name, *args) (or to_enum) is the idiomatic way to return an Enumerator when no block is supplied.
  • An explicit &block parameter captures the block as a Proc object, useful for forwarding it to another method.
  • Yielded values destructure into block parameters just like Proc arguments, following lenient arity rules.
  • This yield/block_given? pattern underlies nearly every dual-mode Enumerable method in Ruby's standard library.

Practice what you learned

Was this page helpful?

Topics covered

#Ruby#RubyStudyNotes#Programming#YieldAndBlockGiven#Yield#Block#Given#Mechanics#StudyNotes#SkillVeris