DEV Community

Abeid Ahmed
Abeid Ahmed

Posted on

Understanding proc objects

What is a proc?

Proc objects are blocks of code that have been bound to a set of local variables. That means we can pass them as method arguments, push them inside an array, and do any other things that we normally do to objects.

Before moving on, I would like to clarify that Proc will denote the class and proc will denote the instance of the Proc class.

Calling a proc

pr = Proc.new { puts "hello world, once" }
pr.call

# hello world, once
Enter fullscreen mode Exit fullscreen mode

Proc.new is an alias for the Kernel#proc method.

pr = Kernel.proc { puts "hello world, twice" }
pr.call

# hello world, twice
Enter fullscreen mode Exit fullscreen mode

We can also write like this.

pr = proc { puts "hello world, thrice" }
pr.call

# hello world, thrice
Enter fullscreen mode Exit fullscreen mode

Capturing a code block

A method can capture a block and objectify it using the special & operator. Without the & operator, ruby has no way of understanding that you want to perform a block to proc conversion, rather than passing a regular argument.

def call_a_proc(&block)
    block.call
end

call_a_proc { puts "Hello world" }

# Hello world
Enter fullscreen mode Exit fullscreen mode

Similar to this we can also place a Proc.new to serve in place of the code block.

p = Proc.new { |x| puts x.upcase }
%w(abeid ahmed).each(&p)
Enter fullscreen mode Exit fullscreen mode

It outputs to:

ABEID
AHMED
=> ["abeid", "ahmed"]
Enter fullscreen mode Exit fullscreen mode

Here p is an instance of the Proc class. You can verify this using the p.class in your terminal.

A Proc.new takes in a code block that tells what to do when a proc is called. Now that is exactly what we are doing in the above code.

If you are writing ruby for sometime, you must be familiar with the each keyword. each method, takes in a block of some kind with an argument. The &p convinces each that it doesn't need an actual block and to receive a proc object.
The above code is same as saying:

%w(abeid ahmed).each { |x| puts x.upcase }
Enter fullscreen mode Exit fullscreen mode

Block-proc conversion

def capture_block(&block)
    block.call
end

capture_block { puts "Beautiful day" }
Enter fullscreen mode Exit fullscreen mode

We've seen this type of code in one of the examples above. So, here's how this method gets called.

Step 1

The capture_block method with the code block is called first.

capture_block { puts "Beautiful day" }
Enter fullscreen mode Exit fullscreen mode
Step 2

A new proc object is created using the Proc.new.

Proc.new { puts "Beautiful day" }
Enter fullscreen mode Exit fullscreen mode
Step 3

The proc created in step 2, is captured or bound to the block argument in the capture_block method.

capture_block(&block)
Enter fullscreen mode Exit fullscreen mode

So, these are the three steps that are completed to call the capture_block method.

Wait, there's more to this proc. Keen readers would be able to identify it and even if you didn't it is completely fine.

Remember the each example that we talked about? We passed in a Proc.new, like,

%w(abeid ahmed).each(&p)
Enter fullscreen mode Exit fullscreen mode

We can do the same with the capture_block method. Instead of calling the block like,

capture_block { puts "hello world" }
Enter fullscreen mode Exit fullscreen mode

we can do exactly the same as the each method. First we create a new Proc.new and we pass it on.

my_proc = Proc.new { puts "Another way" }
capture_block(&my_proc)

# Another way
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this article we have accomplished quite a lot. We learned how to create proc objects, how to capture them, and how the conversion from block to proc takes place. If you are interested in learning more about Proc head over to the official ruby docs.

This is my first article on this platform, so go easy on me 😄. If you found this article helpful, you know the drill and if there's any typo or general errors let me know in the comments. Good day and happy learning!

Credits: The Well Grounded Rubyist

Top comments (1)

Collapse
 
pedroherreraj profile image
Pedro Herrera

Excelent article!!