Skip to main content

Command Palette

Search for a command to run...

Elixir-like pipes in Ruby

Published
2 min readView as Markdown

If you use Elixir (and the Phoenix framework), you’ve probably admired the beauty and power of the |> pipelines. For example:

"String"
|> add(" is a common type")
|> IO.puts
# => "String is a common type"

In Ruby, the same mechanism can be achieved using yield_self:

"String"
.then { |s| s.concat(" is a common type") }
.then { |s| puts s }

The thing I love in Elixir is that you don’t need to pass the previous value explicitly—the put alone knows to take the preceding result as its first argument.

I wanted the same behavior in Ruby.

Or at least to avoid the redundant |subject|.

⚠️ 💣💀😱 To do this, I’m sacrificing the Kernel | operator and using it for my purposes:

module Kernel
  def |(&block)
    instance_eval(&block)
  end
end

Now, I almost get the same magic; I just need to use self to refer to the previous result:

"My string"
.| { "#{self} is a String value" }
.| { puts self }

Preserving the | operator

To avoid permanently overriding |, we can use refinements:

# In a file 'pipeline.rb'
module Pipeline
  refine Kernel do
    def |(&block)
      instance_eval(&block)
    end
  end
end

Now, to use this feature:

require 'pipeline'
using Pipeline

"My string"
.| { "#{self} is a String value" }
.| { puts self }