In this article, we’ll learn how to define a function, delve into blocks, and also learn about chain methods. All of them are closely related.
Function definitions
As we have learned in previous posts, a function in Ruby consists of a name and has no or more parameters:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> puts <span class="token string">"hello, world!"</span> hello <span class="token punctuation">,</span> world <span class="token operator">!</span> |
Although it is common to ignore the parentheses, it can also be written in the following way:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> puts <span class="token punctuation">(</span> <span class="token string">"hello, world!"</span> <span class="token punctuation">)</span> hello <span class="token punctuation">,</span> world <span class="token operator">!</span> |
One of the most important tasks in programming is involved in defining a function. In Ruby we can do this by using keyword def . Here, we will look at a simple example in the REPL. We will define a function named day_of_the_week , take the argument Time , and return the name of the weekday by that time.
Recall that the Time object has a method wday that returns the index of that day of the week. (zero-offset)
1 2 3 4 | <span class="token operator">></span> <span class="token operator">></span> now <span class="token operator">=</span> <span class="token builtin">Time</span> <span class="token punctuation">.</span> now <span class="token operator">></span> <span class="token operator">></span> now <span class="token punctuation">.</span> wday <span class="token operator">=</span> <span class="token operator">></span> <span class="token number">4</span> |
By the way, I also explain a bit about the Date library, which defines a constant for the days of the week.
1 2 3 4 | <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">require</span> <span class="token string">'date'</span> <span class="token operator">></span> <span class="token operator">></span> <span class="token constant">Date</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">DAYNAMES</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token string">"Sunday"</span> <span class="token punctuation">,</span> <span class="token string">"Monday"</span> <span class="token punctuation">,</span> <span class="token string">"Tuesday"</span> <span class="token punctuation">,</span> <span class="token string">"Wednesday"</span> <span class="token punctuation">,</span> <span class="token string">"Thursday"</span> <span class="token punctuation">,</span> <span class="token string">"Friday"</span> <span class="token punctuation">,</span> <span class="token string">"Saturday"</span> <span class="token punctuation">]</span> |
And it helps us to find the day of the week name like this:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> <span class="token constant">Date</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> now <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"Thursday"</span> |
It would be very convenient, when we encapsulate this definition and logic in the day_of_the_week function, so that we can write it like this: day_of_the_week(Time.now)
. Combining the above components, we have the following function:
1 2 3 4 | <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">day_of_the_week</span></span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token operator">></span> <span class="token keyword">return</span> <span class="token constant">Date</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> time <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">end</span> |
We see that a Ruby function will start with the keyword def , followed by the function name and arbitrary arguments; then the body of the function, it determines the return value of the function; finally terminated by the keyword end. (it is equivalent to closing curly braces } as in C or Javascript). We can test the following:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> day_of_the_week <span class="token punctuation">(</span> <span class="token builtin">Time</span> <span class="token punctuation">.</span> now <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"Thursday"</span> |
The above function seems quite simple, just find the corresponding element of the array with the wday value. Like many other languages, Ruby returns the value using the return keyword, but in reality the return keyword is not necessary. Usually, Ruby will return implicitly, accordingly, the final body of the function will be automatically returned. Hence, we can rewrite the day_of_the_week function as follows:
1 2 3 4 | <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">day_of_the_week</span></span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token operator">></span> <span class="token constant">Date</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> time <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">end</span> |
Functions in a file
Although the function definition in the REPL is quite convenient to illustrate it to others, it is cumbersome, so the best way is to write it to the file. We will move the function defined above to the hello_app.rb file. Recall the spelling we wrote for the first time as follows:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">require</span> <span class="token string">'sinatra'</span> get <span class="token string">'/'</span> <span class="token keyword">do</span> <span class="token constant">DAYNAMES</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">"Sunday"</span> <span class="token punctuation">,</span> <span class="token string">"Monday"</span> <span class="token punctuation">,</span> <span class="token string">"Tuesday"</span> <span class="token punctuation">,</span> <span class="token string">"Wednesday"</span> <span class="token punctuation">,</span> <span class="token string">"Thursday"</span> <span class="token punctuation">,</span> <span class="token string">"Friday"</span> <span class="token punctuation">,</span> <span class="token string">"Saturday"</span> <span class="token punctuation">]</span> dayname <span class="token operator">=</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> <span class="token builtin">Time</span> <span class="token punctuation">.</span> now <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token string">"Hello, world! Happy <span class="token interpolation"><span class="token delimiter tag">#{</span> dayname <span class="token delimiter tag">}</span></span> ."</span> <span class="token keyword">end</span> |
As a first step, we need to define the function in the file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">require</span> <span class="token string">'sinatra'</span> <span class="token comment"># Returns the day of the week for the given Time object.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">day_of_the_week</span></span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token constant">Date</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> time <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token keyword">end</span> get <span class="token string">'/'</span> <span class="token keyword">do</span> <span class="token constant">DAYNAMES</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">"Sunday"</span> <span class="token punctuation">,</span> <span class="token string">"Monday"</span> <span class="token punctuation">,</span> <span class="token string">"Tuesday"</span> <span class="token punctuation">,</span> <span class="token string">"Wednesday"</span> <span class="token punctuation">,</span> <span class="token string">"Thursday"</span> <span class="token punctuation">,</span> <span class="token string">"Friday"</span> <span class="token punctuation">,</span> <span class="token string">"Saturday"</span> <span class="token punctuation">]</span> dayname <span class="token operator">=</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> <span class="token builtin">Time</span> <span class="token punctuation">.</span> now <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token string">"Hello, world! Happy <span class="token interpolation"><span class="token delimiter tag">#{</span> dayname <span class="token delimiter tag">}</span></span> ."</span> <span class="token keyword">end</span> |
Then, we re-edit the body in get , which will be as follows:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">require</span> <span class="token string">'date'</span> <span class="token comment"># Returns the day of the week for the given Time object.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">day_of_the_week</span></span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token constant">Date</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> time <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token keyword">end</span> get <span class="token string">'/'</span> <span class="token keyword">do</span> <span class="token string">"Hello, world! Happy <span class="token interpolation"><span class="token delimiter tag">#{</span> day_of_the_week <span class="token punctuation">(</span> <span class="token builtin">Time</span> <span class="token punctuation">.</span> now <span class="token punctuation">)</span> <span class="token delimiter tag">}</span></span> ."</span> <span class="token keyword">end</span> |
We try to run it to see if the application runs as expected or not. $ ruby hello_app.rb
We can make the above code neater by moving the day_of_the_week function to a separate file and include it in our app. First, we create a new file, day.rb : touch day.rb
And change the code a little to make it easier to see if our code works. Note that we need to restart the Sinatra server for the code to be updated.
1 2 3 4 5 6 7 | <span class="token keyword">require</span> <span class="token string">'date'</span> <span class="token comment"># Returns the day of the week for the given Time object.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">day_of_the_week</span></span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token constant">Date</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">DAYNAMES</span> <span class="token punctuation">[</span> time <span class="token punctuation">.</span> wday <span class="token punctuation">]</span> <span class="token keyword">end</span> |
1 2 3 4 5 6 | <span class="token keyword">require</span> <span class="token string">'sinatra'</span> get <span class="token string">'/'</span> <span class="token keyword">do</span> <span class="token string">"Hello, world! Happy <span class="token interpolation"><span class="token delimiter tag">#{</span> day_of_the_week <span class="token punctuation">(</span> <span class="token builtin">Time</span> <span class="token punctuation">.</span> now <span class="token punctuation">)</span> <span class="token delimiter tag">}</span></span> —now from a file!"</span> <span class="token keyword">end</span> |
To check if the code is running, we will restart the server and reload the browser.
Unfortunately, our app crashes immediately, and returns the Sinatra error page, and that’s an exception of type NoMethodError. To see what we did wrong, pay attention to the error message text. It turns out that the day_of_the_week method has not been defined. And we also see the exact line of code that caused the error.
This is also a very useful debugging technique: that is, if your Ruby program fails, then the first thing to do is read the error messages carefully. And if you still do not understand exactly where the error is, then you can google the content of the error messages.
Debugging Ruby
One of the essential techniques for programming is debugging: how to quickly find and fix errors in programs. Here are some methods of finding the cause of an error in your program:
- Trace the execution with puts : When you try to figure out why the program doesn’t work properly, it’s helpful to display the value of the variable with the puts command, and remove it when the bugs are fixed. This technique is especially useful when combined with inspect method, which returns a textual representation of the object. For example,
puts array.inspect
orp array
- Stop the execution with raise : Using the raise functon, it raises an exception, which is a pretty big technique since it will stop the entire program, but when it comes to it it is a useful method. For example,
raise array.inspect
- Comment out code: This is a good idea, in case you think this code is irrelevant, and you need to focus on the code that doesn’t run properly.
- Use the REPL: Let’s turn on the irb, and paste the problematic code in, it’s a convenient way to isolate the problem. (A more advanced technique is to use pry gem, it allows running irb right in the app)
- Google it: If you can’t find the problem on your own, then google the error message content is a good way. (It usually leads us to some useful sites like Stack Overflow for example …)
Cause our app crash was due to have removed content in file DAY_OF_THE_WEEK hello_app.rb, so our app will not understand what that function is. The solution is to add a require statement to the file containing the function. Note that the require statement includes the relative path of the file.
1 2 3 4 5 6 7 | <span class="token keyword">require</span> <span class="token string">'sinatra'</span> <span class="token keyword">require</span> <span class="token string">'./day'</span> get <span class="token string">'/'</span> <span class="token keyword">do</span> <span class="token string">"Hello, world! Happy <span class="token interpolation"><span class="token delimiter tag">#{</span> day_of_the_week <span class="token punctuation">(</span> <span class="token builtin">Time</span> <span class="token punctuation">.</span> now <span class="token punctuation">)</span> <span class="token delimiter tag">}</span></span> —now from a file!"</span> <span class="token keyword">end</span> |
Restart the Sinatra server again, and our app is working fine.
Method chaining
In this section we will build the palindrome? function, this function returns true if the input argument is the same for both forward and reverse readings. Otherwise, false will be returned. Or we can understand palindrome simply as “A string and the reverse of that string are the same.” And, the chaning method is meant to call a sequence of messages of a particular object. Also, in the previous articles we learned how to create an array of characters that is split by an empty string:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> <span class="token string">"racecar"</span> <span class="token punctuation">.</span> split <span class="token punctuation">(</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token string">"r"</span> <span class="token punctuation">,</span> <span class="token string">"a"</span> <span class="token punctuation">,</span> <span class="token string">"c"</span> <span class="token punctuation">,</span> <span class="token string">"e"</span> <span class="token punctuation">,</span> <span class="token string">"c"</span> <span class="token punctuation">,</span> <span class="token string">"a"</span> <span class="token punctuation">,</span> <span class="token string">"r"</span> <span class="token punctuation">]</span> |
And the way to reverse an array is as follows:
1 2 3 4 | <span class="token operator">></span> <span class="token operator">></span> a <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token number">17</span> <span class="token punctuation">,</span> <span class="token number">42</span> <span class="token punctuation">,</span> <span class="token number">8</span> <span class="token punctuation">,</span> <span class="token number">99</span> <span class="token punctuation">]</span> <span class="token operator">></span> <span class="token operator">></span> a <span class="token punctuation">.</span> reverse <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token number">99</span> <span class="token punctuation">,</span> <span class="token number">8</span> <span class="token punctuation">,</span> <span class="token number">42</span> <span class="token punctuation">,</span> <span class="token number">17</span> <span class="token punctuation">]</span> |
And the join method to undo the split method:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token string">"r"</span> <span class="token punctuation">,</span> <span class="token string">"a"</span> <span class="token punctuation">,</span> <span class="token string">"c"</span> <span class="token punctuation">,</span> <span class="token string">"e"</span> <span class="token punctuation">,</span> <span class="token string">"c"</span> <span class="token punctuation">,</span> <span class="token string">"a"</span> <span class="token punctuation">,</span> <span class="token string">"r"</span> <span class="token punctuation">]</span> <span class="token punctuation">.</span> join <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"racecar"</span> |
And, we can reverse a string using the chaining method like so:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> <span class="token string">"Racecar"</span> <span class="token punctuation">.</span> split <span class="token punctuation">(</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> reverse <span class="token punctuation">.</span> join <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"racecaR"</span> |
Or we can use a simpler method than the String # chars method, which will return the characters of the string as an array:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> <span class="token string">"Racecar"</span> <span class="token punctuation">.</span> chars <span class="token punctuation">.</span> reverse <span class="token punctuation">.</span> join <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"racecaR"</span> |
This method is perfectly suited to use, and is essential in languages that do not support a dedicated method to reverse a string (such as Javascript …). However, Ruby has built-in support for string reversal, through the String # reverse method:
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> <span class="token string">"Racecar"</span> <span class="token punctuation">.</span> reverse <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"racecaR"</span> |
However, to detect palindromes as “Racecar”, we need to combine reversing and downcasing :
1 2 3 | <span class="token operator">></span> <span class="token operator">></span> <span class="token string">"Racecar"</span> <span class="token punctuation">.</span> downcase <span class="token punctuation">.</span> reverse <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"racecar"</span> |
With the above knowledge, let’s try to create the palindrome method. First, we need to create a file palindrome.rb to write our function: $ touch palindrome.rb
The $ touch palindrome.rb
function will take a string and return true if the string is palindrome, otherwise it will return false.
1 2 3 4 5 | <span class="token comment"># Returns true for a palindrome, false otherwise.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">palindrome</span></span> <span class="token operator">?</span> <span class="token punctuation">(</span> string <span class="token punctuation">)</span> string <span class="token operator">==</span> string <span class="token punctuation">.</span> reverse <span class="token keyword">end</span> |
Above, we used the == comparison, so Ruby will automatically return the boolean value. We can test the code using irb like this: >> load './palindrome.rb'
Using load is better than require as used in the previous sections. Because, it allows reloading the file if changed, while require does not allow us to. And through that, can we access the palindrome? from REPL:
1 2 3 4 5 | <span class="token operator">></span> <span class="token operator">></span> palindrome <span class="token operator">?</span> <span class="token punctuation">(</span> <span class="token string">"racecar"</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token boolean">true</span> <span class="token operator">></span> <span class="token operator">></span> palindrome <span class="token operator">?</span> <span class="token punctuation">(</span> <span class="token string">"Racecar"</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token boolean">false</span> |
The palindrome method indicated that “Racecar” is not a palindrome, so to make our function more general we need to downcase string before comparing like this:
1 2 3 4 5 | <span class="token comment"># Returns true for a palindrome, false otherwise.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">palindrome</span></span> <span class="token operator">?</span> <span class="token punctuation">(</span> string <span class="token punctuation">)</span> string <span class="token punctuation">.</span> downcase <span class="token operator">==</span> string <span class="token punctuation">.</span> downcase <span class="token punctuation">.</span> reverse <span class="token keyword">end</span> |
We try to run it again and test:
1 2 3 4 | <span class="token operator">></span> <span class="token operator">></span> load <span class="token string">'./palindrome.rb'</span> <span class="token operator">></span> <span class="token operator">></span> palindrome <span class="token operator">?</span> <span class="token punctuation">(</span> <span class="token string">"Racecar"</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token boolean">true</span> |
-> Returns true.
Finally, we will apply the DRY (Don’t Repeat Yourself) principle to eliminate duplication in the code above. Reviewing the above code, we see that string.downcase has been used 2 times. Therefore, we will declare a new variable called processed_content to hold the string value for comparison with the reverse string.
1 2 3 4 5 6 | <span class="token comment"># Returns true for a palindrome, false otherwise.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">palindrome</span></span> <span class="token operator">?</span> <span class="token punctuation">(</span> string <span class="token punctuation">)</span> processed_content <span class="token operator">=</span> string <span class="token punctuation">.</span> downcase processed_content <span class="token operator">==</span> processed_content <span class="token punctuation">.</span> reverse <span class="token keyword">end</span> |
The above code has helped us reduce 1 call downcase , but must write one more line. It may not seem like much of an improvement, but the declaration of a separate variable gives us much more flexibility in detecting and handling a complex palindromes.
Finally, we run again to see the palindrome function? is it still working correctly?
1 2 3 4 5 6 | <span class="token operator">></span> <span class="token operator">></span> load <span class="token string">'./palindrome.rb'</span> <span class="token operator">></span> <span class="token operator">></span> palindrome <span class="token operator">?</span> <span class="token punctuation">(</span> <span class="token string">"Racecar"</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token boolean">true</span> <span class="token operator">></span> <span class="token operator">></span> palindrome <span class="token operator">?</span> <span class="token punctuation">(</span> <span class="token string">"Able was I ere I saw Elba"</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token boolean">true</span> |
Blocks
Blocks are one of the most useful features and structures in Ruby. We’ve seen it in previous sections and articles. However, in this section we will focus on digging deeper into how it works.
We’ll start with a simple block that prints out the powers of 2:
1 2 3 4 5 6 7 | <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token number">1.</span> <span class="token number">.5</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token punctuation">{</span> <span class="token operator">|</span> i <span class="token operator">|</span> puts <span class="token number">2</span> <span class="token operator">*</span> <span class="token operator">*</span> i <span class="token punctuation">}</span> <span class="token number">2</span> <span class="token number">4</span> <span class="token number">8</span> <span class="token number">16</span> <span class="token number">32</span> |
The code above calls each function in scope (1..5) and has blocks of {| i | puts 2 * i} . In it, vertical bars surround variable name | i | That’s Ruby’s syntax called block variable . In this case, the each method can process the block with the single local variable, which we set as i , and only execute this block within the specified scope.
We can use curly braces to delineate a block like above, or we can write in the following way:
1 2 3 4 5 6 7 8 9 10 | <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token number">1.</span> <span class="token number">.5</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span> i <span class="token operator">|</span> <span class="token operator">?</span> <span class="token operator">></span> puts <span class="token number">2</span> <span class="token operator">*</span> <span class="token operator">*</span> i <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">end</span> <span class="token number">2</span> <span class="token number">4</span> <span class="token number">8</span> <span class="token number">16</span> <span class="token number">32</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token number">1.</span> <span class="token number">.5</span> |
Blocks can be one or more lines. Normally, we will follow convention of using curly braces for short method (in 1 line) and use do..end for long method (written on multiple lines).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token number">1.</span> <span class="token number">.5</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span> number <span class="token operator">|</span> <span class="token operator">?</span> <span class="token operator">></span> puts <span class="token number">2</span> <span class="token operator">*</span> <span class="token operator">*</span> number <span class="token operator">></span> <span class="token operator">></span> puts <span class="token string">'--'</span> <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">end</span> <span class="token number">2</span> <span class="token operator">--</span> <span class="token number">4</span> <span class="token operator">--</span> <span class="token number">8</span> <span class="token operator">--</span> <span class="token number">16</span> <span class="token operator">--</span> <span class="token number">32</span> <span class="token operator">--</span> |
Above, we changed the variable name from i to number , to emphasize that the variable name is optional, you can name anything.
And we can think of blocks as anonymous (unnamed) functions that we can create right away. If you have learned about Javascript, you will find this usage quite familiar, which is that it includes an unnamed function to print out elements in the Javascript array:
1 2 3 4 5 6 7 8 | <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token string">"ant"</span> <span class="token punctuation">,</span> <span class="token string">"bat"</span> <span class="token punctuation">,</span> <span class="token string">"cat"</span> <span class="token punctuation">,</span> <span class="token number">42</span> <span class="token punctuation">]</span> <span class="token punctuation">.</span> forEach <span class="token punctuation">(</span> function <span class="token punctuation">(</span> element <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> log <span class="token punctuation">(</span> element <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> ant bat cat <span class="token number">42</span> |
A Ruby block can be seen as a way to do the same Js code above without having to include a separate function.
1 2 3 4 5 6 7 8 | <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token string">"ant"</span> <span class="token punctuation">,</span> <span class="token string">"bat"</span> <span class="token punctuation">,</span> <span class="token string">"cat"</span> <span class="token punctuation">,</span> <span class="token number">42</span> <span class="token punctuation">]</span> <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span> element <span class="token operator">|</span> <span class="token operator">?</span> <span class="token operator">></span> puts element <span class="token operator">></span> <span class="token operator">></span> <span class="token keyword">end</span> ant bat cat <span class="token number">42</span> |
Perhaps, each is the most common method to use in a block, but there are many other similar functions, such as the times method, which iterates over a given block a certain number of times:
1 2 3 4 5 | <span class="token operator">></span> <span class="token operator">></span> <span class="token number">3.</span> times <span class="token punctuation">{</span> puts <span class="token string">"Betelgeuse!"</span> <span class="token punctuation">}</span> <span class="token comment"># `times` takes a block with no variables.</span> <span class="token string">"Betelgeuse!"</span> <span class="token string">"Betelgeuse!"</span> <span class="token string">"Betelgeuse!"</span> |
Yield
We can develop our understanding of blocks by using them in some of our functions. Note that (1) every Ruby method can take a block and (2) we can call the block using the yield keyword. Let’s take a look at a few specific examples to understand how it works:
First, we create a new file: $ touch blocks.rb
.
Then, we define a function called sandwich , and yield a block that will lie between two puts commands
1 2 3 4 5 6 | <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">sandwich</span></span> puts <span class="token string">"top bread"</span> <span class="token keyword">yield</span> puts <span class="token string">"bottom bread"</span> <span class="token keyword">end</span> |
So what does a block mean? It’s a one-block sandwich run.
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">sandwich</span></span> puts <span class="token string">"top bread"</span> <span class="token keyword">yield</span> puts <span class="token string">"bottom bread"</span> <span class="token keyword">end</span> sandwich <span class="token keyword">do</span> puts <span class="token string">"mutton, lettuce, and tomato"</span> <span class="token keyword">end</span> |
Running the above file, we have the following results:
1 2 3 4 5 | $ ruby blocks <span class="token punctuation">.</span> rb top bread mutton <span class="token punctuation">,</span> lettuce <span class="token punctuation">,</span> <span class="token keyword">and</span> tomato bottom bread |
One advantage of Ruby’s block is that it will not display until the yield keyword appears.
The next example is about the tag function, which will wrap the text into the passed HTML tag. In this example, we learn how to use block variables.
1 2 3 4 5 6 7 8 | <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">tag</span></span> <span class="token punctuation">(</span> tagname <span class="token punctuation">,</span> text <span class="token punctuation">)</span> html <span class="token operator">=</span> <span class="token string">"< <span class="token interpolation"><span class="token delimiter tag">#{</span> tagname <span class="token delimiter tag">}</span></span> > <span class="token interpolation"><span class="token delimiter tag">#{</span> text <span class="token delimiter tag">}</span></span> </ <span class="token interpolation"><span class="token delimiter tag">#{</span> tagname <span class="token delimiter tag">}</span></span> >"</span> <span class="token keyword">yield</span> html <span class="token keyword">end</span> |
Above, we have defined a function with many parameters, separated by commas between parameters. Then we pass the tag function two required parameters, tagname and text, and a block representing the HTML markup.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">tag</span></span> <span class="token punctuation">(</span> tagname <span class="token punctuation">,</span> text <span class="token punctuation">)</span> html <span class="token operator">=</span> <span class="token string">"< <span class="token interpolation"><span class="token delimiter tag">#{</span> tagname <span class="token delimiter tag">}</span></span> > <span class="token interpolation"><span class="token delimiter tag">#{</span> text <span class="token delimiter tag">}</span></span> </ <span class="token interpolation"><span class="token delimiter tag">#{</span> tagname <span class="token delimiter tag">}</span></span> >"</span> <span class="token keyword">yield</span> html <span class="token keyword">end</span> <span class="token comment"># Wrap some text in a paragraph tag.</span> tag <span class="token punctuation">(</span> <span class="token string">"p"</span> <span class="token punctuation">,</span> <span class="token string">"Lorem ipsum dolor sit amet"</span> <span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span> markup <span class="token operator">|</span> puts markup <span class="token keyword">end</span> |
Running the above code, we get the following result:
1 2 3 4 5 6 | $ ruby blocks <span class="token punctuation">.</span> rb top bread mutton <span class="token punctuation">,</span> lettuce <span class="token punctuation">,</span> <span class="token keyword">and</span> tomato bottom bread <span class="token operator"><</span> p <span class="token operator">></span> <span class="token constant">Lorem</span> ipsum dolor sit amet <span class="token operator"><</span> <span class="token operator">/</span> p <span class="token operator">></span> |
Over. We will learn together about other topics in Ruby in the next posts.
Source: Learn-enough