First look: Procs in Ruby
If you read my last post, I used Ruby enumerators to create the basic structure of an opera aria and an art song using the #map and #each methods. I feel pretty comfortable with iteration and figured it was about time that I built upon what I already knew about it. My solution literally fell from the sky in the form of my instructor.
While sitting in a lecture today, my instructor used a shorthand that I was not familiar with. Names, in this case, is an array of strings.
names.map(&:upcase)
He very briefly explained that it was a shorthand for iteration.
But wait. I learned it this way:
names.map do |name|
name.upcase
end
More lines, more fun, right?
I was pretty excited to look into this and found out that I can do things like iterate through databases, arrays, etc with just one line.
The ampersand is calling the #to_proc method and is essentially creating a new proc out of the object you pass it. Here’s the longhand of its functionality:
scream_things = Proc.new {|word| word.upcase}
This works the same way:
names = ["Pete", "Patricia", "Patty"]
names.map(&scream_things)
=> ["PETE", "PATRICIA", "PATTY"]
What exactly is a proc?
A proc, (short for procedure), is one of the three types of closures in Ruby along with blocks and lambdas. It’s a block of code that can use the local variables around it. If the variables are reassigned, they keep the value from their very first assignment.
Like most things in Ruby, a proc is an object and in this case, it’s an object of the Proc class and creating one will generate an instance.
=> #<Proc:0x007f8c1e0c2b30@(irb):51>
This shorthand really comes in handy and I highly encourage using it to make your code more concise and readable. If you’re building something that uses a certain method multiple times, you can save it to a proc. This comes especially handy when we need to extract data from a database. For example, if you need to sort some book titles from the “title” column in your “books” table, you can use a proc in addition to ActiveRecord’s #pluck method.
Book.pluck(:title).map(&:sort!)
Brevity has never been more welcome!
Taking a look back at the code I wrote for my art song hash, I refactored it by using a proc to output the song. The results speak directly to the usefulness of procs.
We went from this:
To this:
This outputs:
3 bars of a nostaligic introduction with a certain je ne sais quoi
Im wunderschönen Monat Mai,
Als alle Knospen sprangen,
Da ist in meinem Herzen
Die Liebe aufgegangen
2 bars seamlessly carrying us to verse 2
Im wunderschönen Monat Mai,
Als alle Vögel sangen,
Da hab ich ihr gestanden
Mein Sehnen und Verlangen.
3 bars of depth and longing that leads us tactfully into the next song in the cycle...=> {:intro=>"3 bars of a nostaligic introduction with a certain je ne sais quoi", :verse_1=>"Im wundersch\u00F6nen Monat Mai,\nAls alle Knospen sprangen,\nDa ist in meinem Herzen\nDie Liebe aufgegangen", :interlude=>"2 bars seamlessly carrying us to verse 2", :verse_2=>"Im wundersch\u00F6nen Monat Mai,\nAls alle V\u00F6gel sangen,\nDa hab ich ihr gestanden\nMein Sehnen und Verlangen.", :postlude=>"3 bars of depth and longing that leads us tactfully into the next song in the cycle..."}
Unfortunately, I can’t use this for nested hashes and/or sub-arrays but I’m super excited to implement this into my code and learn more about closures in general.
In the future, I will edit this to be more wholesome and go into lambdas as well! Until then:
2.3.3 :061 > Time.now.friday?=> false