rubyguides

Kernel#yield_self

obj.yield_self { |obj| block } -> object

The yield_self method (introduced in Ruby 2.5) passes the receiver to a block and returns the result. It’s useful for chaining operations on any object without changing the original.

Basic Usage

# Simple chaining
result = 5.yield_self { |x| x * 2 }  # => 10
"hello".yield_self { |s| s.upcase }  # => "HELLO"

The block receives the receiver as its argument, so you can chain transformations that change the value from one type to another. Each call to yield_self feeds the previous result forward, keeping the pipeline flowing without introducing temporary variables.

Practical Examples

String Pipelines

# Clean up and transform string
filename = "  MY_FILE.TXT  "

filename
  .yield_self { |s| s.strip }
  .yield_self { |s| s.downcase }
  .yield_self { |s| s.gsub(" ", "_") }
# => "my_file.txt"

The string pipeline pattern is one of the clearest uses of yield_self: each step takes a string, transforms it, and passes the result to the next block. The method calls read in the order they happen, which makes the sequence easier to debug than nested function calls.

Number Transformations

# Chain numeric operations
100
  .yield_self { |n| n * 0.1 }
  .yield_self { |n| n.round(2) }
  .yield_self { |n| "$#{n}" }
# => "$10.0"

Numeric pipelines work well with yield_self when each step converts the number to a different representation: a percentage becomes a rounded value, then a formatted string. The chain tells a story that reads from top to bottom without the reader needing to track intermediate assignments.

Safe method calling

# Similar to Object#then (Ruby 2.5+)
obj.yield_self { |o| o.method_that_might_fail }

When the method you need to call might be nil or might not exist, yield_self wraps the call in a block that only runs if the receiver is valid. This is a lightweight alternative to the safe navigation operator &. when you want more control over what happens when the call succeeds or fails.

Data Processing

# Parse and transform
data = "100"

data
  .yield_self { |s| Integer(s) }
  .yield_self { |n| n * 2 }
  .yield_self { |n| { result: n } }
# => {:result=>200}

The data processing example shows how yield_self can move a value through several type changes: from a string to an integer, then to a doubled value, and finally to a wrapped hash. Each block has one clear job, keeping the code focused on what changes rather than on how the data is stored in between.

Comparison with other approaches

# Using yield_self
result = object.yield_self { |o| o.transform }

# Using tap (modifies self, returns self)
result = object.tap { |o| o.transform! }

# Using then (Ruby 2.5+ alias)
result = object.then { |o| o.transform }

# Traditional
result = transform(object)

The comparison makes the tradeoffs clear: yield_self returns the transformed value, tap returns the original, then is the newer alias, and the traditional approach uses a standalone method call. Choose yield_self or then when the output matters more than the input, and tap when you need the original object back after a side effect.

With chained methods

# Combine with regular methods
(1..10)
  .yield_self { |r| r.to_a }
  .select { |n| n.even? }
  .sum
# => 30

Why Use yield_self

  • Method chaining on non-enumerable objects
  • Creating pipelines
  • Cleaner transformation code
  • Alternative to temporary variables
  • Works with any object type

keeping transformations local

yield_self is useful when a value needs a short, contained transformation before the next step runs. It keeps the intermediate object close to the call site, which makes the pipeline easier to follow than a separate temporary variable in some cases. That is especially handy when the code is moving from one shape to another, like a string becoming a number or a list becoming a summary object. The result stays focused on the transformation instead of on bookkeeping.

The method is also a good reminder that the block should do one clear thing. If the code starts to branch, raise errors, or juggle several temporary values, the benefit of a small pipeline can disappear quickly. In that situation, a named helper may give the reader a better grip on the flow. Used well, yield_self keeps the steps small and honest, which is often enough to make a chain of operations feel calm instead of crowded.

It also helps to use it where the value is already available and the next operation is a true transformation rather than a side effect. That keeps the method feeling like a narrow bridge between one shape and the next. When the block is short, the overall code can read like a sequence of simple decisions instead of a pile of nested steps. That is usually the sweet spot for this method.

See Also