rubyguides

Kernel#iterator?

iterator? -> true or false

The iterator? method (also known as block_given?) checks whether the current context is being called with a block. It returns true if a block was passed to the current method and is available for yielding.

Basic Usage

def my_method
  if iterator?
    yield
  else
    "No block given"
  end
end

my_method              # => "No block given"
my_method { "block!" } # => "block!"

The method checks iterator? at the top and branches immediately. When a block is present, control flows to yield which passes execution back to the caller’s block. When no block is given, the else branch supplies a default return value. This dual-mode pattern is the foundation of many Ruby APIs that offer both a block form and a plain-return form.

Practical Examples

Optional block handling

def process_items(items)
  if iterator?
    items.each { |item| yield(item) }
  else
    items
  end
end

# Without block - returns array
result = process_items([1, 2, 3])  # => [1, 2, 3]

# With block - yields each
result = process_items([1, 2, 3]) { |x| x * 2 }  # => nil (yields)

With a block, the method iterates and yields each element for custom processing. Without one, it returns the items array unchanged. This lets callers treat the method as either a pass-through accessor or a transformer, depending on whether they supply a block. The branching happens at the top so the two paths are easy to compare at a glance.

Conditional feature activation

def find_matches(items)
  matches = []
  items.each do |item|
    if block_given?
      matches << item if yield(item)
    else
      matches << item  # Include all if no block
    end
  end
  matches
end

find_matches([1, 2, 3, 4])              # => [1, 2, 3, 4]
find_matches([1, 2, 3, 4]) { |x| x > 2 } # => [3, 4]

The inner block_given? check decides whether to filter or keep everything. Without a block, the method is a pass-through; with one, it becomes a filter. This is a common pattern in Ruby for methods that offer optional filtering behavior without requiring two separate method names. The same body handles both cases, keeping the API surface small.

API Design

class DataProcessor
  def process(data)
    return enum_for(:process, data) unless block_given?
    
    data.each do |item|
      transformed = yield(item)
      store(transformed)
    end
  end
end

When no block is given, the method returns an Enumerator via enum_for. This lets callers chain the method with other collection operations or use it lazily. The pattern is common in Ruby’s built-in classes: each, map, and select all return an Enumerator when called without a block, giving the caller control over when and how iteration happens.

Default Behavior

def greet
  if block_given?
    yield("World")
  else
    "Hello, World!"
  end
end

greet                              # => "Hello, World!"
greet { |name| "Hi, #{name}!" }   # => "Hi, World!"

The block form customizes the greeting while the default behavior provides a sensible fallback. Yielding "World" to the block lets callers interpolate the name into any format they like without hardcoding the greeting structure. The no-block path returns a fixed string, keeping the simplest use case as short as possible.

Method Names

# Both work identically
iterator?
block_given?

Both names call the same underlying check. block_given? is the more common choice in modern Ruby and reads like a natural question, while iterator? is the legacy name that still works for backward compatibility. Either one can appear in library code, so it helps to recognize both forms.

In conditional expressions

# Common pattern
def compute
  if block_given?
    yield
  else
    default_value
  end
end

The if block_given? guard at the top of a method is one of the most common Ruby patterns. It keeps the branching short and visible, so anyone reading the method can see both paths immediately. The pattern works well when the block and non-block code paths are each only a few lines.

With enum_for

def each_item(items)
  return enum_for(__method__, items) unless block_given?
  
  items.each { |item| yield item }
end

# Now works without block
enum = each_item([1, 2, 3])
puts enum.first  # => 1

This method is fundamental to Ruby’s block and iterator system, enabling methods to work both with and without blocks.

checking for a block intentionally

iterator? is a small but helpful guard when a method can behave differently depending on whether a block was supplied.

def safe_yield
  if block_given?
    yield
  else
    "default result"
  end
end

safe_yield { "custom" } # => "custom"
safe_yield               # => "default result"

It lets the method choose between returning an enumerator, yielding work, or falling back to a default response. That makes public APIs feel flexible without hiding the control flow. In practice, the clearest code still keeps the block branch short and obvious so the caller can see which path will run.

This pattern is also helpful when you want one method to serve both direct calls and block-driven calls without duplicating the setup logic. The block check can sit near the top of the method, which gives the reader a clear fork in the path before any real work begins. That is a clean way to support Ruby’s block style while still keeping the method predictable. When the block branch becomes too large, the API often benefits from splitting the behavior into smaller pieces instead of growing the conditional. For more on block patterns, see Kernel#yield_self.

Examples also become easier to understand easier to understand because the method can show both modes in one place. One call path returns an ordinary value, while the other yields to custom logic. That dual behavior is useful, but it should stay easy to trace. A short block branch and a sensible fallback keep the method approachable for anyone reading it later.

A good reminder here is that API shape matters. When a method may be used with or without a block, the code can speak clearly about both cases instead of hiding the fallback behavior in a separate helper. That keeps examples compact and makes the block-friendly design feel intentional. The result is an interface that still behaves like ordinary Ruby, even when it offers a little extra flexibility.

In practice, this pattern helps small library methods feel welcoming. The caller can use the method in the simplest way possible, and later decide to pass a block when custom behavior is needed. That makes the method feel adaptable without adding extra method names or separate entry points for the same core idea.

The block-aware design keeps examples honest because the same method can show a default path and a custom path without inventing a second API. That is often enough for small helpers and iterator-style methods. When the reader can see both cases close together, the feature feels easier to approach.

# A method that works with or without a block
def wrap(tag, &block)
  if block
    "<#{tag}>#{block.call}</#{tag}>"
  else
    "<#{tag} />"
  end
end

wrap("div") { "content" }  # => "<div>content</div>"
wrap("br")                  # => "<br />"

See Also