Understanding proc objects
Tags: ruby
Published: 2020-07-01 06:42:47

### 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
```ruby
pr = Proc.new { puts "hello world, once" }
pr.call

# hello world, once
```
`Proc.new` is an alias for the `Kernel#proc` method.
```ruby
pr = Kernel.proc { puts "hello world, twice" }
pr.call

# hello world, twice
```
We can also write like this.
```ruby
pr = proc { puts "hello world, thrice" }
pr.call
    
# hello world, thrice
```

### 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.
```ruby
def call_a_proc(&block)
    block.call
end

call_a_proc { puts "Hello world" }

# Hello world
```
Similar to this we can also place a `Proc.new` to serve in place of the code block.
```ruby
p = Proc.new { |x| puts x.upcase }
%w(abeid ahmed).each(&p)
```
It outputs to:

```ruby
ABEID
AHMED
=> ["abeid", "ahmed"]
```
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:
```ruby
%w(abeid ahmed).each { |x| puts x.upcase }
```

### Block-proc conversion
```ruby
def capture_block(&block)
    block.call
end

capture_block { puts "Beautiful day" }
```
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.

```ruby
capture_block { puts "Beautiful day" }
```

##### Step  2

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

```ruby
Proc.new { puts "Beautiful day" }
```

##### Step 3

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

```ruby
capture_block(&block)
```
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,

```ruby
%w(abeid ahmed).each(&p)
```

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

```ruby
capture_block { puts "hello world" }
```

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

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

# Another way
```

### 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](https://docs.ruby-lang.org/en/2.0.0/Proc.html).

This is my first article on this platform, so go easy on me :smile:. 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](https://www.amazon.com/Well-Grounded-Rubyist-David-Black/dp/1617295213/ref=sr_1_1?crid=2EPQNR1IOSJ97&dchild=1&keywords=well+grounded+rubyist&qid=1593584433&sprefix=Well+grounded%2Caps%2C536&sr=8-1)