My own exploration of Ruby Proc objects

Ruby!

I’ve just started learning how to code Ruby. I stumbled upon the idea of a Proc object and had no idea what it was. This post will be my attempt at learning about them and understand a use for them as I type.

A Proc instance in ruby is basically a block of code assigned to a variable. You can then call this block of code from the variable using #call . You can create a Proc with Proc.new . Then follow up with the block.

fun = Proc.new{"Hello!"}
fun.call
=> "Hello!

It’s important to note that simply calling the variable (in this case, ‘fun’) will return the Proc’s ID. Something you probably don’t care so much about.

fun
=><Proc:0x0055bf32dbd6b0>

Now, using a Proc to return a simple String instance seems silly and unnecessary. Well, yea, it is. The whole point of a Proc is a give the block a longer amount of code that you don’t want to type over and over and over. As you know, programmers are lazy.

You can assign the Proc to a block with a variable!

divide_by_two = Proc.new{|variable| variable / 2}
divide_by_two.call(10)
=> 5
divide_by_two.call(500)
=> 250

Though, looking at that, I think I’ve actually used a few more characters than I would have if I had just written 10/5. But, c’mon, baby steps.

Let’s jump ahead. In the Proc block, we can have another block! Maybe you really like bananas. You come home and there are some bananas on your kitchen table. You are so happy! You’re going to scream “Bananas!” You want to scream “Bananas!” for each banana on the table.

scream_bananas = Proc.new{|number_of_bananas| number_of_bananas.times do
"Bananas!"
end
}
scream_bananas.call(3)
#will output
"Bananas!"
"Bananas!"
"Bananas!"
=> 3

You can change how many times you scream “Bananas!” by changing the argument in #call . Also note that in this example, the return value is whatever you put in as the argument.

Quick mental break!

So far, I haven’t seen any real practical use for Procs. All of the things I’ve shown you can be more easily done other ways. scream_bananas would be a great function. And it would be a lot cleaner to look at. So let’s have some fun with it.

Imagine now that you really love fruit.

Like. A lot. Every time you come home and there’s fruit on the table you scream that fruit as many times as there are on the table. So if there are 3 bananas, 2 strawberry, and 5 grapes, (I don’t know who would’ve left just five grapes, but that’s just not the point), you would scream “bananas” three times, strawberries two, and grapes five.

We love when we have code that writes more code for us so let’s create a function that builds a Proc for us.

def fruit_scream_proc_creator(fruit = "Fruit")
Proc.new{|number_of_fruits| number_of_fruits.times do
puts "#{fruit.capitalize}!"
end
}
end
=> :fruit_scream_proc_creator

Whoa. That’s dense. Let’s take a step back and go step-by-step.

First, we’re defining a new function (fruit_scream_proc_creator) that takes an argument (but also has a default). Second line, we’re creating a new instance of Proc. Then we’re telling the proc that the block will have a variable “number_of_fruits”. Then, that number of times, do…third line. Puts whatever fruit you passed into the function (capitalized). And, because Ruby, return the Proc.

Let’s see how this would work.

banana = fruit_scream_proc_creator("bananas")
=> #<Proc:0x00560b82c8e1d0>

This line of code will create this:

banana = {|number_of_fruits| number_of_fruits.times do
puts "Bananas!"
end
}

So through #fruit_scream_proc_creator we’ve now made it possible to create Procs given any fruit. So…

strawberry = fruit_scream_proc_creator("strawberries")
strawberry.call(4)
#Will output
"Strawberries!"
"Strawberries!"
"Strawberries!"
"Strawberries!"
=> 4

Look how much fun we’re having now.

But just for the fun of it, let’s maybe make this a little more applicable.

Imagine now that your are the Super of a school district. You have lots of schools(…has many schools). Each school has lots of students. Each student has life-info. Maybe it’s set kinda like this:

school_a = {
"Steve Rogers" => {
"age" => 12,
"grade" => 7,
"dob" => [04,11,1998]
},
"Tony Stark" => {
"age" => 13,
"grade" => 8,
"dob" => [07,13,1997]
}
}
school_b = {
"Bruce Wayne" => {
"age" => 12,
"grade" => 5,
"dob" => [02,14,2000]
},
"Clark Kent" => {
"age" => 13,
"grade" => 10,
"dob" => [01,29,1995]
}
}

You, Super, want to be able to easily find a student’s info by their name.

Unfortunately the hashes aren’t together in one nice hash. They’re in different variables. So let’s create a function that creates a Proc to help us find this student.

def find_student_proc(school)
Proc.new{|name| school.find do |k,v|
k == name
end
}
end

Now you can assign variable to the proc with any school.

find_in_school_a = find_student_proc(school_a)
find_in_school_b = find_student_proc(school_b)

Then from there you can simply add a name to the call argument

find_in_school_a.call("Steve Rodgers")
=> ["Steve Rogers", {"age"=>12, "grade"=>7, "dob"=>[4, 11, 1998]}]
find_in_school_b.call("Steve Rogers")
=> nil

Hooray!

Show your support

Clapping shows how much you appreciated Will Scripps’s story.