DEV Community

loading...

Ruby already has pipeline functionality

jleblanc profile image Josh LeBlanc ・2 min read

There's a big fuss going on in the ruby world about an upcoming operator inappropriately named "the pipeline operator".

A traditional pipeline operator lets you unwrap nested function calls like a(b(c(5))), by writing it in pipes. 5 |> c |> b |> a

The ruby one, however, just lets you do this:

1..5 
|> map { |i| i * 2 }
|> reduce(0) { |i, s| s + i }
Enter fullscreen mode Exit fullscreen mode

rather than

(1..5)
.map { |i| i * 2 }
.reduce(0) { |i, s| s + i }
Enter fullscreen mode Exit fullscreen mode

Brandon Weaver talks about it here:

I wanted to expand on a comment from that thread from Johan Wentholt:

Overall a pretty informative post. However I would like to add that:

5.then(&double).then(&double).then(&increment).then(&double)
Enter fullscreen mode Exit fullscreen mode
Enter fullscreen mode Exit fullscreen mode

Enter fullscreen mode Exit fullscreen mode

Could also be written as:

5.then(&double >> double >> increment >> double)
Enter fullscreen mode Exit fullscreen mode
Enter fullscreen mode Exit fullscreen mode

Enter fullscreen mode Exit fullscreen mode
</div>
Enter fullscreen mode Exit fullscreen mode

The feature that Johan Wentholt is using is called functional composition, and ruby 2.6 shipped with 2 operators for it. <<, for a(b()), and >> for b(a()). These operators allow you to compose procs out of existing procs. He's combining this feature with #then, which yields self to the given block.

For example, if you had the following procs

double -> { @1 * 2 }
add_two -> { @1 + 2 }
Enter fullscreen mode Exit fullscreen mode

Then you could create a new proc, add_two_then_double

add_two_then_double = add_two >> double
# OR
add_two_then_double = double << add_two

add_two_then_double.call(5) #> 14
Enter fullscreen mode Exit fullscreen mode

Up above, I gave an example of the pipeline operator by simplifying a(b(c(5))). With functional composition, you can write this as:

(c >> b >> a).call(5)
Enter fullscreen mode Exit fullscreen mode

Of course, you can also apply ruby's new pipeline operator to this, to get c >> b >> a |> call(5)

So as a tl;dr:

double = -> { @1 * 2 }
add_two = -> { @1 + 2 }

# these are all double(add_two(5))

(add_two >> double)[5]
(add_two >> double).call(5)
add_two >> double |> call(5)
5.then(&add_two >> double)
Enter fullscreen mode Exit fullscreen mode

Discussion (2)

Collapse
rhymes profile image
rhymes

The feature that Johan Wentholt is using is called functional composition, and ruby 2.6 shipped with 2 operators for it. <<, for a(b()), and >> for b(a()). These operators allow you to compose procs out of existing procs

Totally didn't know!! This is so cool :) A bit obscure in its syntax but cool.

I would have added just one, >>, you can just change the order of the listed procs if you need to. Or maybe I'm missing something

Collapse
joecannatti profile image
Joe Cannatti

i could see myself using that occasionally. I didn't know about the << for that case.

Forem Open with the Forem app