Learning a programming language for the first time can be tricky, but remember — you’re not alone in that! As one of many resources available on the internet, this short series on translating documentation is meant to help bridge the gap for new developers on the scene.
When I started learning Ruby, each new task I needed to accomplish meant learning a new method. It felt mildly overwhelming at first, because 1) there are so many ways to arrive at a solution, and 2) it was a process in and of itself to decipher what the task was intended to teach.
As I added reading the Ruby documentation to my process, I found myself staring at letters and numbers that would hopefully/eventually make sense to me. At one point though, the documentation clicked, and the friction I experienced was not how to understand what the method was meant for, but my personal implementation of it — the A-ha! moment I hoped for ended up sprinkled over time, marking my progress to becoming a developer.
One area that seemed mystifying at first was understanding how to use enumerables.
Enumerables for beginners:
When you have a collection of things, and you need to perform a repetitive task on each item in that collection, you use an enumerable. This allows you to work with each item in the collection one at a time, without having to manipulate the item outside of the collection. Some enumerables modify the original collection, while others do not, and instead create a copy with the output of your code.
I understood what enumerables were in theory, but when I looked at the documentation to find a specific enumerable, the connection to understanding fell apart. If you feel the same way, let’s take a look at an enumerable to break down the pieces.
Quick tip:
An array is a collection of items, stored inside []s. It is not necessarily stored in order, despite what humans can deduce at first.
The .select enumerable in Ruby is defined in the API Dock Ruby Documentation as follows, and with the included example:
select() publicReturns a new array containing all elements of ary for which the given block returns a true value.If no block is given, an Enumerator is returned instead.[1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
a = %w{ a b c d e f }
a.select { |v| v =~ /[aeiou]/ } #=> ["a", "e"]
The first lines of text are the definition of the .select enumerable, and lets us know that the return value of calling .select on an array is a new array. This is good to know, in case we need to keep the original array unmodified for future use.
Moving on to the actual demonstrated use of select, we see the following :
[1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
The numbers inside the brackets, [1,2,3,4,5], make up the original array. By looking at the output of the code, #=> [2,4], it seems that we are trying to select the even numbers in the collection.
Between calling .select on the [1,2,3,4,5] array, and the output of [2,4], we can focus in on:
{ |num| num.even? }
Inside the curly braces {}, there is something called num, and .even? is used with it. The text inside the curly braces is referred to as a block of code — for an enumerable, this is where you can work with one item at a time in a collection.
The two “pipes”, or ||, around num identify what we are calling each item in the array. We as developers get to decide what to call it, and could alter the code in the following ways (with the same result):
//original:
[1,2,3,4,5].select { |num| num.even? } #=> [2, 4]//alternate 1:
[1,2,3,4,5].select { |number| number.even? } #=> [2, 4]//alternate 2:
[1,2,3,4,5].select { |thing| thing.even? } #=> [2, 4]//alternate 3:
[1,2,3,4,5].select { |bubblegum| bubblegum.even? } #=> [2, 4]
While “num” and “number” are clearly related to what each item in the array is, “thing” is less so, and “bubblegum” makes no logical sense. The key here is to understand that whatever word you place inside the || will be the placeholder name for each item in the collection. It is important, whether you are working solo or on a team of 100, to keep your naming convention clear. After programming for 10 hours, you may not remember why you named something “bubblegum”, even if it was funny, and your co-workers will certainly not understand or appreciate the attempt at “humor”.
Anything following the placeholder name inside the || can be one line, as it is in this example, or multiple lines of code. That code describes what actions need to be performed on (or with) the item at hand.
Our example here checks to see if the number is even. If that condition is true (if the number is even), that item gets stored in the new output array. If it is false (if the number is not even), we move on to the next item in the collection.
Let’s see this example in slo-mo action:
//original:
[1,2,3,4,5].select { |num| num.even? }//inside the block:
//1:
{ 1.even? }
//False: 1 is not even, it does not get stored in the new array
//2:
{ 2.even? } #=> [2]
//True: 2 is even, it does get stored in the new array
//3:
{ 3.even? }
//False: 3 is not even, it does not get stored in the new array
//4:
{ 4.even? } #=> [2,4]
//True: 4 is even, it does get stored in the new array
//5:
{ 5.even? }
//False: 5 is not even, it does not get stored in the new array//final output:
#=> [2, 4]
The way the .select enumerable is demonstrated in the API Dock Ruby Documentation is a very common pattern, not just for Ruby enumerables, but across many languages : a text based definition, and “live” examples of the process.
I hope this step-by-step walkthrough helps de-mystify not only Ruby’s .select enumerable specifically, but also how to approach reading language based documentation. If you have a specific request for a future “edition” of Translating Documentation, feel free to let me know in the comments below!