
June 15, 2026
Ruby is full of delightful surprises.
Even after years of writing Ruby professionally, I still occasionally stumble upon a feature that makes me stop and think:
“Wait… Ruby can do that?”
Recently, that feature was Enumerator#feed.
Most Ruby developers are familiar with Enumerators. We use them every day through methods like map, select, and each. Some of us have even created custom Enumerators using Enumerator.new.
But very few developers seem to know about feed.
A Simple Enumerator
Let’s start with something familiar:
e = Enumerator.new do |y| y << 1 y << 2 y << 3ende.next # => 1e.next # => 2e.next # => 3
The Enumerator yields values, and the caller consumes them one at a time.
Nothing unusual so far.
When Enumerators Need Input
Now let’s look at something different.
e = Enumerator.new do |y| input = y.yield("What is your name?") y << "Hello #{input}"end
Running it produces something interesting:
e.next# => "What is your name?"e.feed("Rubyist")e.next# => "Hello Rubyist"
The value passed to feed becomes the return value of yield inside the Enumerator.
This means the Enumerator isn’t just producing values.
It’s receiving them too.
A Two-Way Conversation
Most developers think of Enumerators as one-way streams:
Enumerator -> Caller
With feed, the relationship becomes bidirectional:
Enumerator <-> Caller
The Enumerator pauses execution.
The caller injects a value.
Execution resumes using that value.
At this point, Enumerators start feeling surprisingly similar to coroutines.
Building a Tiny Interactive Workflow
Here’s a more complete example:
calculator = Enumerator.new do |y| a = y.yield("First number?") b = y.yield("Second number?") y << a + bendcalculator.next# => "First number?"calculator.feed(10)calculator.next# => "Second number?"calculator.feed(20)calculator.next# => 30
The Enumerator maintains state between pauses without requiring:
- Instance variables
- Classes
- External state management
Everything happens naturally inside the Enumerator itself.
How Does It Work?
The important detail is that:
value = y.yield("something")
doesn’t simply emit a value.
It creates a suspension point.
When execution resumes, value becomes whatever was provided through:
enumerator.feed(...)
In other words:
input = y.yield("Enter value")
behaves almost like:
input = receive_value_from_caller
except the Enumerator controls when the pause happens.
Why Does Ruby Have This?
Ruby’s Enumerator implementation borrows ideas from generators and coroutine-like execution models.
The feed method allows a suspended Enumerator to receive information from the outside world before continuing.
Most day-to-day Ruby code doesn’t need this capability, which is probably why so many developers never encounter it.
When developers need bidirectional communication, they typically reach for:
- Plain objects
- Service classes
- State machines
- Fibers
- Callbacks
As a result, feed remains one of Ruby’s lesser-known features.
Is It Useful?
For a typical Rails application?
Probably not.
You won’t suddenly improve your controllers or Active Record models by introducing Enumerator#feed.
However, it becomes interesting when building:
- Interactive workflows
- DSLs
- Parsers
- Custom interpreters
- Educational tools
- Experimental concurrency systems
Even if you never use it in production, understanding it provides insight into how Ruby’s execution model works under the hood.
Final Thoughts
One of Ruby’s greatest strengths is its depth.
You can be productive for years without learning every corner of the language, yet occasionally discover a feature that changes how you think about familiar concepts.
Enumerator#feed is one of those features.
It’s not something you’ll use every day.
But it’s a fascinating reminder that Ruby’s simple APIs often hide surprisingly sophisticated behavior.
And sometimes, years into your Ruby journey, you still find yourself saying:
“Wait… Ruby can do that?”
