DEV Community

Miguel Jimenez
Miguel Jimenez

Posted on

 

Composition in Ruby with the >> operator

In Ruby, you can compose behavior and make arguments flow from to proc to proc using the >> operator.

Let's say I want the addition of two numbers

add = proc { |first, second| first + second }
add.call(1,2)
# => 3
Enter fullscreen mode Exit fullscreen mode

Let's say I would also like my program to square numbers

square = proc { |number| number ** 2 }  
square.call(2)
# => 4
Enter fullscreen mode Exit fullscreen mode

Now, I would like the program to perform one action after the other. First add two numbers, and then square them

add_then_square = square.call(add.call(1,2))
# => 9
Enter fullscreen mode Exit fullscreen mode

I tried composing two simple functions and I don't like where this is going. Now need to read the line from left to right. This is when the >> operator comes in to make our day.

add_then_square = add >> square
add_then_square.call(1,2)
# => 9
Enter fullscreen mode Exit fullscreen mode

You can also reverse the order of operations by using <<

greet = proc { |name| "Hello, #{name}!" }
sanitize_name = proc {|name| name.capitalize }

say_hello = greet << sanitize_name
say_hello.call("BENDER")

# =>  "Hello, Bender!"
Enter fullscreen mode Exit fullscreen mode

And we do not even have to assign multiple procs to a variable in order to call them.

total = 0
appetizer = proc { total += 10 }
salad = proc { total += 15 }
dessert = proc { total += 6 }

(appetizer >> salad >> dessert).call

# => 31
Enter fullscreen mode Exit fullscreen mode

All this makes composing and pipelining behavior really easy. Procs are, however, one of the very few things in Ruby that are not objects. We need to add a bit of indirection to our methods if we want to make them compatible with >>.

def sanitize_name
    proc { |n| n.capitalize }
end

def verify_robot
    robot_names = %w(Bender Marvin Kitt)
    proc {|n| n if robot_names.include?(n) }
end

def greet
    proc {|n| "Hello ,#{n}!" }
end

join_robot_army = sanitize_name >> verify_robot >> greet
join_robot_army.call("BENDER")

# =>  "Hello, Bender!"
Enter fullscreen mode Exit fullscreen mode

Ruby is famous for being an OOP-first language, but it has tremendous support for function composition and creating pipes. The >> operator is part of it, but you also have beautiful pieces of handy syntax like #then, #yield_self and ===.

Top comments (0)

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.