<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: meleu</title>
    <description>The latest articles on Forem by meleu (@meleu).</description>
    <link>https://forem.com/meleu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F519711%2F83e97011-fbf8-4b02-b624-7f4fe011534e.png</url>
      <title>Forem: meleu</title>
      <link>https://forem.com/meleu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/meleu"/>
    <language>en</language>
    <item>
      <title>Create robust CLI apps with Bashly</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Fri, 29 Aug 2025 20:35:25 +0000</pubDate>
      <link>https://forem.com/meleu/create-robust-cli-apps-with-bashly-5gb0</link>
      <guid>https://forem.com/meleu/create-robust-cli-apps-with-bashly-5gb0</guid>
      <description>&lt;p&gt;In this article we're going to know Bashly, a framework that lets you create robust CLI applications using just bash.&lt;/p&gt;

&lt;p&gt;We will do it with a hands-on approach, developing a very simple application, but with a solid look and feel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bashly?
&lt;/h2&gt;

&lt;p&gt;Imagine this scenario...&lt;/p&gt;

&lt;p&gt;We want to create a random number generator. In bash this is so simple that we can just do &lt;code&gt;echo $RANDOM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We don't even need a script for that, but we started to think in new features. Example: we want to specify the maximum number to be generated.&lt;/p&gt;

&lt;p&gt;Consider our program is called &lt;code&gt;rndm&lt;/code&gt;, we could have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# simulating a dice roll&lt;/span&gt;
rndm &lt;span class="nt"&gt;--max&lt;/span&gt; 6

&lt;span class="c"&gt;# tossing a coin&lt;/span&gt;
rndm &lt;span class="nt"&gt;--max&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe you already know how to generate random numbers between a specific range, the logic for this is not that complicated. But if you already wrote a bash program parsing command line &lt;code&gt;--options&lt;/code&gt;, then you know what happens: our simple program will explode in complexity just because of the code needed to handle such options.&lt;/p&gt;

&lt;p&gt;Ah! As you added options, you now have to provide a &lt;code&gt;--help&lt;/code&gt;, so your users know how to use the available options.&lt;/p&gt;

&lt;p&gt;Also, if you are going to accept user input, it's important to validate what they are sending to the program.&lt;/p&gt;

&lt;p&gt;At the end of the day you'll probably spend more energy handling all these details than with the problem you really want to solve: generate random numbers.&lt;/p&gt;

&lt;p&gt;That's why Bashly was created! With it we can easily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parse &lt;code&gt;--options&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;create help messages&lt;/li&gt;
&lt;li&gt;validate input&lt;/li&gt;
&lt;li&gt;check dependencies&lt;/li&gt;
&lt;li&gt;other typical things required from a robust CLI application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Delegate such tedious tasks to Bashly and focus on the logic of the problem you really want to solve.&lt;/p&gt;

&lt;p&gt;To illustrate how to create a robust CLI with Bashly, we are going to develop a random number generator. It starts simple but will gradually get more interesting features.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: in order to use Bashly it's assumed you know how to handle YAML files (which is very simple)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installing Bashly
&lt;/h2&gt;

&lt;p&gt;Bashly is a Ruby gem. In the Ruby ecosystem we call the packages as a &lt;em&gt;gem&lt;/em&gt; (like a npm package for NodeJS, or a create for Rust).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: although it's developed in Ruby:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you do &lt;strong&gt;not&lt;/strong&gt; need to know any Ruby to use Bashly.&lt;/li&gt;
&lt;li&gt;the users of your program do &lt;strong&gt;not&lt;/strong&gt; need Ruby installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bashly depends on Ruby 3.2+. If you run &lt;code&gt;ruby --version&lt;/code&gt; and see a version equal or greater than 3.2, then you're good. Otherwise, you'll need to install a proper version.&lt;/p&gt;

&lt;p&gt;I like to use "runtime version managers", like &lt;a href="https://mise.jdx.dev/" rel="noopener noreferrer"&gt;mise&lt;/a&gt; (I use and recommend) or &lt;a href="https://asdf-vm.com" rel="noopener noreferrer"&gt;asdf&lt;/a&gt; to install interpreters and compilers in different versions. I suggest you to do the same to install a proper Ruby version.&lt;/p&gt;

&lt;p&gt;Here's an example using mise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# installing ruby 3.4 and setting as the default&lt;/span&gt;
mise use &lt;span class="nt"&gt;--global&lt;/span&gt; ruby@3.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once Ruby is installed, we can install Bashly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;bashly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just checking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bashly --version
1.3.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of this writing Bashly version is 1.3.2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bash Version
&lt;/h3&gt;

&lt;p&gt;The final Bash code generated by Bashly make use of associative arrays and other features that came to bash in the version 4.2 (which was released in 2011).&lt;/p&gt;

&lt;p&gt;If you're using a Linux distro, then you probably already have a compatible version.&lt;/p&gt;

&lt;p&gt;If you're on MacOS, your Bash is probably "frozen" in version 3.2.57. Don't worry, a simple &lt;code&gt;brew install bash&lt;/code&gt; can fix the problem (I'm assuming you have &lt;a href="https://brew.sh" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; installed).&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting a Project
&lt;/h2&gt;

&lt;p&gt;Let's start with a directory for our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;rndm
&lt;span class="nb"&gt;cd &lt;/span&gt;rndm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A way to start a Bashly project is by running &lt;code&gt;bashly init&lt;/code&gt;, which creates a file named &lt;code&gt;src/bashly.yml&lt;/code&gt;. If you do it you'll note that the file comes filled with some data, but that can be confusing for our first start.&lt;/p&gt;

&lt;p&gt;Here we're going to write our &lt;code&gt;bashly.yml&lt;/code&gt; from scratch, learning each configuration. Therefore, open your &lt;code&gt;src/bashly.yml&lt;/code&gt;, remove all its contents and add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rndm&lt;/span&gt;
&lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prints a random number&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can run &lt;code&gt;bashly generate&lt;/code&gt; and see an output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bashly generate
creating user files in src
created src/root_command.sh
created ./rndm
run ./rndm --help to test your bash script
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's do exactly what it's suggesting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm --help
rndm - Prints a random number

Usage:
  rndm
  rndm --help | -h
  rndm --version | -v

Options:
  --help, -h
    Show this help

  --version, -v
    Show version number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🤩 - Look at that!&lt;/p&gt;

&lt;p&gt;We didn't write a single bash line and look at that beautiful help message we already have!&lt;/p&gt;

&lt;p&gt;Trying to explain, in simple terms, what Bashly just did:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;read the &lt;code&gt;src/bashly.yml&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;understood that we want to create a script named &lt;code&gt;rndm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;read the script's description in the &lt;code&gt;help:&lt;/code&gt; directive&lt;/li&gt;
&lt;li&gt;read the script's version in &lt;code&gt;version:&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;created a file named &lt;code&gt;src/root_command.sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;generated the final script &lt;code&gt;rndm&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One thing we already noticed is that the &lt;code&gt;rndm&lt;/code&gt; script was already generated with a &lt;code&gt;--help&lt;/code&gt; and &lt;code&gt;--version&lt;/code&gt; feature.&lt;/p&gt;

&lt;p&gt;The final &lt;code&gt;rndm&lt;/code&gt; script is "self-contained", which means that you can distribute it to anyone with bash available to run it (as long as you don't introduce external dependencies, which we'll talk about soon).&lt;/p&gt;

&lt;p&gt;Let's take a look at the &lt;code&gt;src/root_command.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# This file is located at 'src/root_command.sh'."&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# It contains the implementation for the 'rndm' command."&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# The code you write here will be wrapped by a function named 'root_command()'."&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# Feel free to edit this file; your changes will persist when regenerating."&lt;/span&gt;
inspect_args
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's talk a bit more about this...&lt;/p&gt;

&lt;p&gt;When we ran &lt;code&gt;bashly generate&lt;/code&gt; the file &lt;code&gt;src/root_command.sh&lt;/code&gt; was created, and that's where we should put our program's logic.&lt;/p&gt;

&lt;p&gt;In the final &lt;code&gt;rndm&lt;/code&gt; script all the contents of this file will be wrapped in a function named &lt;code&gt;root_command()&lt;/code&gt;. And if we check the final script we'll confirm that the function is there (maybe around line 10):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# ...&lt;/span&gt;

root_command&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# This file is located at 'src/root_command.sh'."&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# It contains the implementation for the 'rndm' command."&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# The code you write here will be wrapped by a function named 'root_command()'."&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# Feel free to edit this file; your changes will persist when regenerating."&lt;/span&gt;
  inspect_args

&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;src/root_command.sh&lt;/code&gt; file is created, Bashly doesn't change it anymore. We can edit it at will and our code will remain untouched, even after a new &lt;code&gt;bashly generate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Well, the initial contents of this file exist just to tell us these things, now we can start implementing our feature. But first, I think it's a good idea to version control our project...&lt;/p&gt;

&lt;h3&gt;
  
  
  Version Control
&lt;/h3&gt;

&lt;p&gt;With a version control system we can create safe "checkpoints" of the evolution of our project. Therefore let's start a new git repository and commit what we have until now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'Starting bashly project'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: for a better reading experience I'm not going to worry about updating the &lt;code&gt;version: 0.0.1&lt;/code&gt; in our &lt;code&gt;src/bashly.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating Random Numbers
&lt;/h3&gt;

&lt;p&gt;We can now delete everything in &lt;code&gt;src/root_command.sh&lt;/code&gt; and finally put our great random number generator code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RANDOM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regenerate the script and check the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bashly generate
creating user files in src
skipped src/root_command.sh (exists)
created ./rndm
run ./rndm --help to test your bash script
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this time Bashly skipped the &lt;code&gt;src/root_command.sh&lt;/code&gt; creation (because it already exists). Just the final &lt;code&gt;rndm&lt;/code&gt; script was generated again, this time with our new code.&lt;/p&gt;

&lt;p&gt;If we run the program a few times we'll see a different random number after each execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm
8783

$ ./rndm
32008

$ ./rndm
12550
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Done! That's all we want for now!&lt;/p&gt;

&lt;p&gt;Commit the changes and let's pick another feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling &lt;code&gt;--options&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Some people take randomness very seriously (especially those who deal with cryptography). There's even a web service called &lt;a href="https://random.org/" rel="noopener noreferrer"&gt;random.org&lt;/a&gt; self-described as "a &lt;strong&gt;true&lt;/strong&gt; random number service that generates randomness via atmospheric noise". Well, I don't know exactly what "atmospheric noise" means, but as the site exists since 1998 and is still running, I'm assuming they're good at randomness.&lt;/p&gt;

&lt;p&gt;A cool thing about the site is that they offer an endpoint from where we can get random numbers. Here's an example of how we can get one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://www.random.org/integers/?num=1&amp;amp;min=0&amp;amp;max=32767&amp;amp;col=1&amp;amp;base=10&amp;amp;format=plain"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to understand each parameter being passed to the endpoint, you can check the &lt;a href="https://www.random.org/clients/http/api/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;. But if you want to keep your focus on learning Bashly, stay with me...&lt;/p&gt;

&lt;p&gt;Let's assume some of our users want True Randomness™, instead of a simple &lt;code&gt;echo $RANDOM&lt;/code&gt;. Then let's make our program pick numbers from random.org.&lt;/p&gt;

&lt;p&gt;What I have in mind is to provide the &lt;code&gt;--web&lt;/code&gt; option so we can tell our program to get the number from the web. The first step is to put this in our &lt;code&gt;src/bashly.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rndm&lt;/span&gt;
&lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prints a random number&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.1&lt;/span&gt;

&lt;span class="c1"&gt;# specifying flags&lt;/span&gt;
&lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# long version:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;long&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--web&lt;/span&gt;
    &lt;span class="c1"&gt;# also a short version:&lt;/span&gt;
    &lt;span class="na"&gt;short&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-w&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the random number from &amp;lt;https://random.org&amp;gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With just this YAML we can run &lt;code&gt;bashly generate&lt;/code&gt; and check the help message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bashly generate
creating user files in src
skipped src/root_command.sh (exists)
created ./rndm
run ./rndm --help to test your bash script

$ ./rndm --help
rndm - Prints a random number

Usage:
  rndm [OPTIONS]
  rndm --help | -h
  rndm --version | -v

Options:
  --web, -w
    Get the random number from &amp;lt;https://random.org&amp;gt;.

  --help, -h
    Show this help

  --version, -v
    Show version number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How cool is that?! A neat help message generated with only a few lines in our YAML!&lt;/p&gt;

&lt;p&gt;Yeah, that's cool. But we still need to implement the feature.&lt;/p&gt;

&lt;p&gt;Let's understand how we can get this &lt;code&gt;--web&lt;/code&gt; flag in our code.&lt;/p&gt;

&lt;p&gt;When we pass a flag for our program, Bashly put it in an associative array named &lt;code&gt;$args&lt;/code&gt;, where each key is precisely the name of the flag. So, as we used &lt;code&gt;--web&lt;/code&gt;, in our code we access this data with &lt;code&gt;${args[--web]}&lt;/code&gt;. And as it's a boolean flag, with no arguments, the value here is &lt;code&gt;1&lt;/code&gt; to mean "true, the &lt;code&gt;--web&lt;/code&gt; option was passed".&lt;/p&gt;

&lt;p&gt;Note: even if we use the short version &lt;code&gt;-w&lt;/code&gt;, in our code we still access the value via &lt;code&gt;${args[--web]}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's use it in our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;

&lt;span class="c"&gt;# if we use `rndm --web` or `rndm -w`,&lt;/span&gt;
&lt;span class="c"&gt;# the ${args[--web]} will be '1'&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--web]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;curl &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"https://www.random.org/integers/?num=1&amp;amp;min=0&amp;amp;max=32767&amp;amp;col=1&amp;amp;base=10&amp;amp;format=plain"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RANDOM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now regenerate the script&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Smarter way to &lt;code&gt;bashly generate&lt;/code&gt;.
&lt;/h3&gt;

&lt;p&gt;You'll soon notice that we constantly run &lt;code&gt;bashly generate&lt;/code&gt; after each file change. This can be tedious and we can make it simpler. Open a new terminal and run:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bashly generate --watch
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Now Bashly will watch for changes and regenerate after any change is detected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's confirm the &lt;code&gt;--web&lt;/code&gt; option works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # numbers generated locally
$ ./rndm
2934

$ ./rndm
16891

$ # numbers coming from random.org
$ ./rndm --web
18253

$ ./rndm -w
137
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the commands above you'll notice that when we run &lt;code&gt;rndm --web&lt;/code&gt; the answer takes some milliseconds more than the local version. Such latency is expected when we're using a distributed system. There's nothing we can do in our code to solve that.&lt;/p&gt;

&lt;p&gt;We can consider this feature as ready. So, now is a good moment for a commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Listing Dependencies
&lt;/h2&gt;

&lt;p&gt;When we added the option to get a number from the web we ended up introducing a dependency for our program: the &lt;code&gt;curl&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;If w run our program in an environment without &lt;code&gt;curl&lt;/code&gt;, it's going to crash with a message like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # environment without 'curl'
$ ./rndm --web
./rndm: line 17: curl: command not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, without &lt;code&gt;curl&lt;/code&gt; our program is not able to send a request to random.org. But we have better ways to tell our users they need to have &lt;code&gt;curl&lt;/code&gt; installed.&lt;/p&gt;

&lt;p&gt;We can edit our &lt;code&gt;src/bashly.yml&lt;/code&gt; and add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prints a random number&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.1&lt;/span&gt;

&lt;span class="c1"&gt;# specifying the dependencies&lt;/span&gt;
&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl&lt;/span&gt;

&lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;long&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--web&lt;/span&gt;
    &lt;span class="na"&gt;short&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-w&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the random number from &amp;lt;https://random.org&amp;gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: from now on I'm assuming you're using &lt;code&gt;bashly generate --watch&lt;/code&gt; and I won't be telling you to regenerate after each change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's check the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # environment without 'curl'
$ ./rndm --web
missing dependency: curl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's slightly better than the "command not found at line 17", isn't it?&lt;/p&gt;

&lt;p&gt;Time for a new commit and move on...&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Our Code Modular
&lt;/h2&gt;

&lt;p&gt;Let's check our code again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--web]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;curl &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"https://www.random.org/integers/?num=1&amp;amp;min=0&amp;amp;max=32767&amp;amp;col=1&amp;amp;base=10&amp;amp;format=plain"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RANDOM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although it's simple, I'm willing to give names to these operations. Example: rather than that big &lt;code&gt;curl&lt;/code&gt; I want to call &lt;code&gt;get_random_number_from_web&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To reach such goal we need to create functions, and for that we're going to create a directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/lib/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we create a file named &lt;code&gt;src/lib/random_number_functions.sh&lt;/code&gt; and create the functions there, this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/lib/random_number_functions.sh&lt;/span&gt;

generate_random_number&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RANDOM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

get_random_number_from_web&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  curl &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"https://www.random.org/integers/?num=1&amp;amp;min=0&amp;amp;max=32767&amp;amp;col=1&amp;amp;base=10&amp;amp;format=plain"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After doing this 👆 we can now make our &lt;code&gt;src/root_command.sh&lt;/code&gt; much more pleasant to read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--web]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;get_random_number_from_web
&lt;span class="k"&gt;else
  &lt;/span&gt;generate_random_number
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your &lt;code&gt;rndm&lt;/code&gt; (you regenerated it, right?) and make sure things are working as expected.&lt;/p&gt;

&lt;p&gt;A cool thing to notice is that Bashly took the contents of &lt;code&gt;src/lib/random_number_functions.sh&lt;/code&gt; and put in the final script (the &lt;code&gt;rndm&lt;/code&gt; file). That's why we can call the functions we've created with no need to &lt;code&gt;source&lt;/code&gt; anything.&lt;/p&gt;

&lt;p&gt;You can keep in mind that Bashly take the contents of any &lt;code&gt;src/lib/*.sh&lt;/code&gt; file and puts them in the final script. Therefore, it's a good way to make your code modular, allowing you to keep each file focused on solving one kind of problem (aka Separation of Concerns). Your bash code can be more readable and organized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;--options-with arguments&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes we want to generate a random number up to a given limit. For example to simulate rolling a dice. For such situation I'd like to have a command like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# prints a random number between 1 and 6&lt;/span&gt;
rndm &lt;span class="nt"&gt;--max&lt;/span&gt; 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create such option we need to add in our YAML a flag that accepts an argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rndm&lt;/span&gt;
&lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prints a random number&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.1&lt;/span&gt;

&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl&lt;/span&gt;

&lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;long&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--web&lt;/span&gt;
    &lt;span class="na"&gt;short&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-w&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the random number from &amp;lt;https://random.org&amp;gt;.&lt;/span&gt;

  &lt;span class="c1"&gt;# specifying a flag that accepts an argument&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;long&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--max&lt;/span&gt;
    &lt;span class="na"&gt;arg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;max_num&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Specifies the maximum number to be generated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before writing any code, let's check the help message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm --help
rndm - Prints a random number

Usage:
  rndm [OPTIONS]
  rndm --help | -h
  rndm --version | -v

Options:
  --web, -w
    Get the random number from &amp;lt;https://random.org&amp;gt;.

  --max MAX_NUM
    Specifies the maximum number to be generated

  --help, -h
    Show this help

  --version, -v
    Show version number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An interesting detail: as we passed &lt;code&gt;arg: max_num&lt;/code&gt; in the YAML, Bashly does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;understand that the &lt;code&gt;--max&lt;/code&gt; flag requires an argument&lt;/li&gt;
&lt;li&gt;mentions such requirement in the help message&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although we used the name &lt;code&gt;max_num&lt;/code&gt;, this name is &lt;strong&gt;not&lt;/strong&gt; used in our code (it's used only in the help message).&lt;/p&gt;

&lt;p&gt;In our code we get the value given to the &lt;code&gt;--max&lt;/code&gt; via &lt;code&gt;${args[--max]}&lt;/code&gt;. Let's get this value in &lt;code&gt;src/root_command.sh&lt;/code&gt; and then pass it to our functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;

&lt;span class="c"&gt;# note that the '--max' argument is&lt;/span&gt;
&lt;span class="c"&gt;# obtained via '${args[--max]}':&lt;/span&gt;
&lt;span class="nv"&gt;max_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--max]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# we're putting it in a 'max_number' variable&lt;/span&gt;
&lt;span class="c"&gt;# just to use it more easily below.&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--web]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;get_random_number_from_web &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;generate_random_number &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to make use if it in our functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/lib/random_number_functions.sh&lt;/span&gt;

generate_random_number&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;max_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="c"&gt;# new logic to generate a number up to a number&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;RANDOM &lt;span class="o"&gt;%&lt;/span&gt; max_number &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

get_random_number_from_web&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;max_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  curl &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"https://www.random.org/integers/?num=1&amp;amp;min=0&amp;amp;max=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;max_number&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;col=1&amp;amp;base=10&amp;amp;format=plain"&lt;/span&gt;
    &lt;span class="c"&gt;# specify the maximum value passed to random.org 👆&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run it sometimes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm --max 6
5

$ ./rndm --max 6
1

$ ./rndm --max 6
4

$ # from the web
$ ./rndm --max 6 -w
6

$ ./rndm --max 6 -w
4

$ # not specifying a maximum value
$ ./rndm
./rndm: line 29: RANDOM % max_number + 1: division by 0 (error token is "max_number + 1")

$ ./rndm --web
Error: The maximum value must be an integer in the [-1000000000,1000000000] interval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😱 - What?! Scary bugs!&lt;/p&gt;

&lt;p&gt;If the user doesn't specify a &lt;code&gt;--max&lt;/code&gt; value, our scripts crash.&lt;/p&gt;

&lt;p&gt;Let's solve it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Assigning a Default Value to an Argument
&lt;/h3&gt;

&lt;p&gt;As we saw, our code is buggy! We ended up making it mandatory a max number to be given.&lt;/p&gt;

&lt;p&gt;We can solve this by defining a default value. The question is: which value should we use as default?&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;rndm --web&lt;/code&gt; error message we can see that the maximum is 1,000,000,000 (one billion). However, our local version is not that powerful...&lt;/p&gt;

&lt;p&gt;In the Bash manpage we can see (in the "Shell Variables" session) that the &lt;code&gt;$RANDOM&lt;/code&gt; generates an integer between 0 and 32,767. So, for consistency sake, let's set the default as &lt;code&gt;32767&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The good news is that Bashly offers a simple way to define a default value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rndm&lt;/span&gt;
&lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prints a random number&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.1&lt;/span&gt;

&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl&lt;/span&gt;

&lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;long&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--web&lt;/span&gt;
    &lt;span class="na"&gt;short&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-w&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the random number from &amp;lt;https://random.org&amp;gt;.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;long&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--max&lt;/span&gt;
    &lt;span class="na"&gt;arg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;max&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Specifies the maximum number to be generated&lt;/span&gt;
    &lt;span class="c1"&gt;# Look how simple!&lt;/span&gt;
    &lt;span class="c1"&gt;# NOTE: the "double-quotes" are mandatory,&lt;/span&gt;
    &lt;span class="c1"&gt;#       so the value is seen as a string.&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;32767"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the help:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm --help
rndm - Prints a random number

Usage:
  rndm [OPTIONS]
  rndm --help | -h
  rndm --version | -v

Options:
  --web, -w
    Get the random number from &amp;lt;https://random.org&amp;gt;.

  --max MAX_NUMBER
    Specifies the maximum number to be generated
    Default: 32767

  --help, -h
    Show this help

  --version, -v
    Show version number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool! It puts clearly for the user what's the default value! 👍&lt;/p&gt;

&lt;p&gt;Now let's see if it actually works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm
8654

$ ./rndm
26564

$ ./rndm --web
9511

$ ./rndm --web --max 100
45

$ ./rndm --web --max 100
3

$ ./rndm --max 100
88
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apparently it's fine, but let's try to mess things up: 😈&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm --max texto
./rndm: line 29: RANDOM % max_number + 1: division by 0 (error token is "max_number + 1")

$ ./rndm --max texto --web
Error: The maximum value must be an integer in the [-1000000000,1000000000] interval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😖 - Ouch!&lt;/p&gt;

&lt;p&gt;This feature looked innocent but brought a lot of headaches for us to handle... 😓&lt;/p&gt;

&lt;h3&gt;
  
  
  Validating Arguments
&lt;/h3&gt;

&lt;p&gt;To fix the invalid input bug we'll need to add a validation logic. Such validation needs to ensure the argument is a positive integer.&lt;/p&gt;

&lt;p&gt;Let's solve this with this regular expression: &lt;code&gt;^[1-9][0-9]*$&lt;/code&gt;. Which means "a digit between 1 and 9 followed by any amount of digits between 0 and 9".&lt;/p&gt;

&lt;p&gt;Our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;

&lt;span class="nv"&gt;max_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--max]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# abort execution if max_number is not a positive integer&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^[1-9][0-9]&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"The argument must be a positive integer. Given value: &lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--web]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;get_random_number_from_web &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;generate_random_number &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm --max texto
The argument must be a positive integer. Given value: texto

$ ./rndm --max -1
The argument must be a positive integer. Given value: -1

$ ./rndm
26509
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, apparently it's fine. But I don't like this logic polluting my main code. Let's move it to its own file named &lt;code&gt;src/lib/validations.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/lib/validations.sh&lt;/span&gt;

validate_positive_integer&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; is_positive_integer &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"The argument must be a positive integer. Given value: &lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# personal rule:&lt;/span&gt;
&lt;span class="c"&gt;# if something is done with a regular expression,&lt;/span&gt;
&lt;span class="c"&gt;# it needs to be wrapped in a function (or variable)&lt;/span&gt;
&lt;span class="c"&gt;# with a meaningful name.&lt;/span&gt;
is_positive_integer&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^[1-9][0-9]&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our main code can be simpler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;

&lt;span class="nv"&gt;max_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--max]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 👇 calling validation here&lt;/span&gt;
validate_positive_integer &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--web]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;get_random_number_from_web &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;generate_random_number &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm it's still working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm --max texto
The argument must be a positive integer. Given value: texto

$ ./rndm --max -1
The argument must be a positive integer. Given value: -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's a nice time for a new commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validating Arguments the Bashly way
&lt;/h3&gt;

&lt;p&gt;Although we are already validating the &lt;code&gt;--max&lt;/code&gt; input by calling &lt;code&gt;validate_positive_integer&lt;/code&gt; from our &lt;code&gt;src/root_command.sh&lt;/code&gt;, Bashly offers a cleaner way to execute such validation. In a way where we remove the reference to the validations from our code and keep our code tidy and focused on random numbers generation.&lt;/p&gt;

&lt;p&gt;The Bashly way to make validations works this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the flag configuration we add a line like this: &lt;code&gt;validate: function_name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a function called &lt;code&gt;validate_function_name&lt;/code&gt;, which will be automatically called before the user input is used.&lt;/li&gt;
&lt;li&gt;If the function prints anything to stdout, that's considered an error. The content is print as an error message and the program aborts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let's apply this to our program.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: add &lt;code&gt;validate: positive_integer&lt;/code&gt; in our &lt;code&gt;src/bashly.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rndm&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;

&lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;long&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--max&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="c1"&gt;# 👇👇👇 just add this line&lt;/span&gt;
    &lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;positive_integer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: create a function named &lt;code&gt;validate_positive_integer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We already did it in the previous section. The function is saved in &lt;code&gt;src/lib/validations.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: the function needs to print something to stdout to be considered a failure&lt;/p&gt;

&lt;p&gt;Our function already does that. The only thing to be changed is that we don't need an explicit &lt;code&gt;exit 1&lt;/code&gt;, as this is going to be handled by Bashly. Therefore, the new version is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/lib/validations.sh&lt;/span&gt;

validate_positive_integer&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; is_positive_integer &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"The argument must be a positive integer. Given value: &lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice! Let's test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./rndm
26086

$ ./rndm --max 0
validation error in --max MAX_NUMBER:
The argument must be a positive integer. Given value: 0

$ ./rndm --max texto
validation error in --max MAX_NUMBER:
The argument must be a positive integer. Given value: texto

$ ./rndm --max -1
validation error in --max MAX_NUMBER:
The argument must be a positive integer. Given value: -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool! Bashly even improved the error message, making it clear that the validation failure is related to the &lt;code&gt;--max&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;OK, we did this validation &lt;em&gt;a-la-Bashly&lt;/em&gt; but our main code is still calling the validation function (which is not needed anymore). Let's clean that up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/root_command.sh&lt;/span&gt;

&lt;span class="nv"&gt;max_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--max]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[--web]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;get_random_number_from_web &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;generate_random_number &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$max_number&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much easier on the eyes, isn't it? 🤩&lt;/p&gt;

&lt;p&gt;Make new tests and confirm everything works fine. Alright... Maybe you'll find more edge-cases to be addressed. But for our purpose of showing how to start working with Bashly I think we're done.&lt;/p&gt;

&lt;p&gt;Make a new commit and we're going to finish this first part of the tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finishing (for now)
&lt;/h2&gt;

&lt;p&gt;I'd like to call your attention for a moment and invite you to appreciate our &lt;code&gt;src/root_command.sh&lt;/code&gt; again. Look how simple that code is.&lt;/p&gt;

&lt;p&gt;Check also the directory structure of our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree
.
├── rndm
└── src
    ├── bashly.yml
    ├── lib
    │   ├── random_number_functions.sh
    │   └── validations.sh
    └── root_command.sh

2 directories, 5 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From those 5 files, only 3 (small) ones are actual bash code, with specific goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;validations.sh&lt;/code&gt;: responsible for input validation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;random_number_functions.sh&lt;/code&gt;: storing the functions that actually bring random numbers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;root_command.sh&lt;/code&gt;: the entrypoint of our application, calling the right function based on user input.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's remember all the details we didn't need to spend energy on because Bashly solved for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a professional help message&lt;/li&gt;
&lt;li&gt;dependency checking&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--options&lt;/code&gt; parsing&lt;/li&gt;
&lt;li&gt;call the right input validation&lt;/li&gt;
&lt;li&gt;code modularization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is just a short intro to Bashly. If you want me to write more about this topic, leave a comment below! Bashly has more features to explore!&lt;/p&gt;

&lt;h2&gt;
  
  
  Main Takeaways
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;bashly&lt;/code&gt; command
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bashly is a Ruby gem that depends on Ruby 3.2+.

&lt;ul&gt;
&lt;li&gt;No Ruby knowledge is necessary to use Bashly&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The &lt;code&gt;bashly generate&lt;/code&gt; command reads the &lt;code&gt;src/bashly.yml&lt;/code&gt; file and generates the final script

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;bashly generate --watch&lt;/code&gt; to monitor changes and automatically generate.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Files
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;src/bashly.yml&lt;/code&gt; file is a YAML that acts like an interface contract between our application and the user.

&lt;ul&gt;
&lt;li&gt;We can specify dependencies via &lt;code&gt;dependencies:&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The &lt;code&gt;src/root_command.sh&lt;/code&gt; file is the application's "entry point."&lt;/li&gt;

&lt;li&gt;Files in &lt;code&gt;src/lib/*.sh&lt;/code&gt; are all included in the final script.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Command Line Arguments
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Flags

&lt;ul&gt;
&lt;li&gt;Values are stored in &lt;code&gt;${args[--flag-name]}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Boolean flags have a value of &lt;code&gt;1&lt;/code&gt; when used&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Argument validation:

&lt;ul&gt;
&lt;li&gt;In the flag configuration: &lt;code&gt;validate: function_name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;validate_function_name&lt;/code&gt; function will be executed before using the user's input.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;validate_function_name&lt;/code&gt; prints anything to stdout, the program aborts.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://bashly.dev" rel="noopener noreferrer"&gt;Bashly official documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>Learn TDD with Ruby - Loops, Blocks and Strings</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Thu, 24 Oct 2024 00:28:36 +0000</pubDate>
      <link>https://forem.com/meleu/learn-tdd-with-ruby-loops-blocks-and-strings-36he</link>
      <guid>https://forem.com/meleu/learn-tdd-with-ruby-loops-blocks-and-strings-36he</guid>
      <description>&lt;p&gt;When we want to do something repeatedly, we use loops. There are many ways to create loops in Ruby, in this chapter we're going to see a couple of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text Banner
&lt;/h2&gt;

&lt;p&gt;We're going to write a method that adds a decoration to a string to make it look like it's in a banner, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;================
this is a banner
================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting the &lt;code&gt;banner&lt;/code&gt; project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# define TDD_RUBY_PATH in your shell configuration&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$TDD_RUBY_PATH&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;banner
&lt;span class="nb"&gt;cd &lt;/span&gt;banner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let's start with the test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write the test first
&lt;/h3&gt;

&lt;p&gt;Here's our first test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'minitest/autorun'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'banner'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestBanner&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_banner&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"====&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;====&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe you felt a little uncomfortable with that hard-to-read value assigned to &lt;code&gt;expected&lt;/code&gt;. Yeah, me too.&lt;/p&gt;

&lt;p&gt;I think that mentally counting the amount of &lt;code&gt;=&lt;/code&gt;s to put above and below the text is very error prone. It can make future maintainer's life worse (keep in mind that the future maintainer can be you). Let's find a better way to write that.&lt;/p&gt;

&lt;h4&gt;
  
  
  Here Documents
&lt;/h4&gt;

&lt;p&gt;A &lt;a href="https://ruby-doc.org/current/syntax/literals_rdoc.html#label-Here+Document+Literals" rel="noopener noreferrer"&gt;here document&lt;/a&gt; (aka heredoc) is a more comfortable way to read a multilinear block of text. In our case, as we want to check if the borders of the banner have the proper length in a quick glance, we would use a heredoc like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_banner&lt;/span&gt;
  &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class="no"&gt;BANNER&lt;/span&gt;&lt;span class="sh"&gt;
    ====
    text
    ====
&lt;/span&gt;&lt;span class="no"&gt;  BANNER&lt;/span&gt;
  &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're using a "squiggly heredoc" so we can have indented content between the opening identifier (&lt;code&gt;&amp;lt;&amp;lt;~BANNER&lt;/code&gt;) and the closing one (&lt;code&gt;BANNER&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Check the &lt;a href="https://ruby-doc.org/current/syntax/literals_rdoc.html#label-Here+Document+Literals" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; if you need more info about heredocs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write the minimal amount of code for the test to run
&lt;/h3&gt;

&lt;p&gt;Running the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;banner_test.rb:2:in `require_relative': cannot load such file -- /path/to/banner (LoadError)
        from banner_test.rb:2:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As expected, we got an &lt;strong&gt;error&lt;/strong&gt; (not a &lt;strong&gt;failure&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Keep the discipline!&lt;/em&gt; You don't need to know anything new to make the test fail properly.&lt;/p&gt;

&lt;p&gt;All you need to do right now is write enough code to make the test &lt;strong&gt;fail&lt;/strong&gt; with no &lt;strong&gt;errors&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you let the error messages drive the development you'll end up with a file named &lt;code&gt;banner.rb&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test and now it should &lt;strong&gt;fail&lt;/strong&gt; with no errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write enough code to make the test pass
&lt;/h3&gt;

&lt;p&gt;In order to create the banner we need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;check how many characters there are in the given string&lt;/li&gt;
&lt;li&gt;put the &lt;code&gt;=&lt;/code&gt; character the same amount of times as the length of the given string, above and below the string&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  String length
&lt;/h4&gt;

&lt;p&gt;For our first goal, we can check the String class documentation and look if it has a method to give us the length of a string. Turns out that such method is the &lt;a href="https://ruby-doc.org/current/String.html#method-i-length" rel="noopener noreferrer"&gt;String#length&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's experiment in &lt;code&gt;irb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IRB SESSION&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; 3&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'meleu'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; 5&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'long string with many words...'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; 30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, that's exactly what we need!&lt;/p&gt;

&lt;p&gt;Moving on...&lt;/p&gt;

&lt;h4&gt;
  
  
  Loops and Blocks
&lt;/h4&gt;

&lt;p&gt;One of the simplest ways to create a loop in Ruby is by using &lt;a href="https://ruby-doc.org/current/Integer.html#method-i-times" rel="noopener noreferrer"&gt;the Integer#times method&lt;/a&gt;. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Learn Ruby with TDD"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this code in &lt;code&gt;irb&lt;/code&gt; and you'll see that it prints &lt;code&gt;Learn Ruby with TDD&lt;/code&gt; 5 times.&lt;/p&gt;

&lt;p&gt;Although that code is easy to read, almost like natural language, the way it's written can be new for us, programmers.&lt;/p&gt;

&lt;p&gt;In that code we're using the &lt;code&gt;#times&lt;/code&gt; method and also a &lt;em&gt;block&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Blocks are frequently used in Ruby. It's like a way of bundling up a set of instructions for use elsewhere.&lt;/p&gt;

&lt;p&gt;In our code above, the block starts with the keyword &lt;code&gt;do&lt;/code&gt; and ends with the &lt;code&gt;end&lt;/code&gt;. The block is being passed to the &lt;code&gt;#times&lt;/code&gt; method to be executed.&lt;/p&gt;

&lt;p&gt;We're going to talk more about blocks, but for now that's enough.&lt;/p&gt;

&lt;h4&gt;
  
  
  Concatenating Strings
&lt;/h4&gt;

&lt;p&gt;The simplistic way to concatenate strings is by using the &lt;code&gt;+&lt;/code&gt; plus sign, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IRB SESSION&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'meleu'&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "meleu"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Hello, '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Hello, meleu"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to append content to a variable we could use the &lt;code&gt;+=&lt;/code&gt; operator, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IRB SESSION&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Hello"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s1"&gt;', meleu'&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Hello, meleu"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Hello, meleu"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although it's possible to append contents to a string variable with the &lt;code&gt;+=&lt;/code&gt; operator, the most usual Rubyist way to do it is by using the &lt;a href="https://ruby-doc.org/current/String.html#method-i-3C-3C" rel="noopener noreferrer"&gt;shovel operator&lt;/a&gt;: &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IRB SESSION&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Hello"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;', meleu'&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Hello, meleu"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Hello, meleu"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final result can look like the same, but there are subtle differences between &lt;code&gt;+=&lt;/code&gt; and &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;. The most notable one is that using &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; has a better performance, specially when used in a loop, which is our case. Let's stick with the &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/q/4684446" rel="noopener noreferrer"&gt;This StackOverflow Q&amp;amp;A&lt;/a&gt; has some good answers about the differences between &lt;code&gt;+=&lt;/code&gt; and &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;. Including some code where you can prove the difference in performance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  First implementation
&lt;/h4&gt;

&lt;p&gt;Let's recap what we've just learned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the string length with &lt;code&gt;text.length&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Repeat instructions in a loop &lt;code&gt;x&lt;/code&gt; times by

&lt;ul&gt;
&lt;li&gt;bundling up a set of instructions in a block&lt;/li&gt;
&lt;li&gt;passing the block to &lt;code&gt;x.times&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Append contents to a string variable with &lt;code&gt;var &amp;lt;&amp;lt; 'more content'&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Combining these techniques we can create a text banner function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# create an empty string&lt;/span&gt;
  &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;

  &lt;span class="c1"&gt;# get the text length and call the&lt;/span&gt;
  &lt;span class="c1"&gt;# .times method to create a loop&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="c1"&gt;# appending '=' to the border&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# interpolating the border before and after the text&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've put some comments just to explain what we're doing now. In the refactor phase we're going to clean them up.&lt;/p&gt;

&lt;p&gt;Maybe the only thing that require an extra explanation is the &lt;code&gt;text.length.times&lt;/code&gt; expression. We can use that because &lt;code&gt;String#length&lt;/code&gt; returns an Integer, and then we can use &lt;code&gt;Integer#times&lt;/code&gt;, which is what creates the loop&lt;/p&gt;

&lt;p&gt;Let's run the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Run options: --seed 15260

# Running:

.

Finished in 0.000478s, 2092.0506 runs/s, 2092.0506 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! A successful test triggers our brain to make that decision: refactor or commit?&lt;/p&gt;

&lt;p&gt;Let's refactor!&lt;/p&gt;

&lt;h3&gt;
  
  
  Refactor
&lt;/h3&gt;

&lt;p&gt;I'd like to use this refactoring session to talk about blocks again...&lt;/p&gt;

&lt;h5&gt;
  
  
  Bracket Blocks
&lt;/h5&gt;

&lt;p&gt;When a block contains just a single instruction, it's usual to use &lt;code&gt;{&lt;/code&gt; brackets &lt;code&gt;}&lt;/code&gt; to delimiter the block, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Learn Ruby with TDD"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this 👆 in &lt;code&gt;irb&lt;/code&gt; and confirm.&lt;/p&gt;

&lt;p&gt;With this new knowledge we can make our code shorter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test and you'll see that it's still working fine.&lt;/p&gt;

&lt;h4&gt;
  
  
  String multiplication
&lt;/h4&gt;

&lt;p&gt;One interesting thing in &lt;a href="https://ruby-doc.org/current/String.html#method-i-2A" rel="noopener noreferrer"&gt;String documentation&lt;/a&gt; is that we can use &lt;code&gt;string * integer&lt;/code&gt; to get a new string containing &lt;code&gt;integer&lt;/code&gt; copies of the original &lt;code&gt;string&lt;/code&gt;. Like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Ho! "&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Ho! Ho! Ho! "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an example of how expressive the Ruby language can be.&lt;/p&gt;

&lt;p&gt;With this knowledge we can refactor our banner function so it doesn't even need a loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test to confirm this is working as expected, and then we're done with this feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add banner_test.rb banner.rb
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'feat(banner): put text in a banner'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  New requirements
&lt;/h2&gt;

&lt;p&gt;Let's imagine we released our software to the world. This is when the "real work" begins: maintaining our software. We start to see our code being used in ways we didn't anticipate, and bugs start to appear.&lt;/p&gt;

&lt;p&gt;A few days after publishing our code a user submitted a bug report saying that it doesn't work with multiline strings.&lt;/p&gt;

&lt;p&gt;When we receive a bug report the very first thing to do is to reproduce it. Let's do it in &lt;code&gt;irb&lt;/code&gt; (be sure to be in the same directory as your code):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IRB SESSION #&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# yeah! we can require code in irb too!&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'banner'&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; true&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"this is&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;a multiline&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;string"&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "this is\na multiline\nstring"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# confirming it's multiline&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;multiline&lt;/span&gt;
&lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; nil&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==========================&lt;/span&gt;
&lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;multiline&lt;/span&gt;
&lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="o"&gt;==========================&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, that's not what we would expect from the banner code. We didn't envisaged this use case when we were developing. Such situation is one of the most common things in the day-to-day work of a professional developer, we must get used to it.&lt;/p&gt;

&lt;p&gt;In fact this situation is so common that more than fifty years ago a computer scientist named &lt;a href="https://en.wikipedia.org/wiki/Manny_Lehman_(computer_scientist)" rel="noopener noreferrer"&gt;Manny Lehman&lt;/a&gt; already noticed that and said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A system must be continually adapted or it becomes progressively less satisfactory.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the first of the eight &lt;a href="https://en.wikipedia.org/wiki/Lehman's_laws_of_software_evolution" rel="noopener noreferrer"&gt;Lehman's laws of software evolution&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we confirmed that the bug report is valid. Then let's &lt;del&gt;fix it&lt;/del&gt; reproduce it in a test case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write the test first
&lt;/h3&gt;

&lt;p&gt;We expect the borders to be as long as the longest line, then let's write a test for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_banner_with_multiple_lines&lt;/span&gt;
  &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class="no"&gt;BANNER&lt;/span&gt;&lt;span class="sh"&gt;
    =============
    text
    with multiple
    lines
    =============
&lt;/span&gt;&lt;span class="no"&gt;  BANNER&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"text&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;with multiple&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;lines"&lt;/span&gt;
  &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test to see the error/failure message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  1) Failure:
TestBanner#test_banner_with_multiple_lines [banner_test.rb:25]:
--- expected
+++ actual
@@ -1,6 +1,6 @@
-"=============
+"========================
 text
 with multiple
 lines
-=============
+========================
 "
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good thing that the test &lt;strong&gt;failed&lt;/strong&gt; with &lt;strong&gt;no errors&lt;/strong&gt;, but we still need to sort the failure.&lt;/p&gt;

&lt;p&gt;The output shows exactly the difference between the expected and the actual borders, while the text in between remains the same.&lt;/p&gt;

&lt;p&gt;Now that we have a good test, we can work on our fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write enough code to make the test pass
&lt;/h3&gt;

&lt;p&gt;If our border needs to be as long as the longest line in the string, we need a way to check each line length.&lt;/p&gt;

&lt;h4&gt;
  
  
  Iterating over each line of a String
&lt;/h4&gt;

&lt;p&gt;In the String class page we can see &lt;a href="https://ruby-doc.org/current/String.html#method-i-each_line" rel="noopener noreferrer"&gt;a method called &lt;code&gt;#each_line&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When we call &lt;code&gt;String#each_line&lt;/code&gt; giving a block to it, it creates substrings that are the result of splitting the original string at each occurrence of a new line. The new thing for us here is that &lt;code&gt;#each_line&lt;/code&gt; needs a place (a variable) to where it puts the created substring. In this case we need to use a block with a parameter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Block Parameters
&lt;/h4&gt;

&lt;p&gt;When the instructions within our block need to reference the value they're currently working with, we specify a block parameter. Let's see an example in &lt;code&gt;irb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IRB SESSION&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"multi&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;line&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;string"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_line&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="s2"&gt;"multi&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="s2"&gt;"line&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="s2"&gt;"string"&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "multi\nline\nstring"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In each iteration the substring is stored in the &lt;code&gt;line&lt;/code&gt; variable and we can use it however we want. In the example above we're just inspecting it with &lt;a href="https://ruby-doc.org/current/Kernel.html#method-i-p" rel="noopener noreferrer"&gt;the &lt;code&gt;Kernel#p&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That looks promising! 🙂&lt;/p&gt;

&lt;h4&gt;
  
  
  Longest line
&lt;/h4&gt;

&lt;p&gt;Let's use what we've learned to check the longest line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# assume the max_length is zero&lt;/span&gt;
  &lt;span class="n"&gt;max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="c1"&gt;# loop over each line and check if its length &amp;gt; max_length&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_line&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
    &lt;span class="n"&gt;max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="c1"&gt;# create the border&lt;/span&gt;
  &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;

  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the loop above we're checking if the current line length is longer than &lt;code&gt;max_length&lt;/code&gt;. If that's true, then we update the value of &lt;code&gt;max_length&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Running the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  1) Failure:
TestBanner#test_banner_with_multiple_lines [banner_test.rb:25]:
--- expected
+++ actual
@@ -1,6 +1,6 @@
-"=============
+"==============
 text
 with multiple
 lines
-=============
+==============
 "
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whoops! Looks like there's an extra &lt;code&gt;=&lt;/code&gt; character in the border.&lt;/p&gt;

&lt;p&gt;The reason for this is that &lt;code&gt;String#each_line&lt;/code&gt; creates substrings by splitting the original string at the occurrences of a new line, &lt;em&gt;but it preserves the newline character&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We could see that in our &lt;code&gt;irb&lt;/code&gt; session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IRB SESSION #&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"multi&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;line&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;string"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_line&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="s2"&gt;"multi&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="s2"&gt;"line&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="s2"&gt;"string"&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "multi\nline\nstring"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, in order to accurately get the length of a line we must ignore the trailing newline character. Fortunately we ha method for that: &lt;a href="https://ruby-doc.org/current/String.html#method-i-chomp" rel="noopener noreferrer"&gt;String#chomp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This time you check by yourself on &lt;code&gt;irb&lt;/code&gt;. Try it with a string like &lt;code&gt;"meleu\n"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the new version of our code using &lt;code&gt;#chomp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_line&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="c1"&gt;# using chomp 👇 here&lt;/span&gt;
    &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
    &lt;span class="n"&gt;max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;

  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests and they should pass now.&lt;/p&gt;

&lt;p&gt;Time for refactoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refactor
&lt;/h3&gt;

&lt;p&gt;I think our banner code is starting to accumulate too much logic in it. It should be a function that just puts borders above and below a given text.&lt;/p&gt;

&lt;p&gt;Unfortunately real world is not that simple. We found a need to handle the case where the input text has multiple lines. Our &lt;code&gt;banner&lt;/code&gt; is handling this but its complexity increased. This situation reminds another one of the &lt;a href="https://en.wikipedia.org/wiki/Lehman's_laws_of_software_evolution" rel="noopener noreferrer"&gt;Lehman's laws&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;As a system evolves, its complexity increases unless work is done to maintain or reduce it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We need to proactively fight against this increasing complexity. In our case here we're going to achieve this by delegating the longest-line-detection logic to a separate function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;max_line_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;max_line_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_line&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
    &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;max&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests and they should pass.&lt;/p&gt;

&lt;p&gt;For now I think I'm happy with this version. So, let's move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add banner_test.rb banner.rb
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'fix(banner): handle multiline text'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ruby
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Heredocs&lt;/li&gt;
&lt;li&gt;Loops with &lt;code&gt;Integer#times&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Blocks

&lt;ul&gt;
&lt;li&gt;with &lt;code&gt;do&lt;/code&gt;/&lt;code&gt;end&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;with &lt;code&gt;{&lt;/code&gt; brackets &lt;code&gt;}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;with a parameter&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;String methods

&lt;ul&gt;
&lt;li&gt;concatenating with &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; (aka shovel operator)&lt;/li&gt;
&lt;li&gt;string "multiplication" with &lt;code&gt;*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;length&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;each_line&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chomp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reinforced TDD practices (write test first!)&lt;/li&gt;
&lt;li&gt;After receiving a bug report:

&lt;ul&gt;
&lt;li&gt;first reproduce it in a test case&lt;/li&gt;
&lt;li&gt;then start working on the fix&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Software Engineering
&lt;/h3&gt;

&lt;p&gt;The two first &lt;a href="https://en.wikipedia.org/wiki/Lehman's_laws_of_software_evolution" rel="noopener noreferrer"&gt;Lehman's laws of software evolution&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Continuing Change&lt;/strong&gt;: A system must be continually adapted or it becomes progressively less satisfactory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Increasing Complexity&lt;/strong&gt;: As a system evolves, its complexity increases unless work is done to maintain or reduce it.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ruby</category>
      <category>tdd</category>
      <category>minitest</category>
      <category>rails</category>
    </item>
    <item>
      <title>Learn TDD with Ruby - Objects, Methods and Integers</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Wed, 11 Sep 2024 16:46:48 +0000</pubDate>
      <link>https://forem.com/meleu/objects-methods-and-integers-40jo</link>
      <guid>https://forem.com/meleu/objects-methods-and-integers-40jo</guid>
      <description>&lt;p&gt;Ruby is an Object-Oriented Programming (OOP) language, which means that (almost) everything we interact with is an object. That includes basic data types like numbers, strings and even &lt;code&gt;nil&lt;/code&gt;. Every value in Ruby has an underlying object representation and can be manipulated with methods.&lt;/p&gt;

&lt;p&gt;Ruby is also known to be "weakly typed", which means that type checking is not strictly enforced. This feature allows variables to change types dynamically at runtime. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;      &lt;span class="c1"&gt;# x is an Integer&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt; &lt;span class="c1"&gt;# x is now a String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The object-oriented approach combined with the dynamic type system make Ruby a powerful and flexible language. In this chapter we're going to use these features to code an integer to binary converter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integer to Binary Converter
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://simple.wikipedia.org/wiki/Binary_number" rel="noopener noreferrer"&gt;binary numeral system&lt;/a&gt; is a way to write numbers using only two digits: &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;. As it only needs two digits, we can say it's a &lt;em&gt;base two&lt;/em&gt; number system.&lt;/p&gt;

&lt;p&gt;For computers the binary system is extremely efficient because they need to store information in only two simple different states: "on" or "off" (&lt;code&gt;1&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt;). Sets of binary numbers can be used to represent any information, such as text, audio, or video.&lt;/p&gt;

&lt;p&gt;For the code we're going to work on this chapter I'm assuming you at least know what a binary number is and that it's a &lt;em&gt;base two&lt;/em&gt; number system (uses only two digits to represent the possible values).&lt;/p&gt;

&lt;p&gt;You don't need to know the math needed to convert a decimal number to binary notation (Ruby has convenient ways to do it). But I'm assuming you know that the binary &lt;code&gt;1001&lt;/code&gt; is not one thousand and one (you don't even need to know that it's nine).&lt;/p&gt;

&lt;p&gt;If you need more information on this topic, &lt;a href="https://simple.wikipedia.org/wiki/Binary_number" rel="noopener noreferrer"&gt;this Wikipedia page&lt;/a&gt; can be a good start.&lt;/p&gt;

&lt;p&gt;Now let's start our &lt;em&gt;Integer to Binary Converter™&lt;/em&gt; project following the TDD cycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a test&lt;/li&gt;
&lt;li&gt;Run the test, see it fails and check the error message&lt;/li&gt;
&lt;li&gt;Write enough code to make the test pass&lt;/li&gt;
&lt;li&gt;Refactor&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&gt;

&lt;p&gt;We still have no idea about how to implement this converter, but by looking at the &lt;a href="https://simple.wikipedia.org/wiki/Binary_number" rel="noopener noreferrer"&gt;Wikipedia page about binary numbers&lt;/a&gt; we can see a table with some equivalents. Here are some examples:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;decimal&lt;/th&gt;
&lt;th&gt;binary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;11&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;100&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;101&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;110&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;code&gt;111&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1000&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Alright, let's choose one of these values and write our first test. I choose 8.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;int2bin_test.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"minitest/autorun"&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s2"&gt;"int2bin"&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestInt2Bin&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_convert_8&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1000"&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run this test and see it failing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the minimal amount of code to for the test to run
&lt;/h2&gt;

&lt;p&gt;When we run the tests, check the error and write the minimal amount of code to fix the error, we're letting the tests guide our development. That's a core concept of Test-Driven Development.&lt;/p&gt;

&lt;p&gt;So let's start the cycle of checking the test error message and trying to solve what the message says.&lt;/p&gt;

&lt;p&gt;In the very first run we see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ruby int2bin_test.rb

int2bin_test.rb:2:in `require_relative': cannot load such file -- /path/to/int2bin (LoadError)
        from int2bin_test.rb:2:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, we're requiring a file that doesn't exist. Then let's create the file, run the test again and see the next error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # creating the file
$ touch int2bin.rb

$ # running the test
$ ruby int2bin_test.rb

# Running:

E

Finished in 0.000271s, 3690.0373 runs/s, 0.0000 assertions/s.

  1) Error:
TestInt2Bin#test_convert_8:
NoMethodError: undefined method `int2bin' for #&amp;lt;TestInt2Bin:0x00000001348f40f0&amp;gt;
    int2bin_test.rb:7:in `test_convert_8'

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the error message says &lt;code&gt;NoMethodError: undefined method 'int2bin' ...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's create that method in our &lt;code&gt;int2bin.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;int2bin&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test, check the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1) Error:
TestInt2Bin#test_convert_8:
ArgumentError: wrong number of arguments (given 1, expected 0)
    /path/to/int2bin.rb:1:in `int2bin'
    int2bin_test.rb:7:in `test_convert_8'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's fix the &lt;code&gt;wrong number of arguments&lt;/code&gt; in our &lt;code&gt;int2bin.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test, check the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  1) Failure:
TestInt2Bin#test_convert_8 [int2bin_test.rb:8]:
Expected: "1000"
  Actual: nil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our test is actually running with no errors, but it's failing. We're almost there!&lt;/p&gt;

&lt;p&gt;At this point you may be thinking that you're wasting your time in this tedious loop of running the test, checking the error message and writing the minimal amount of code to fix the error message. I have two points about this practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is a nice way to prevent over-engineering - your tests are the requirements in form of code, and your software just needs to meet such requirements.&lt;/li&gt;
&lt;li&gt;You'll soon find ways to automatically run tests right after saving your file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if my arguments are not convincing you, please stick with this practice while we're here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write enough code to make the test pass
&lt;/h2&gt;

&lt;p&gt;The failure message says that the expected result is &lt;code&gt;"1000"&lt;/code&gt; but it received &lt;code&gt;nil&lt;/code&gt;. So, let's fix this like a pedantic programmer and "write the minimal amount of code to make the test pass":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"1000"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ah hah! Foiled again! TDD is a sham, right?&lt;/p&gt;

&lt;p&gt;Maybe we should add another test to &lt;code&gt;int2bin_test.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_convert_2&lt;/span&gt;
  &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10"&lt;/span&gt;
  &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Running:

F.

Finished in 0.000265s, 7547.1687 runs/s, 7547.1687 assertions/s.

  1) Failure:
TestInt2Bin#test_convert_2 [int2bin_test.rb:14]:
Expected: "10"
  Actual: "1000"

2 runs, 2 assertions, 1 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If our pedantic instincts evolve to the point where we want to be a prick, we could add an if in our code just to answer with &lt;code&gt;"10"&lt;/code&gt; when the argument is &lt;code&gt;2&lt;/code&gt;. But that feels like &lt;a href="https://en.m.wikipedia.org/wiki/Cat_and_mouse" rel="noopener noreferrer"&gt;a game of cat and mouse&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's stop here and start to work on the code that will actually convert an integer to its binary representation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rubyists best friends
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Everything" is an Object
&lt;/h3&gt;

&lt;p&gt;In the beginning of this chapter I said: &lt;strong&gt;every value in Ruby has an underlying object representation and can be manipulated with methods&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That includes the integer numbers. They are objects and we can interact with them using their methods.&lt;/p&gt;

&lt;p&gt;Another fact about Ruby objects is that all of them have a string representation that can be obtained by the &lt;code&gt;#to_s&lt;/code&gt; method (&lt;code&gt;to_s&lt;/code&gt; stands for "to string").&lt;/p&gt;

&lt;p&gt;As our goal is to convert an integer to its binary representation, and this representation is written in a string, maybe we can get some help from &lt;code&gt;Integer#to_s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now is the perfect time to know two great friends of all Rubyists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Ruby documentation&lt;/li&gt;
&lt;li&gt;the Interactive Ruby Shell, aka &lt;code&gt;irb&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ruby documentation
&lt;/h3&gt;

&lt;p&gt;Here's one of our great friends: &lt;a href="https://ruby-doc.org/" rel="noopener noreferrer"&gt;https://ruby-doc.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we want to work on Integers, we need to check the documentation about the Integer class: &lt;a href="https://ruby-doc.org/current/Integer.html" rel="noopener noreferrer"&gt;https://ruby-doc.org/current/Integer.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In that page we can see a pretty decent amount of information about Integers.Iincluding what they can do, in other words, which methods they have.&lt;/p&gt;

&lt;p&gt;We don't need to read all that page, but use it as a reference when needed. As we are suspecting the &lt;code&gt;Integer#to_s&lt;/code&gt; can help us, now is a good momento to use it. So let's take a look at &lt;a href="https://ruby-doc.org/current/Integer.html#method-i-to_s" rel="noopener noreferrer"&gt;its documentation&lt;/a&gt; (below I bring only the part related to our problem):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;to_s(base = 10) → string&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns a string containing the place-value representation of &lt;code&gt;self&lt;/code&gt; in radix &lt;code&gt;base&lt;/code&gt; (in 2..36).&lt;/p&gt;


&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;     &lt;span class="c1"&gt;# =&amp;gt; "12345"&lt;/span&gt;
&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; "11000000111001"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Hey! That looks promising! The method accepts an argument that acts as the base for the string representation we want to get from the integer. As the binary system uses base two, let's check if it can be used in our converter.&lt;/p&gt;

&lt;p&gt;Before opening our code editor and writing our implementation, let's play a bit with our next great friend...&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive Ruby Shell (&lt;code&gt;irb&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;irb&lt;/code&gt; is an awesome way to quickly try things out with no need to put code in a file, save it and call it from the command line. You just need to type the code and check the results.&lt;/p&gt;

&lt;p&gt;In order to use the Interactive Ruby Shell you just need to type &lt;code&gt;irb&lt;/code&gt; in your terminal. You should see something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ irb

irb(main):001:0&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see this, you're in the &lt;code&gt;irb&lt;/code&gt; prompt. Here you can type Ruby code and see the results immediately.&lt;/p&gt;

&lt;p&gt;In our case, we want to check if &lt;code&gt;Integer#to_s&lt;/code&gt; is able to give us a binary representation of an integer. So, let's try it with &lt;code&gt;8.to_s(2)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;irb(main):001:0&amp;gt; 8.to_s(2)
=&amp;gt; "1000"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah! That seems to be exactly what we want! Let's try different values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;irb(main):002:0&amp;gt; 7.to_s(2)
=&amp;gt; "111"
irb(main):003:0&amp;gt; 2.to_s(2)
=&amp;gt; "10"
irb(main):004:0&amp;gt; 0.to_s(2)
=&amp;gt; "0"
irb(main):005:0&amp;gt; 15.to_s(2)
=&amp;gt; "1111"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright! I'm convinced! Let's use this method in our converter.&lt;/p&gt;

&lt;p&gt;By the way: you can use &lt;code&gt;exit&lt;/code&gt; to go out from &lt;code&gt;irb&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First implementation
&lt;/h2&gt;

&lt;p&gt;Now that we know &lt;code&gt;Integer#to_s&lt;/code&gt; can solve our problem, let's use it in our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Running:

..

Finished in 0.000261s, 7662.8350 runs/s, 7662.8350 assertions/s.

2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! All tests passing means that it's time to refactor. But, uhm... there's no much room for refactoring in single line function.&lt;/p&gt;

&lt;p&gt;Let's just use our current code in an application.&lt;/p&gt;

&lt;h2&gt;
  
  
  i2b CLI
&lt;/h2&gt;

&lt;p&gt;Now that we have working software, backed by tests, we should be safe to use it in a "real" application.&lt;/p&gt;

&lt;p&gt;Let's write an extremely simple application that reads a number from user's input and prints the binary representation of the number.&lt;/p&gt;

&lt;p&gt;Create a file named exactly like this: &lt;code&gt;i2b&lt;/code&gt;. Note that there's no &lt;code&gt;.rb&lt;/code&gt; extension in the file.&lt;/p&gt;

&lt;p&gt;Here are the contents to be put in the &lt;code&gt;i2b&lt;/code&gt; file. Don't worry if you don't understand everything, I'm going to explain right away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s2"&gt;"int2bin"&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"integer: "&lt;/span&gt;
&lt;span class="n"&gt;my_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;gets&lt;/span&gt;

&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"binary: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quickly explaining the code above:&lt;/p&gt;

&lt;p&gt;In the very first line we're putting a &lt;a href="https://en.wikipedia.org/wiki/Shebang_(Unix)" rel="noopener noreferrer"&gt;shebang&lt;/a&gt; to tell our OS which interpreter we wan to use to execute the commands in this file, in our case we're telling the OS to use the &lt;code&gt;ruby&lt;/code&gt; executable found in the user's &lt;code&gt;PATH&lt;/code&gt; (it's not necessary to know all the details here, but if you're curious &lt;a href="https://dev.to/meleu/what-the-shebang-really-does-and-why-it-s-so-important-in-your-shell-scripts-2755"&gt;this article&lt;/a&gt; can help).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;print&lt;/code&gt; method is just like &lt;code&gt;puts&lt;/code&gt;, but it doesn't add a trailing newline. This is useful to keep the cursor right in front of the &lt;code&gt;integer:&lt;/code&gt; string.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;gets&lt;/code&gt; method is used to get user's input. It returns the data submitted by the user, and we store it in the &lt;code&gt;my_number&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;The rest of the code should be familiar to you and easy to understand.&lt;/p&gt;

&lt;p&gt;In order to run this program, we need to give the executable permission to the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod a+x i2b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're ready to run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./i2b
integer: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice. It's waiting for our input. Let's give it a number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./i2b
integer: 7
/path/to/int2bin.rb:2:in `to_s': wrong number of arguments (given 1, expected 0) (ArgumentError)
        from /path/to/int2bin.rb:2:in `int2bin'
        from ./i2b:8:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😳 How could this happen? We used TDD to code our function and it passed the tests!&lt;/p&gt;

&lt;p&gt;That's time to tell you a truth about Test-Driven Development: TDD is not a way to &lt;em&gt;assure&lt;/em&gt; your code does not have bugs.&lt;/p&gt;

&lt;p&gt;TDD is a way to facilitate and guide development, giving you short feedback loops (as you don't need to test your software manually) and lead your implementation to a better design.&lt;/p&gt;

&lt;p&gt;Although TDD can reduce &lt;em&gt;a lot&lt;/em&gt; the appearance of bugs, &lt;em&gt;making sure&lt;/em&gt; your code doesn't have bugs is not something TDD can promise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging with &lt;code&gt;irb&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;After this kinda frustrating news, let's try to understand what's wrong on our code. Check the main part of the error message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/path/to/int2bin.rb:2:in `to_s': wrong number of arguments (given 1, expected 0) (ArgumentError)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The message says that the error happened in &lt;code&gt;int2bin.rb:2&lt;/code&gt;, which means in the 2nd line of the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 👈 ERROR HAPPENED HERE&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The message also says that we passed a wrong number of arguments to the &lt;code&gt;to_s&lt;/code&gt; method. But in the documentation we saw that &lt;code&gt;Integer#to_s&lt;/code&gt; accepts an argument. 🤔 Uhm... Is that &lt;code&gt;number&lt;/code&gt; really an &lt;code&gt;Integer&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;In order to check that we're going to turn again to one of our best friends: &lt;code&gt;irb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ruby provides a way to open an &lt;code&gt;irb&lt;/code&gt; session from anywhere in your program using &lt;code&gt;binding.irb&lt;/code&gt;. This is helpful for debugging and is exactly what we need now.&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;binding.irb&lt;/code&gt; right before the buggy line. Your &lt;code&gt;int2bin.rb&lt;/code&gt; should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;irb&lt;/span&gt;
  &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's repeat the steps where we faced the error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./i2b
integer: 7
From: /path/to/int2bin.rb @ line 2 :

    1: def int2bin(number)
 =&amp;gt; 2:   binding.irb
    3:   number.to_s(2)
    4: end

irb(main):001:0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're on the &lt;code&gt;irb&lt;/code&gt; prompt, right before the point where the crash happened. How cool is that?! 🙂&lt;/p&gt;

&lt;p&gt;Let's check what exactly is in the &lt;code&gt;number&lt;/code&gt; variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;irb(main):001:0&amp;gt; number
=&amp;gt; "7\n"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👀 That's a String composed of a character &lt;code&gt;7&lt;/code&gt; followed by a newline. That means that our &lt;code&gt;int2bin&lt;/code&gt; function was called with a String as an argument!&lt;/p&gt;

&lt;p&gt;Let's check our &lt;code&gt;i2b&lt;/code&gt; again, adding some notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s2"&gt;"int2bin"&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"integer: "&lt;/span&gt;
&lt;span class="n"&gt;my_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;gets&lt;/span&gt;            &lt;span class="c1"&gt;# 👈 my_number IS ASSIGNED HERE&lt;/span&gt;

&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 👈 int2bin IS CALLED HERE&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"binary: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're assigning a value to &lt;code&gt;my_number&lt;/code&gt; with &lt;code&gt;gets&lt;/code&gt;, which returns the user's input &lt;em&gt;as a String&lt;/em&gt;. When we pass this string to &lt;code&gt;#int2bin&lt;/code&gt; it calls &lt;code&gt;String#to_s&lt;/code&gt; instead of &lt;code&gt;Integer#to_s&lt;/code&gt;. And if we check the &lt;a href="https://ruby-doc.org/current/String.html#method-i-to_s" rel="noopener noreferrer"&gt;String#to_s documentation&lt;/a&gt;, we'll see that it doesn't accept an argument. That's why our program is crashing!&lt;/p&gt;

&lt;p&gt;This is an example of how Ruby's dynamism is a double-edged sword. It can be powerful and allow rapid development, but also requires extra attention. In this case the lack of type checking allowed us to pass an unexpected data type that crashed our application.&lt;/p&gt;

&lt;p&gt;Now, before working in a solution for this bug, we'll apply another valuable testing practice: &lt;strong&gt;when you find a bug, replicate it in a test case &lt;em&gt;before fixing it&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: once we found the bug, we can now remove the &lt;code&gt;binding.irb&lt;/code&gt; line from our &lt;code&gt;int2bin.rb&lt;/code&gt; code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replicate bugs in tests
&lt;/h3&gt;

&lt;p&gt;Let's write a test giving the problematic String to the &lt;code&gt;int2bin&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_convert_7_as_string&lt;/span&gt;
  &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"111"&lt;/span&gt;
  &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"7&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test and see if the crash was really replicated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  1) Error:
TestInt2Bin#test_convert_7_as_string:
ArgumentError: wrong number of arguments (given 1, expected 0)
    /path/to/int2bin.rb:2:in `to_s'
    /path/to/int2bin.rb:2:in `int2bin'
    int2bin_test.rb:19:in `test_convert_7_as_string'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice! Now we can start working on a solution and quickly check if we're on the right path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing the bug
&lt;/h3&gt;

&lt;p&gt;Fortunately we can easily solve this issue by converting the string to an Integer using the &lt;code&gt;String#to_i&lt;/code&gt; method (&lt;a href="https://ruby-doc.org/current/String.html#method-i-to_i" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;). It's also fortunate that this method is also available for Integers (&lt;a href="https://ruby-doc.org/current/Integer.html#method-i-to_i" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This is an example of how the Ruby's dynamism can promote rapid development. If we were coding with a strongly typed language, we would need to code different functions to allow receiving different data types. With Ruby we can code only one function and work on ways to handle the dynamic typing. As you can notice, everything is a trade-off (and if you're reading until here, you probably like Ruby's dynamism).&lt;/p&gt;

&lt;p&gt;In order to fix the bug we just need to chain &lt;code&gt;to_i&lt;/code&gt; and &lt;code&gt;to_s&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;int2bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests and they should be passing now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Concepts
&lt;/h2&gt;

&lt;p&gt;Let's recap what we learned in this chapter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;OOP: everything in Ruby is an object&lt;/li&gt;
&lt;li&gt;Dynamic typing: variables can change types at runtime&lt;/li&gt;
&lt;li&gt;String representation: all objects have a &lt;code&gt;to_s&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;It wasn't explicitly said but you probably noticed: the Rubyist way to write method names is using &lt;code&gt;snake_case&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ruby-doc.org/" rel="noopener noreferrer"&gt;Ruby documentation&lt;/a&gt;: essential resource of information.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;irb&lt;/code&gt;: quickly experiment Ruby code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;binding.irb&lt;/code&gt; is a useful debugging technique&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gets&lt;/code&gt;: read user's input&lt;/li&gt;
&lt;li&gt;method chaining: calling multiple methods in sequence (e.g.: &lt;code&gt;number.to_i.to_s(2)&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  TDD
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test-first approach: write the test before implementation code.&lt;/li&gt;
&lt;li&gt;Minimal implementation: write just enough code to make the tests pass (without being pedantic, please).&lt;/li&gt;
&lt;li&gt;TDD guides the development, but does not assure our software is free of bugs.&lt;/li&gt;
&lt;li&gt;Replicating bugs in tests: add test cases for discovered issues before fixing.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>tdd</category>
      <category>minitest</category>
      <category>rails</category>
    </item>
    <item>
      <title>Learn TDD with Ruby - Hello, World</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Tue, 27 Aug 2024 22:54:38 +0000</pubDate>
      <link>https://forem.com/meleu/learn-ruby-and-tdd-at-the-same-time-2en1</link>
      <guid>https://forem.com/meleu/learn-ruby-and-tdd-at-the-same-time-2en1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is an attempt to teach the basics of Ruby and TDD (with Minitest) at the same time.&lt;/p&gt;

&lt;p&gt;It's mainly aimed at people who already know how to code and want to quickly learn such topics.&lt;/p&gt;

&lt;p&gt;It's heavily inspired by the first chapter of the awesome &lt;a href="https://quii.gitbook.io/" rel="noopener noreferrer"&gt;Learn Go with Tests&lt;/a&gt;, by &lt;a href="https://quii.dev/" rel="noopener noreferrer"&gt;Chris James&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you enjoy this, please leave a comment and share so I can measure the interest and &lt;strong&gt;maybe&lt;/strong&gt; evolve this to a free book (still inspired by "Learn Go with Tests" but focused on idiomatic Ruby and Object-Oriented Programming).&lt;/p&gt;

&lt;p&gt;It's assumed you already have Ruby installed. The code here were tested on Ruby 3.2.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Hello, World
&lt;/h2&gt;

&lt;p&gt;It is traditional for your first program in a new language to be &lt;a href="https://en.m.wikipedia.org/wiki/%22Hello,_World!%22_program" rel="noopener noreferrer"&gt;Hello, World&lt;/a&gt;. This is going to be the fanciest "Hello, world" program you will ever write!&lt;/p&gt;

&lt;p&gt;Open your terminal and create a &lt;code&gt;hello&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file called &lt;code&gt;hello.rb&lt;/code&gt; and put the following code inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello, World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run it type &lt;code&gt;ruby hello.rb&lt;/code&gt; in your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;puts&lt;/code&gt; instruction stands for "Put String", and what it does is to put the string you give to it in the output.&lt;/p&gt;

&lt;p&gt;In our code we're giving the "Hello, World" string.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to test
&lt;/h2&gt;

&lt;p&gt;How do you test this program? It is good to separate your "domain" code from the outside world (side-effects). The &lt;code&gt;puts&lt;/code&gt; is a side effect (printing to stdout), and the string we send in is our domain.&lt;/p&gt;

&lt;p&gt;So, let's separate these concerns so it's easier to test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello, world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have defined a new function with &lt;code&gt;def&lt;/code&gt; and we're returning the string &lt;code&gt;"Hello, world"&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Idiomatic Ruby
&lt;/h3&gt;

&lt;p&gt;I'd like to call your attention to the fact that the code above has a lot of parentheses. If you're coming from another programming language you may think it's perfectly normal.&lt;/p&gt;

&lt;p&gt;In Ruby the use of these parentheses are usually optional. They may be required to clear up what may otherwise be ambiguous in the syntax, but in simple cases the Ruby programmers usually omit them.&lt;/p&gt;

&lt;p&gt;Let's code like a real Rubyist, then let's clear the unnecessary parentheses from our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Hello, world"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another Ruby syntactic sugar is that the last evaluated expression of a ruby function is always returned. Therefore the use of the &lt;code&gt;return&lt;/code&gt; in the last line is unnecessary.&lt;/p&gt;

&lt;p&gt;So, let's clear our code a little more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, world"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's much easier on the eyes, don't you agree?&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing your first test
&lt;/h3&gt;

&lt;p&gt;Now create a new file called &lt;code&gt;hello_test.rb&lt;/code&gt; where we are going to write a test for our &lt;code&gt;hello&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'minitest/autorun'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'hello'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestHello&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_hello&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, world"&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to run the test.&lt;/p&gt;

&lt;p&gt;Enter &lt;code&gt;ruby hello_test.rb&lt;/code&gt; in your terminal and you should see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ruby hello_test.rb
Hello, world
Run options: --seed 20392

# Running:

.

Finished in 0.001096s, 912.1682 runs/s, 912.1682 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see something similar to this 👆 then your test passed!&lt;/p&gt;

&lt;p&gt;Don't worry (for now) if parts of this output looks cryptic, we'll learn about that soon.&lt;/p&gt;

&lt;p&gt;Just to check, try deliberately breaking the test by changing the &lt;code&gt;expected&lt;/code&gt; string. You'll notice that the &lt;code&gt;.&lt;/code&gt; dot will be replaced with an &lt;code&gt;F&lt;/code&gt;, meaning that a Failure happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minitest "rules"
&lt;/h3&gt;

&lt;p&gt;Writing a test with Minitest is like writing a method in a class, but with some "rules" (some of them are not actual strict rules)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file should be named like &lt;code&gt;*_test.rb&lt;/code&gt; (not mandatory, but a good practice)&lt;/li&gt;
&lt;li&gt;The file do &lt;code&gt;require 'minitest/autorun'&lt;/code&gt; so we can easily run it from the command line.&lt;/li&gt;
&lt;li&gt;The file must &lt;code&gt;require_relative 'hello'&lt;/code&gt; so it can access the code being tested.&lt;/li&gt;
&lt;li&gt;The test must be written in a subclass of &lt;code&gt;Minitest::Test&lt;/code&gt; (don't worry if you still don't know what is a subclass)&lt;/li&gt;
&lt;li&gt;The test method must start with &lt;code&gt;test_&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The assertion determines if the test is to be considered successful or not. In this case we are asserting that the expected value is equal to the actual value using &lt;code&gt;assert_equal expected, actual&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this testing code we're covering some new Ruby concepts:&lt;/p&gt;

&lt;h4&gt;
  
  
  require and require_relative
&lt;/h4&gt;

&lt;p&gt;When a file needs the code defined in another file, one way to access it is requiring the "another file".&lt;/p&gt;

&lt;p&gt;When we use &lt;code&gt;require&lt;/code&gt;, we're getting the code from a package installed in our system (in Ruby we call such packages as "gems").&lt;/p&gt;

&lt;p&gt;When we use &lt;code&gt;require_relative&lt;/code&gt;, we're getting the code from a file stored in a path relative to the current file. In our case, as both &lt;code&gt;hello_test.rb&lt;/code&gt; and &lt;code&gt;hello.rb&lt;/code&gt; are in the same directory, we can simply use &lt;code&gt;require_relative 'hello'&lt;/code&gt; (yeah, you guessed right: the &lt;code&gt;.rb&lt;/code&gt; extension can be omitted).&lt;/p&gt;

&lt;h4&gt;
  
  
  creating a subclass
&lt;/h4&gt;

&lt;p&gt;In the code below we're creating a new class named &lt;code&gt;TestHello&lt;/code&gt; as a subclass of &lt;code&gt;Minitest::Test&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestHello&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The concept of class and subclass will be explained in another moment. For now just keep in mind that when we create the &lt;code&gt;TestHello&lt;/code&gt; as a subclass of &lt;code&gt;Minitest::Test&lt;/code&gt;, this means that &lt;code&gt;TestHello&lt;/code&gt; inherits the behavior defined in &lt;code&gt;Minitest::Test&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello, YOU
&lt;/h2&gt;

&lt;p&gt;Now that we have a test, we can iterate on our software safely.&lt;/p&gt;

&lt;p&gt;In the last example, we wrote the test &lt;em&gt;after&lt;/em&gt; the code had been written. We did this so that you could get an example of how to write a test and declare a function. From this point on, we will be &lt;em&gt;writing tests first&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Our next requirement is to specify the recipient of the greeting.&lt;/p&gt;

&lt;p&gt;Let's start by capturing these requirements in a test. This is basic test-driven development and allows us to make sure our test is &lt;em&gt;actually&lt;/em&gt; testing what we want. When you retrospectively write tests, there is the risk that your test may continue to pass even if the code doesn't work as intended.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'minitest/autorun'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'hello'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestHello&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_hello&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, meleu"&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"meleu"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run &lt;code&gt;ruby hello_test.rb&lt;/code&gt; and you should see a failure like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Running:

E

Finished in 0.001266s, 789.7771 runs/s, 0.0000 assertions/s.

  1) Error:
TestHello#test_hello:
ArgumentError: wrong number of arguments (given 1, expected 0)
    hello.rb:1:in `hello'
    hello_test.rb:7:in `test_hello'

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's important to pay attention to the error message here, it gives us the information we need to figure out what's wrong with our code.&lt;/p&gt;

&lt;p&gt;The Ruby interpreter is telling what you need to do to continue. In our test we passed an argument to the &lt;code&gt;hello&lt;/code&gt; function, but the function is not prepared to receive an argument. That's why Ruby is telling us: &lt;code&gt;wrong number of arguments (given 1, expected 0)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Edit the &lt;code&gt;hello&lt;/code&gt; function to accept an argument. Now your &lt;code&gt;hello.rb&lt;/code&gt; should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, world"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try and run your tests again, it will fail with a kinda scary message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/path/to/hello.rb:1:in `hello': wrong number of arguments (given 0, expected 1) (ArgumentError)
        from /path/to/hello.rb:5:in `&amp;lt;top (required)&amp;gt;'
        from hello_test.rb:2:in `require_relative'
        from hello_test.rb:2:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output looks different from what we saw before. But we can see that it's pointing that we're still passing a wrong number of arguments, but now it's complaining that we're giving 0 while &lt;code&gt;hello&lt;/code&gt; expects 1.&lt;/p&gt;

&lt;p&gt;The error happened when our test file were doing &lt;code&gt;require_relative 'hello'&lt;/code&gt; and the line &lt;code&gt;puts hello&lt;/code&gt; was reached. That line is being actually executed (we should move that &lt;code&gt;puts&lt;/code&gt; to a different file, but let's keep things simple for now).&lt;/p&gt;

&lt;p&gt;The line is calling &lt;code&gt;#hello&lt;/code&gt; with no arguments, but now it requires one. So let's fix that in &lt;code&gt;hello.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you run the tests you should see a failure with this message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  1) Failure:
TestHello#test_hello [hello_test.rb:8]:
Expected: "Hello, meleu"
  Actual: "Hello, world"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test is now failing because it's not meeting our requirements.&lt;/p&gt;

&lt;p&gt;Let's make the test pass by using the &lt;code&gt;name&lt;/code&gt; argument and interpolate it in the string being returned by &lt;code&gt;#hello&lt;/code&gt;. In Ruby, we do interpolation with &lt;code&gt;#{variable_name}&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run the tests now, it should pass.&lt;/p&gt;

&lt;p&gt;Normally, as part of the TDD cycle, we should now &lt;em&gt;refactor&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A note on source control
&lt;/h3&gt;

&lt;p&gt;At this point, if you are using source control (which you should!) you should &lt;code&gt;commit&lt;/code&gt; the code as it is. We have working software backed by a test.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add hello.rb hello_test.rb
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'hello-world, work in progress'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I &lt;em&gt;wouldn't&lt;/em&gt; push to main though, because I plan to refactor next. It is nice to commit at this point in case you somehow get into a mess with refactoring - you can always go back to the working version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello, world... again
&lt;/h2&gt;

&lt;p&gt;The next requirement is when our function is called with no arguments, it defaults to printing &lt;code&gt;Hello, world&lt;/code&gt;, rather than &lt;code&gt;Hello,&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As TDD practitioners, we write the &lt;em&gt;tests first&lt;/em&gt;, so let's write a new failing test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestHello&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_say_hello_to_people&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, meleu"&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"meleu"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_say_hello_world_when_called_with_no_arguments&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, world"&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do note that the test functions now have a descriptive (and long) name. It's important to give descriptive names to your tests, so you can know what to do when they fail.&lt;/p&gt;

&lt;p&gt;After running the tests we'll see an output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Running:

.E

Finished in 0.001415s, 1413.7393 runs/s, 706.8696 assertions/s.

  1) Error:
TestHello#test_say_hello_world_when_called_with_no_arguments:
ArgumentError: wrong number of arguments (given 0, expected 1)
    /path/to/hello.rb:1:in `hello'
    hello_test.rb:13:in `test_say_hello_world_when_called_with_no_arguments'

2 runs, 1 assertions, 0 failures, 1 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That error message is telling us that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;TestHello#test_say_hello_world_when_called_with_no_arguments&lt;/code&gt; failed&lt;/li&gt;
&lt;li&gt;it failed due to the &lt;code&gt;ArgumentError&lt;/code&gt;, because the &lt;code&gt;#hello&lt;/code&gt; expected 1 argument and we didn't give any.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's check our &lt;code&gt;#hello&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a dilema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;#hello&lt;/code&gt; expects an argument so we can use &lt;code&gt;hello("meleu")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;we also want to be able to call &lt;code&gt;#hello&lt;/code&gt; with no arguments and it should respond with &lt;code&gt;"Hello, world"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To achieve this we can define a default value for the &lt;code&gt;name&lt;/code&gt; argument, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we're defining a default value for the &lt;code&gt;name&lt;/code&gt; variable, calling &lt;code&gt;#hello&lt;/code&gt; with an argument is optional (if none is passed, it uses the default value).&lt;/p&gt;

&lt;p&gt;Run your tests and you should see a successful run. It satisfies the new requirement and we haven't accidentally broken the other functionality.&lt;/p&gt;

&lt;p&gt;It is important that your tests are &lt;em&gt;clear specifications&lt;/em&gt; of what the code needs to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back to source control
&lt;/h3&gt;

&lt;p&gt;Now that we are happy with the code, I would amend the previous commit so that we only check in the lovely version of our code with its test.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add hello.rb hello_test.rb
git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Discipline
&lt;/h3&gt;

&lt;p&gt;Let's go over the cycle again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a test&lt;/li&gt;
&lt;li&gt;Run the test, see it fails and check the error message&lt;/li&gt;
&lt;li&gt;Write enough code to make the test pass&lt;/li&gt;
&lt;li&gt;Refactor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the face of it this may seem tedious, but sticking to the feedback loop is important.&lt;/p&gt;

&lt;p&gt;Not only does it ensure that you have &lt;em&gt;relevant tests&lt;/em&gt;, it helps ensure &lt;em&gt;you design good software&lt;/em&gt; by refactoring with the safety of tests.&lt;/p&gt;

&lt;p&gt;Seeing the test fail is an important check because it also lets you see what the error message looks like. As a developer it can be very hard to work with a codebase when failing tests do not give a clear idea as to what the problem is.&lt;/p&gt;

&lt;p&gt;By ensuring your tests are &lt;em&gt;fast&lt;/em&gt; and setting up your tools so that running tests is simple, you can get in to a state of flow when writing your code.&lt;/p&gt;

&lt;p&gt;By not writing tests, you are committing to manually checking your code by running your software, which breaks your state of flow. You won't be saving yourself any time, especially in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep going! More requirements
&lt;/h2&gt;

&lt;p&gt;A new requirement arrived! We now need to support a second parameter, specifying the language of the greeting. If we don't recognize the language, default to English.&lt;/p&gt;

&lt;p&gt;We should be confident that we can easily use TDD to flesh out this functionality!&lt;/p&gt;

&lt;h3&gt;
  
  
  Hola
&lt;/h3&gt;

&lt;p&gt;Let's write a test for a user passing in Spanish and add it to the existing suite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_say_hello_in_spanish&lt;/span&gt;
  &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hola, Juan"&lt;/span&gt;
  &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Juan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"spanish"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember not to cheat! &lt;em&gt;Test first&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Running:

..E

Finished in 0.000772s, 3884.1235 runs/s, 2589.4157 assertions/s.

  1) Error:
TestHello#test_say_hello_in_spanish:
ArgumentError: wrong number of arguments (given 2, expected 0..1)
    /path/to/hello.rb:1:in `hello'
    hello_test.rb:19:in `test_say_hello_in_spanish'

3 runs, 2 assertions, 0 failures, 1 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that our software is still working for the two initial tests we already have, and failing only for the new one.&lt;/p&gt;

&lt;p&gt;We're again having an &lt;code&gt;ArgumentError: wrong number of arguments (given 2, expected 0..1)&lt;/code&gt;. That's because in our test we're calling &lt;code&gt;hello("Juan", "spanish")&lt;/code&gt;, with 2 arguments.&lt;/p&gt;

&lt;p&gt;Let's fix this by adding a new argument to &lt;code&gt;#hello&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's our attempt to write just enough code to make the test pass, based on the error message. Then, let's run the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Running:

FFE

Finished in 0.000895s, 3351.7981 runs/s, 2234.5321 assertions/s.

  1) Failure:
TestHello#test_say_hello_to_people [hello_test.rb:8]:
Expected: "Hello, meleu"
  Actual: "Hello, world"

  2) Failure:
TestHello#test_say_hello_in_spanish [hello_test.rb:20]:
Expected: "Hola, Juan"
  Actual: "Hello, Juan"

  3) Error:
TestHello#test_say_hello_world_when_called_with_no_arguments:
ArgumentError: wrong number of arguments (given 0, expected 1..2)
    /path/to/hello.rb:1:in `hello'
    hello_test.rb:13:in `test_say_hello_world_when_called_with_no_arguments'

3 runs, 2 assertions, 2 failures, 1 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😱 Our change broke all tests!!!&lt;/p&gt;

&lt;p&gt;Always keep this in mind: if your change breaks tests that are unrelated to your current work and that were previously succeeding, you're probably doing something wrong!&lt;/p&gt;

&lt;p&gt;Tests are a safety net that brings confidence to change the code with no fear. If tests fail because you've broken the code, the cure is simple: undo the last change and make a better one.&lt;/p&gt;

&lt;p&gt;In our case here we're breaking the previous tests because we added a new &lt;em&gt;mandatory&lt;/em&gt; argument: &lt;code&gt;language&lt;/code&gt;. In order to fix this we should make it optional by setting a default value for it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Running:

..F

Finished in 0.000799s, 3755.2759 runs/s, 3755.2759 assertions/s.

  1) Failure:
TestHello#test_say_hello_in_spanish [hello_test.rb:20]:
Expected: "Hola, Juan"
  Actual: "Hello, Juan"

3 runs, 3 assertions, 1 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good, now we have a failing test output with a clear direction about what must be done to make it pass. It's expecting a greeting with &lt;code&gt;Hola&lt;/code&gt; and our code is greeting with &lt;code&gt;Hello&lt;/code&gt;, so let's fix this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'spanish'&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hola'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests and you'll see it pass.&lt;/p&gt;

&lt;p&gt;That's great, but we want to make our fancy "Hello World" program to be not only bilingual, but a polyglot!&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonjour
&lt;/h3&gt;

&lt;p&gt;Let's add a test for the French language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_say_hello_in_french&lt;/span&gt;
  &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Bonjour, Jean'&lt;/span&gt;
  &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Jean'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'french'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test will fail with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  1) Failure:
TestHello#test_say_hello_in_french [hello_test.rb:26]:
Expected: "Bonjour, Jean"
  Actual: "Hello, Jean"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let's write enough code to make the test pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'spanish'&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hola'&lt;/span&gt;
  &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'french'&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Bonjour'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests and you'll see it pass.&lt;/p&gt;

&lt;p&gt;When our tests succeed after implementing a new feature, it's time to &lt;em&gt;refactor&lt;/em&gt;. Let's take this opportunity to learn how to use the &lt;code&gt;case&lt;/code&gt; statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'spanish'&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hola'&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'french'&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Bonjour'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the change run the tests again to make sure you didn't break anything.&lt;/p&gt;

&lt;p&gt;The code is working as expected, but I'm starting to feel like &lt;code&gt;#hello&lt;/code&gt; is accumulating too much logic in it. I want to create a new function just to handle the multilingual greeting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'spanish'&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hola'&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'french'&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Bonjour'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;greeting&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests and it should pass.&lt;/p&gt;

&lt;p&gt;Passing tests triggers a decision for us: refactor or stop coding this feature?&lt;/p&gt;

&lt;p&gt;I still want a refactoring to make the &lt;code&gt;#greeting&lt;/code&gt; function more idiomatic.&lt;/p&gt;

&lt;p&gt;Remember when I said that the last evaluated expression of a ruby function is always returned? The whole &lt;code&gt;case&lt;/code&gt; block is an expression and we can make it the last evaluated one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'spanish'&lt;/span&gt;
    &lt;span class="s1"&gt;'Hola'&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'french'&lt;/span&gt;
    &lt;span class="s1"&gt;'Bonjour'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="s1"&gt;'Hello'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests again and it should pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Olá, Hallo, Ciao, Konnichiwa...
&lt;/h3&gt;

&lt;p&gt;As an exercise add greetings for other languages.&lt;/p&gt;

&lt;p&gt;Remember the cycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a test&lt;/li&gt;
&lt;li&gt;Run the test, see it failing and check the error message&lt;/li&gt;
&lt;li&gt;Write enough code to make the test pass&lt;/li&gt;
&lt;li&gt;Refactor&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Concepts
&lt;/h2&gt;

&lt;p&gt;This is probably the fanciest &lt;code&gt;Hello, world&lt;/code&gt; you have ever written, isn't it?&lt;/p&gt;

&lt;p&gt;We learn a bunch of things here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;functions are defined with &lt;code&gt;def&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;parentheses in function calls are optional&lt;/li&gt;
&lt;li&gt;the last evaluated expression of a function is always returned&lt;/li&gt;
&lt;li&gt;string interpolation (e.g.: &lt;code&gt;"Hello, #{name}"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;if-else&lt;/code&gt; and &lt;code&gt;if-elsif-else&lt;/code&gt; statements&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;case&lt;/code&gt; statements&lt;/li&gt;
&lt;li&gt;how to write tests with Minitest&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  TDD
&lt;/h3&gt;

&lt;p&gt;The TDD process and &lt;em&gt;why&lt;/em&gt; the steps are important&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Write a failing test and see it fail&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;so we know we have written a &lt;em&gt;relevant&lt;/em&gt; test for our requirements&lt;/li&gt;
&lt;li&gt;and seen that it produces an &lt;em&gt;easy to understand description of the failure&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Writing the smallest amount of code to make it pass

&lt;ul&gt;
&lt;li&gt;so we know we have working software&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;Then&lt;/em&gt; refactor, backed with the safety of our tests

&lt;ul&gt;
&lt;li&gt;to ensure we have well-crafted code that is easy to work with&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;We've gone from &lt;code&gt;hello&lt;/code&gt; to &lt;code&gt;hello("name")&lt;/code&gt; and then to &lt;code&gt;hello("name", "french")&lt;/code&gt; in small and easy to understand steps.&lt;/p&gt;

&lt;p&gt;Of course this is trivial compared to "real-world" software, but the principles still stand.&lt;/p&gt;

&lt;p&gt;TDD is a skill that needs practice to develop, and by breaking problems down into smaller components that you can test, you will have a much easier time writing &lt;em&gt;and reading&lt;/em&gt; software.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>tdd</category>
      <category>minitest</category>
      <category>rails</category>
    </item>
    <item>
      <title>A melhor maneira que encontrei para aprender Ruby</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Sat, 03 Sep 2022 00:02:33 +0000</pubDate>
      <link>https://forem.com/meleu/a-melhor-maneira-que-encontrei-para-aprender-ruby-56d5</link>
      <guid>https://forem.com/meleu/a-melhor-maneira-que-encontrei-para-aprender-ruby-56d5</guid>
      <description>&lt;p&gt;Esse artigo contem uma lista de coisas que estão funcionando muito bem para o meu aprendizado da linguagem Ruby. Estou compartilhando aqui pois acredito que também possa ter alguma valia para pessoas que tenham um perfil parecido.&lt;/p&gt;

&lt;p&gt;Reforço que o objetivo aqui &lt;strong&gt;NÃO&lt;/strong&gt; é aprender programação (muito básico), e nem aprender a desenvolver aplicações web usando Ruby (muito avançado).&lt;/p&gt;

&lt;p&gt;O material que indico aqui tem o objetivo bem específico de &lt;strong&gt;ganhar fluência na linguagem Ruby o mais rápido possível&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versão Resumida
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Premissas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;saber ler em inglês.&lt;/li&gt;
&lt;li&gt;já ter alguma noção de programação.&lt;/li&gt;
&lt;li&gt;saber pelo menos os conceitos básicos de programação orientada a objetos.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Leia &lt;a href="http://tutorials.jumpstartlab.com/projects/ruby_in_100_minutes.html" rel="noopener noreferrer"&gt;Ruby in 100 Minutes&lt;/a&gt; para ter uma boa noção inicial da sintaxe.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Faça os desafios da &lt;a href="https://exercism.org/tracks/ruby" rel="noopener noreferrer"&gt;trilha Ruby no exercism.org&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Brinque com os &lt;a href="https://github.com/edgecase/ruby_koans" rel="noopener noreferrer"&gt;Ruby Koans&lt;/a&gt; para ir fixando os conceitos mais fundamentais da linguagem.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Premissas
&lt;/h2&gt;

&lt;p&gt;Os conteúdos listados aqui estão em inglês, portanto é importante saber ler nesse idioma.&lt;/p&gt;

&lt;p&gt;Para fazer os exercícios dos links que listo aqui, é muito conveniente que você se sinta confortável na linha de comando (se você é completamente novato, recomendo &lt;a href="https://youtube.com/playlist?list=PLXoSGejyuQGqJEEyo2fY3SA-QCKlF2rxO" rel="noopener noreferrer"&gt;esse conteúdo gratuito e em português produzido pelo Blau Araujo&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;O meu objetivo aqui &lt;strong&gt;não&lt;/strong&gt; é aprender a programar, estou assumindo que você já tenha alguma noção de programação. O objetivo aqui é adquirir fluência na linguagem Ruby.&lt;/p&gt;

&lt;p&gt;Algum conhecimento dos fundamentos de programação orientada a objetos pode ajudar, mas acredito não ser tããão necessário pra começar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contato inicial com a linguagem
&lt;/h2&gt;

&lt;p&gt;Se estiver com 1 hora e 20 minutos disponível, pode ser legal assistir o vídeo &lt;a href="https://www.akitaonrails.com/" rel="noopener noreferrer"&gt;Fábio Akita&lt;/a&gt; sobre &lt;a href="https://youtu.be/oEorhw5r2Do" rel="noopener noreferrer"&gt;A História do Ruby on Rails&lt;/a&gt;. Eu gostei bastante do vídeo e acabei conhecendo alguns conteúdos que parecem ser bem bacanas (mas que ainda não explorei a fundo).&lt;/p&gt;

&lt;p&gt;Se já quer partir pra ação, leia o &lt;a href="http://tutorials.jumpstartlab.com/projects/ruby_in_100_minutes.html" rel="noopener noreferrer"&gt;Ruby in 100 minutes&lt;/a&gt;. Aqui você vai conhecer a sintaxe básica da linguagem.&lt;/p&gt;

&lt;p&gt;Um exemplo de uma coisa que pra mim foi bem legal, foi entender o conceito de &lt;a href="http://tutorials.jumpstartlab.com/projects/ruby_in_100_minutes.html#6.-blocks" rel="noopener noreferrer"&gt;Blocks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Desafios do exercism
&lt;/h2&gt;

&lt;p&gt;Uma vez que já conhecemos o vocabulário básico da linguagem, vamos começar a botar a mão na massa e praticar.&lt;/p&gt;

&lt;p&gt;A minha recomendação é fazer os desafios presentes na &lt;a href="https://exercism.org/tracks/ruby" rel="noopener noreferrer"&gt;trilha de Ruby do exercism.org&lt;/a&gt;. Os exercícios começam bem simples e vão progredindo lentamente em complexidade.&lt;/p&gt;

&lt;p&gt;Recomendo sempre ficar atento a pegar os exercícios marcados como Easy. Mesmo que você resolva os problemas lógicas de maneira trivial, o objetivo aqui é ir pegando fluência na linguagem.&lt;/p&gt;

&lt;p&gt;Por mais que os exercícios iniciais possam parecer fáceis de resolver, o fato de estar escrevendo em Ruby vai criando aquela fluência que faz com que você comece a pensar diretamente usando a linguagem. Isso pra mim é um ganho gigantesco.&lt;/p&gt;

&lt;p&gt;Uma coisa que eu gosto de fazer é colocar as minhas soluções em um &lt;a href="https://github.com/meleu/exercism/" rel="noopener noreferrer"&gt;repositório no git&lt;/a&gt;, e ainda vou fazendo algumas anotações das coisas que aprendo em cada exercício. Você pode ver um &lt;a href="https://github.com/meleu/exercism/blob/master/ruby/README.md" rel="noopener noreferrer"&gt;exemplo das minhas anotações aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A seguir falo um pouco sobre o exercism. Se você já conhece a plataforma, pode pular essa parte...&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que o exercism é tão bom
&lt;/h3&gt;

&lt;p&gt;O &lt;a href="https://exercism.org" rel="noopener noreferrer"&gt;exercism.org&lt;/a&gt; é uma plataforma maravilhosa para adquirir fluência em qualquer linguagem (atualmente eles têm trilhas para 61 linguagens).&lt;/p&gt;

&lt;p&gt;Eu não conheço nenhuma alternativa de aprendizado de uma nova linguagem de programação que seja melhor do que o exercism.&lt;/p&gt;

&lt;p&gt;Eu sou um grande fã de aprender lendo livros, e continuo achando que livros são uma excelente fonte de referência. Mas digo que o exercism é melhor pra aprender e ganhar fluência, pelos seguintes motivos:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Os exercícios são do tipo &lt;em&gt;Test-Driven Development&lt;/em&gt; (TDD).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Isso significa que você vai resolver o problema proposto no desafio e vai rodar um teste que vai te dizer na hora se você conseguiu resolver o problema.&lt;/p&gt;

&lt;p&gt;Você pode ir aperfeiçoando (refatorando) seu código e ir executando os testes novamente para conferir novas maneiras de resolver o problema. Sem precisar ficar testando "na mão". Isso é muito maravilhoso! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Você vai aprender muito vendo as soluções submetidas por outras pessoas&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uma excelente maneira de aprender os "macetes" de uma determinada linguagem é você ver como que pessoas mais experientes naquela linguagem fazem.&lt;/p&gt;

&lt;p&gt;No exercism, uma vez que você submete a sua solução, você tem acesso às soluções das outras pessoas. E essa é uma excelente maneira de você ir aprendendo aquelas soluções idiomáticas, que fazem um bom uso das características específicas da linguagem.&lt;/p&gt;

&lt;p&gt;Eu recomendo muito que após submeter sua solução você gaste alguns minutinhos dando uma olhada no código das outras pessoas e tentar entender o que elas estão fazendo.&lt;/p&gt;

&lt;p&gt;Lembra que eu falei que estamos usando TDD? Pois então! Você pode pegar trechos de código dos colegas, testar na sua solução e rodar os testes novamente.&lt;/p&gt;

&lt;p&gt;Se você não entender o que o colega fez, você vai dar uma olhada na documentação oficial da linguagem e vai passar a entender.&lt;/p&gt;

&lt;p&gt;Repito: não conheço maneira mais efetiva de ganhar fluência numa linguagem de programação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ruby Koans - Reforçando os fundamentos da linguagem
&lt;/h2&gt;

&lt;p&gt;De acordo com a &lt;a href="https://pt.wikipedia.org/wiki/Koan" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Um &lt;em&gt;koan&lt;/em&gt; é uma narrativa, diálogo, questão ou afirmação do budismo zen que contém aspectos que são inacessíveis a razão. Desta forma, o &lt;em&gt;koan&lt;/em&gt; tem, como objetivo, propiciar a iluminação espiritual do praticante do budismo zen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK, isso parece viajação demais... Vamos abstrair essa parte filosófica e nos concentrar no aspecto técnico.&lt;/p&gt;

&lt;p&gt;Os Ruby Koans são testes que estão "quebrados" e que você terá que corrigir. E a medida que você vai corrigindo você vai aprendendo/fixando alguns conceitos mais fundamentais da linguagem Ruby.&lt;/p&gt;

&lt;p&gt;Eu achei uma abordagem muito bacana e me ajudou a enxergar facilmente algumas coisas sutis. Exemplo: o operador &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; "shovel" muda a string original quando fazemos algo desse tipo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;original_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, "&lt;/span&gt;
&lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_string&lt;/span&gt;
&lt;span class="n"&gt;there&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"World"&lt;/span&gt;
&lt;span class="c1"&gt;# o operador &amp;lt;&amp;lt; "shovel" aqui vai alterar&lt;/span&gt;
&lt;span class="c1"&gt;# ambos, 'hi' e 'original_string'&lt;/span&gt;
&lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;there&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Hello, World"&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;original_string&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Hello, World"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O site dos Ruby Koans é o &lt;a href="http://rubykoans.com/" rel="noopener noreferrer"&gt;http://rubykoans.com/&lt;/a&gt;, mas eu recomendo que você vá pelo repositório: &lt;a href="https://github.com/edgecase/ruby_koans" rel="noopener noreferrer"&gt;https://github.com/edgecase/ruby_koans&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aqui coloco um bizu bem direto ao ponto, mas recomendo que você consulte o README do repositório:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# clonando o repositório&lt;/span&gt;
git clone git@github.com:edgecase/ruby_koans.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ruby_koans

&lt;span class="c"&gt;# checando se o ruby está instalado&lt;/span&gt;
&lt;span class="c"&gt;# se não tiver, recomendo que use o asdf-vm&lt;/span&gt;
ruby &lt;span class="nt"&gt;--version&lt;/span&gt;
rake &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="c"&gt;# gerando os koans&lt;/span&gt;
rake gen

&lt;span class="c"&gt;# se no futuro você precisar/quiser gerar os&lt;/span&gt;
&lt;span class="c"&gt;# koans novamente para estudar desde o início,&lt;/span&gt;
&lt;span class="c"&gt;# use esse comando:&lt;/span&gt;
rake regen

&lt;span class="c"&gt;# para executar todos os testes na ordem sugerida:&lt;/span&gt;
rake
&lt;span class="c"&gt;# que é a mesma coisa que executar isso:&lt;/span&gt;
ruby path_to_enlightenment.rb

&lt;span class="c"&gt;# você também pode executar um koan específico&lt;/span&gt;
&lt;span class="c"&gt;# exemplo:&lt;/span&gt;
ruby about_symbols.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grande parte do processo de aprendizado com os Ruby Koans, é você ir iterando nos seguintes passos&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;executar o teste no terminal e ver aonde está falhando&lt;/li&gt;
&lt;li&gt;editar o arquivo para consertar o teste&lt;/li&gt;
&lt;li&gt;voltar ao passo 1&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cedo ou tarde você vai ficar entendiado de ficar alternando entre o terminal pra testar e o editor de código pra ajeitar os testes.&lt;/p&gt;

&lt;p&gt;Para ajudar nessa tarefa, podemos usar o &lt;code&gt;observr&lt;/code&gt;, desse jeito:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# instalar o observr gem
gem install observr

# rodar os testes a cada alteração
# em qqr um dos koans
observr ./koans/koans.watchr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto, agora vc pode deixar uma janela com o editor e outra com observr executando os testes a cada vez q vc salvar o arquivo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coisas que tentei antes de chegar aqui
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.ruby-lang.org/en/documentation/quickstart/" rel="noopener noreferrer"&gt;Ruby in 20 minutes&lt;/a&gt; - não achei as explicações muito coesas. Por isso preferi o "Ruby in 100 minutes".&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codewars.com" rel="noopener noreferrer"&gt;codewars.com&lt;/a&gt; - a proposta até que é legalzinha, mas achei o exercism bem mais amigáve e sem propagandas.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.manning.com/books/the-well-grounded-rubyist-third-edition" rel="noopener noreferrer"&gt;The Well-Grounded Rubyist, 3rd Edition&lt;/a&gt; - comecei lendo o livro, mas achei meio "devagar". Continuo lendo devagarinho para fixar alguns conceitos, pois ele explica com profundidade. Mas pra ganhar fluência rápida, eu já pulei pro exercism.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>programming</category>
    </item>
    <item>
      <title>Checking if an array contains an element in bash</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Sat, 12 Dec 2020 21:55:27 +0000</pubDate>
      <link>https://forem.com/meleu/checking-if-an-array-contains-an-element-in-bash-5bn1</link>
      <guid>https://forem.com/meleu/checking-if-an-array-contains-an-element-in-bash-5bn1</guid>
      <description>&lt;p&gt;When working with arrays it's quite common to face the need to check if an array includes a certain element. Although we can have arrays in bash, we don't have a specific method to check that. In this article we're going to address this problem using a not so known bash feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;If you just want the solution and don't care about how it works, here it is (the explanation comes right after):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

joinByChar&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# if extglob is not enabled, uncomment the line below&lt;/span&gt;
&lt;span class="c"&gt;# shopt -s extglob&lt;/span&gt;
&lt;span class="c"&gt;# The function returns status 0 if the array contains the element&lt;/span&gt;
elementInArray&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  local &lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$element&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; @&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;joinByChar &lt;span class="s1"&gt;'|'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[@]//|/\\|&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;extglob&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We're going to use the shell option &lt;code&gt;extglob&lt;/code&gt;, which stands for Extended Globbing. This feature was implemented in bash in version 2.02 (1998), so, unless you're using a 20 year old system, this method is pretty portable.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;extglob&lt;/code&gt; we have a richer way to specify sets of filenames (aka &lt;a href="https://en.wikipedia.org/wiki/Glob_(programming)" rel="noopener noreferrer"&gt;globbing&lt;/a&gt;). There are many cool things you can do with this feature. Here in this article we're going to use just a single part of it.&lt;/p&gt;

&lt;p&gt;In order to use the method we're going to explain here the shell option &lt;code&gt;extglob&lt;/code&gt; must be enabled. It seems to be the default nowadays, but to be sure, let's check it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ shopt extglob
extglob         on

$ # if it was off, you could turn it on with the following command

$ shopt -s extglob

$ # the -s option stands for *set* the option (turn it on)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that option is enabled, we can search for a string inside a list where each element is separated by a &lt;code&gt;|&lt;/code&gt; pipe. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$element&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; @&lt;span class="o"&gt;(&lt;/span&gt;element1|element2|elementN&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's a practical example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ [[ one == @(one|two|three) ]] &amp;amp;&amp;amp; echo yes || echo no
yes

$ [[ four == @(one|two|three) ]] &amp;amp;&amp;amp; echo yes || echo no
no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty simple, isn't it? In order to use this feature to check if an element is present in an array, first we need to get each element of the array and separate them with a &lt;code&gt;|&lt;/code&gt; pipe. So, let's use a function to help us with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;joinByChar()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We addressed this problem in &lt;a href="https://dev.to/meleu/how-to-join-array-elements-in-a-bash-script-303a"&gt;a previous article&lt;/a&gt; where we created the &lt;code&gt;joinByChar()&lt;/code&gt; function. The function is pretty short (you can find the explanation of how it works in that article):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;joinByChar&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice, now looks like we can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# elementInArray.sh&lt;/span&gt;
&lt;span class="c"&gt;###################&lt;/span&gt;

joinByChar&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# if extglob is not enabled, uncomment the line below&lt;/span&gt;
&lt;span class="c"&gt;# shopt -s extglob&lt;/span&gt;
elementInArray&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  local &lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$element&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; @&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;joinByChar &lt;span class="s1"&gt;'|'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ source elementInArray.sh 

$ array1=(one two 'three|four' 'five six')

$ elementInArray ten "${array1[@]}"

$ elementInArray one "${array1[@]}" &amp;amp;&amp;amp; echo yes || echo no
yes

$ elementInArray two "${array1[@]}" &amp;amp;&amp;amp; echo yes || echo no
yes

$ elementInArray three "${array1[@]}" &amp;amp;&amp;amp; echo yes || echo no
yes

$ # wait! I don't have an element 'three' in that array
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uhm... That &lt;code&gt;|&lt;/code&gt; in the element &lt;code&gt;three|four&lt;/code&gt; "confused" our function. We're going to need more bash tricks here.&lt;/p&gt;

&lt;p&gt;Let's use the variable substring replacement to escape our &lt;code&gt;|&lt;/code&gt; pipes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Escaping the pipes
&lt;/h3&gt;

&lt;p&gt;The construction we're using here is sometimes called &lt;strong&gt;global replacement&lt;/strong&gt;, and it works like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${variable//pattern/replacement}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where all matches of &lt;code&gt;pattern&lt;/code&gt;, within &lt;code&gt;variable&lt;/code&gt; is replaced with &lt;code&gt;replacement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We're going to use this: &lt;code&gt;${array[@]//|/\\|}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Which means "replace every ocurrence of &lt;code&gt;|&lt;/code&gt; found in the elements of &lt;code&gt;array&lt;/code&gt; with &lt;code&gt;\|&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;So, our final solution will be this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# elementInArray.sh&lt;/span&gt;
&lt;span class="c"&gt;###################&lt;/span&gt;

joinByChar&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# if extglob is not enabled, uncomment the line below&lt;/span&gt;
&lt;span class="c"&gt;# shopt -s extglob&lt;/span&gt;
&lt;span class="c"&gt;# The function returns status 0 if the array contains the element&lt;/span&gt;
elementInArray&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  local &lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$element&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; @&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;joinByChar &lt;span class="s1"&gt;'|'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[@]//|/\\|&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see if it's really safe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ source elementInArray.sh 

$ term='watermelon'

$ fruits=(grape apple orange kiwi)

$ elementInArray "$term" "${fruits[@]}"

$ elementInArray "$term" "${fruits[@]}" &amp;amp;&amp;amp; echo true || echo false
false

$ # let's make it easier to check the exit status with an alias:

$ alias result='echo true || echo false'

$ elementInArray "$term" "${fruits[@]}" &amp;amp;&amp;amp; result
false

$ # let's try to confuse it with   s p a c e s

$ term='passion'

$ fruits=('passion fruit' apple orange kiwi)

$ elementInArray "$term" "${fruits[@]}" &amp;amp;&amp;amp; result
false

$ term='passion fruit'

$ elementInArray "$term" "${fruits[@]}" &amp;amp;&amp;amp; result
true

$ # let's try to confuse it with|pipes|too

$ array1=(one two 'three|four' 'five six')

$ elementInArray one "${array1[@]}" &amp;amp;&amp;amp; result
true

$ elementInArray three "${array1[@]}" &amp;amp;&amp;amp; result
false

$ # nice! we, indeed, don't have a 'three' element

$ elementInArray 'three|four' "${array1[@]}" &amp;amp;&amp;amp; result
true

$ elementInArray 'five' "${array1[@]}" &amp;amp;&amp;amp; result
false

$ elementInArray 'five six' "${array1[@]}" &amp;amp;&amp;amp; result
true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this seems to be a nice method to check if an array contains an element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bash Extended Globbing: &lt;a href="https://www.linuxjournal.com/content/bash-extended-globbing" rel="noopener noreferrer"&gt;https://www.linuxjournal.com/content/bash-extended-globbing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;How to join array elements in a bash script: &lt;a href="https://dev.to/meleu/how-to-join-array-elements-in-a-bash-script-303a"&gt;https://dev.to/meleu/how-to-join-array-elements-in-a-bash-script-303a&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;List of features added to specific releases of Bash: &lt;a href="http://mywiki.wooledge.org/BashFAQ/061" rel="noopener noreferrer"&gt;http://mywiki.wooledge.org/BashFAQ/061&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tldp.org/LDP/abs/html/parameter-substitution.html" rel="noopener noreferrer"&gt;https://tldp.org/LDP/abs/html/parameter-substitution.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to join() array elements in a bash script</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Sat, 05 Dec 2020 17:47:31 +0000</pubDate>
      <link>https://forem.com/meleu/how-to-join-array-elements-in-a-bash-script-303a</link>
      <guid>https://forem.com/meleu/how-to-join-array-elements-in-a-bash-script-303a</guid>
      <description>&lt;p&gt;Some languages (like JavaScript and PHP) have a function like &lt;code&gt;join()&lt;/code&gt; or &lt;code&gt;implode()&lt;/code&gt; to join the elements of an array separating them by a character or a string. Let's do the same in pure bash.&lt;/p&gt;

&lt;p&gt;As a bonus, at the end this article you'll know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the differences between &lt;code&gt;$*&lt;/code&gt;, &lt;code&gt;$@&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;how the &lt;code&gt;IFS&lt;/code&gt; variable influences the behaviour of &lt;code&gt;$*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a variable expansion/substring replacement technique&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;printf&lt;/code&gt; "hack"&lt;/li&gt;
&lt;li&gt;how to find help from your system (it can be faster than googling)&lt;/li&gt;
&lt;li&gt;how to search inside a huge man page (like the bash's one)&lt;/li&gt;
&lt;li&gt;how to quickly get help for the bash-builtin commands (rather then searching inside that huge man page)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Join elements with a single character
&lt;/h2&gt;

&lt;p&gt;As they say, "Talk is cheap, show me the code.".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;joinByChar&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's see that code in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat joinByChar.sh
#!/usr/bin/env bash

joinByChar() {
  local IFS="$1"
  shift
  echo "$*"
}

$ source joinByChar.sh

$ joinByChar , Moe Larry Curly
Moe,Larry,Curly

$ stooges=(Moe Larry Curly)

$ joinByChar , "${stooges[@]}"
Moe,Larry,Curly

$ joinByChar | "${stooges[@]}"
Moe: command not found

$ # Whoops! We need to protect the pipe with 'single quotes'

$ joinByChar '|' "${stooges[@]}"
Moe|Larry|Curly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then let's understand how that works.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's &lt;code&gt;IFS&lt;/code&gt; doing?
&lt;/h3&gt;

&lt;p&gt;IFS stands for "Internal Field Separator". This is a special variable with a string of characters used to be treated as delimiters when splitting a line of input into different words.&lt;/p&gt;

&lt;p&gt;Its default value is a string with a space followed by tabulation followed by new line.&lt;/p&gt;

&lt;p&gt;Here's an example to show its behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ echo "$PATH"
/bin:/usr/bin:/usr/local/bin

$ for item in $PATH ; do echo $item; done;
/bin:/usr/bin:/usr/local/bin

$ IFS=:

$ for item in $PATH ; do echo $item; done;
/bin
/usr/bin
/usr/local/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you may know, the &lt;code&gt;PATH&lt;/code&gt; variable is a string with a collection of paths separated:by:a:colon.&lt;/p&gt;

&lt;p&gt;In that example, the first &lt;code&gt;for&lt;/code&gt; had only one iteration, because the whole content of &lt;code&gt;PATH&lt;/code&gt; was considered as the only argument.&lt;/p&gt;

&lt;p&gt;After setting the &lt;code&gt;IFS&lt;/code&gt; as &lt;code&gt;:&lt;/code&gt;, we're telling bash that we want it to split the content of &lt;code&gt;PATH&lt;/code&gt; into distinct words by separating them where there's a &lt;code&gt;:&lt;/code&gt; colon.&lt;/p&gt;

&lt;p&gt;Therefore, with &lt;code&gt;IFS=:&lt;/code&gt; the string in the &lt;code&gt;PATH&lt;/code&gt; variable will be splitted exactly where there are &lt;code&gt;:&lt;/code&gt; colons. As a result, that &lt;code&gt;for&lt;/code&gt; clause will get the directory names present in the &lt;code&gt;PATH&lt;/code&gt; individually.&lt;/p&gt;

&lt;p&gt;(I'd like to write a specific article about IFS at some point, but if you want to go deeper right now, I recommend checking the &lt;a href="https://mywiki.wooledge.org/IFS" rel="noopener noreferrer"&gt;Greg's Wiki&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;joinByChar()&lt;/code&gt; function, we're setting the &lt;code&gt;IFS&lt;/code&gt; with the char we want to use to join the elements in only one string. Keep reading and you'll see why it's needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's &lt;code&gt;shift&lt;/code&gt; doing?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;shift&lt;/code&gt; builtin command is used to handle the positional parameters. When you use the &lt;code&gt;shift&lt;/code&gt;, the first parameter goes away, the second becomes &lt;code&gt;$1&lt;/code&gt;, the third becomes &lt;code&gt;$2&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;joinByChar()&lt;/code&gt; function, as soon as we saved the character to be used as the separator in the &lt;code&gt;IFS&lt;/code&gt; variable, we don't need that content to be in the &lt;code&gt;$1&lt;/code&gt; anymore. Let's get rid of it with a &lt;code&gt;shift&lt;/code&gt; and now all other arguments (the elements we want to join) so we can refer to all arguments just by using &lt;code&gt;$*&lt;/code&gt;, which is explained right below.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does &lt;code&gt;$*&lt;/code&gt; really work?
&lt;/h3&gt;

&lt;p&gt;By checking the bash manpage in the "Special Parameters" section, we can see how the &lt;code&gt;*&lt;/code&gt; and the &lt;code&gt;@&lt;/code&gt; work when in the command line parameters context ( &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: the manpage of bash is really really big. So, when in the &lt;code&gt;man&lt;/code&gt; program, type &lt;code&gt;/&lt;/code&gt; followed by the string you wanna search (case sensitive). For example &lt;code&gt;/Special Parameters&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an excerpt of what is described about the expansion with &lt;code&gt;*&lt;/code&gt; from the bash manpage:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the &lt;code&gt;IFS&lt;/code&gt; special variable. That is, &lt;code&gt;"$*"&lt;/code&gt; is equivalent to &lt;code&gt;"$1c$2c..."&lt;/code&gt;, where &lt;code&gt;c&lt;/code&gt; is the first character of the value of the &lt;code&gt;IFS&lt;/code&gt; variable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore &lt;code&gt;*&lt;/code&gt; expands separating with the first character in the &lt;code&gt;IFS&lt;/code&gt; variable, which in the &lt;code&gt;joinByChar()&lt;/code&gt; function is the first character given as the first argument.&lt;/p&gt;

&lt;p&gt;And that's how the &lt;code&gt;joinByChar()&lt;/code&gt; works. This technique serves you only if you want to join the elements with a single character. If you need to join the elements "gluing" them with a string check the technique below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join elements with a string
&lt;/h2&gt;

&lt;p&gt;First the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
joinByString&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;separator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  local &lt;/span&gt;&lt;span class="nv"&gt;first&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift
  printf&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;@/#/&lt;/span&gt;&lt;span class="nv"&gt;$separator&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then that code in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ joinByString , Moe Larry Curly
Moe,Larry,Curly

$ joinByString ', ' Moe Larry Curly
Moe, Larry, Curly

$ joinByString ' &amp;lt;-&amp;gt; ' Moe Larry Curly
Moe &amp;lt;-&amp;gt; Larry &amp;lt;-&amp;gt; Curly

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can be a bit tricky to understand how exactly that function is working. It's combining some handy features of bash and it can be overwhelming to understand all at once. So let's break it into smaller pieces...&lt;/p&gt;

&lt;p&gt;We already saw how &lt;code&gt;shift&lt;/code&gt; works and how it influences the positional parameters. So the explanation here will be focused in the last line of the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;@/#/&lt;/span&gt;&lt;span class="nv"&gt;$separator&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a lot of bash concepts behind this single line of code, so keep calm and stay with me.&lt;/p&gt;

&lt;p&gt;Starting with this cryptic string: &lt;code&gt;${@/#/$separator}&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How does &lt;code&gt;$@&lt;/code&gt; work?
&lt;/h3&gt;

&lt;p&gt;An excerpt of what is described about the expansion with &lt;code&gt;@&lt;/code&gt; from the bash manpage:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Expands to the positional parameters, starting from one. (...) When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is  equivalent  to "$1" "$2" ...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Differently than &lt;code&gt;$*&lt;/code&gt;, which expands "gluing" the parameters with the first char of the &lt;code&gt;IFS&lt;/code&gt;, the &lt;code&gt;$@&lt;/code&gt; expands separating the parameters &lt;strong&gt;with a literal space&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That part in bold is important, then I'm gonna repeat it: the &lt;code&gt;$@&lt;/code&gt; expands separating the parameters &lt;strong&gt;with a literal space&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Substring replacement with &lt;code&gt;${variable/#pattern/replacement}&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;It works like this: if &lt;code&gt;variable&lt;/code&gt; starts with &lt;code&gt;pattern&lt;/code&gt;, then &lt;code&gt;pattern&lt;/code&gt; will be replaced with &lt;code&gt;replacement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Check this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ var='one two three'

$ echo "${var/#one/1}"
1 two three

$ # as var starts with 'one' it worked as expected

$ echo "${var/#two/2}"
one two three

$ # var doesnt start with 'two', then nothing happens

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the replacement only works if the variable starts with that pattern.&lt;/p&gt;

&lt;p&gt;And here's the trick to put a prefix before the variable's content: use an empty pattern.&lt;/p&gt;

&lt;p&gt;We can say that an empty pattern means "nothing", and every string starts with "nothing", right?&lt;/p&gt;

&lt;p&gt;Let's see it in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ var='one two three'

$ echo "${var/#/zero }"
zero one two three
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Substring replacement with &lt;code&gt;${@/#pattern/replacement}&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;An interesting thing happens when we combine this replacement technique with the &lt;code&gt;$@&lt;/code&gt;. If you do something like &lt;code&gt;"${@/#two/2}"&lt;/code&gt;, it'll be expanded to &lt;code&gt;"${0/#two/2}" "${1/#two/2}" "${2/#two/2}" ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Check it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ replace() { echo "${@/#two/2}"; }                                             

$ replace one two three
one 2 three
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;replacement&lt;/code&gt; part of that construction can also be a variable. Let's prefix all those numbers with something:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ addPrefix() { echo "${@/#/$prefix}"; }

$ prefix='something-&amp;gt;'

$ addPrefix one two three
something-&amp;gt;one something-&amp;gt;two something-&amp;gt;three

$ prefix=', '

$ addPrefix one two three
, one , two , three
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it adds the prefix before every parameter.&lt;/p&gt;

&lt;p&gt;Let's remember the problem we want to solve: concatenate all parameters "gluing" them with a specific string. We can achieve this by prefixing all parameters with a string, but we must not prefix the first parameter.&lt;/p&gt;

&lt;p&gt;If you're following me, you probably realised that the "first parameter" thing is easy to solve by saving it in a variable and then using &lt;code&gt;shift&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But there's another thing that doesn't look quite right...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ addPrefix one two three
, one , two , three
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't want those spaces after each element. To solve that, we're going to use the &lt;code&gt;printf&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does bash's &lt;code&gt;printf&lt;/code&gt; work?
&lt;/h3&gt;

&lt;p&gt;I'm assuming you have some familiarity with &lt;code&gt;printf&lt;/code&gt;. If you have a C language background, I'm sure you're comfortable with it, but if you never used &lt;code&gt;printf&lt;/code&gt; before &lt;a href="https://opensource.com/article/20/8/printf" rel="noopener noreferrer"&gt;here's an interesting article specific for the bash context&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: To access the documentation of a bash-builtin command use &lt;code&gt;help&lt;/code&gt;. As &lt;code&gt;printf&lt;/code&gt; is a builtin, check its documentation with &lt;code&gt;help printf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The term &lt;code&gt;printf&lt;/code&gt; stands for "print formatted" where you can tell the format you want by using format specifiers. The one we're going to use here is the &lt;code&gt;%s&lt;/code&gt;, which is simply a string.&lt;/p&gt;

&lt;p&gt;Let's check an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ name='meleu'

$ adjective='nice guy'

$ printf "%s is a %s" "$name" "$adjective"
meleu is a nice guy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, each &lt;code&gt;%s&lt;/code&gt; is replaced with the respective string passed as argument. The first &lt;code&gt;%s&lt;/code&gt; is replaced with the contents of &lt;code&gt;$name&lt;/code&gt; and the second one is replaced with &lt;code&gt;$adjective&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The interesting &lt;code&gt;printf&lt;/code&gt; feature that I want to highlight here is this single sentence buried in that huge bash manpage:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The format is re-used as necessary to consume all of the arguments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uhm... Interesting, let's check that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ namesAndAdjectives=('meleu' 'nice guy' 'swyx' '#LearnInPublic evangelist')

$ printf "%s is a %s\n" "${namesAndAdjectives[@]}"
meleu is a nice guy
swyx is a #LearnInPublic evangelist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's cool! Now we have everything we need to understand that cryptic line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;@/#/&lt;/span&gt;&lt;span class="nv"&gt;$separator&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're following me until here you can agree with this description of that code:&lt;/p&gt;

&lt;p&gt;Print the content of &lt;code&gt;$first&lt;/code&gt; and then print each parameter prefixing them with the content of &lt;code&gt;$separator&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/17841619" rel="noopener noreferrer"&gt;https://stackoverflow.com/a/17841619&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mywiki.wooledge.org/IFS" rel="noopener noreferrer"&gt;https://mywiki.wooledge.org/IFS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tldp.org/LDP/abs/html/parameter-substitution.html" rel="noopener noreferrer"&gt;https://tldp.org/LDP/abs/html/parameter-substitution.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;man bash&lt;/code&gt; in the "Special Parameters" section&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;man bash&lt;/code&gt; in the "Parameter Expansion" section&lt;/li&gt;
&lt;li&gt;&lt;code&gt;help printf&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>What the #! shebang really does</title>
      <dc:creator>meleu</dc:creator>
      <pubDate>Sat, 28 Nov 2020 17:02:24 +0000</pubDate>
      <link>https://forem.com/meleu/what-the-shebang-really-does-and-why-it-s-so-important-in-your-shell-scripts-2755</link>
      <guid>https://forem.com/meleu/what-the-shebang-really-does-and-why-it-s-so-important-in-your-shell-scripts-2755</guid>
      <description>&lt;p&gt;What exactly happens when we run a file starting with &lt;code&gt;#!&lt;/code&gt; (aka shebang), and why some people use &lt;code&gt;#!/usr/bin/env bash&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the &lt;code&gt;#!&lt;/code&gt; works
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;#!&lt;/code&gt; shebang is used to tell the kernel which interpreter should be used to run the commands present in the file.&lt;/p&gt;

&lt;p&gt;When we run a file starting with &lt;code&gt;#!&lt;/code&gt;, the kernel opens the file and takes the contents written right after the &lt;code&gt;#!&lt;/code&gt; until the end of the line. For didactic purposes, let's consider it saves in a variable called &lt;code&gt;command&lt;/code&gt; the string starting after the shebang and ending in the end of line.&lt;/p&gt;

&lt;p&gt;After this the kernel tries to run a command with the contents of the &lt;code&gt;command&lt;/code&gt; and giving as the first argument the filename of the file we're trying to execute.&lt;/p&gt;

&lt;p&gt;Therefore, if you have an executable file called &lt;code&gt;myscript.sh&lt;/code&gt; with some shell commands and starting with &lt;code&gt;#!/bin/bash&lt;/code&gt;, when you run it, the kernel will execute &lt;code&gt;/bin/bash myscript.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the examples below you're going to see it very clearly.&lt;/p&gt;

&lt;p&gt;Starting with the classic &lt;code&gt;hello.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello World!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming this file has the executable permission, when you type this in the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./hello.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The kernel will notice the &lt;code&gt;#!&lt;/code&gt; in the very first line and then will get what's after it, in this case &lt;code&gt;/bin/bash&lt;/code&gt;. And then what is executed has the very same effect of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /bin/bash hello.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's use another example using &lt;code&gt;#!/bin/cat&lt;/code&gt;. The name of the file is &lt;code&gt;shebangcat&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/cat
All the contents of this file will be
printed in the screen when it's executed
(including the '#!/bin/cat' in the first line).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's after the shebang: &lt;code&gt;/bin/cat&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Name of the file: &lt;code&gt;./shebangcat&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore this is what's executed: &lt;code&gt;/bin/cat ./shebangcat&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;See it by yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./shebangcat
#!/bin/cat
All the contents of this file will be
printed in the screen when it's executed
(including the '#!/bin/cat' in the first line).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take another example to make it very clear that things are like I'm saying. The following file is called &lt;code&gt;shebangecho&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/echo
The contents of this file will *NOT* be
printed when it's executed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./shebangecho
./shebangecho
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output was the name of the file because this is what was executed by the kernel &lt;code&gt;/usr/bin/echo ./shebangecho&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another interesting thing, is that if we pass arguments when calling our script, such arguments will also be passed to the command executed by the kernel. As we can see in the following example called &lt;code&gt;shebangls.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/ls
The contents here doesn't matter.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when we run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./shebangls.sh
./shebangls.sh

$ ./shebangls.sh -l
-rwxr-xr-x 1 meleu meleu 41 Nov 28 14:42 ./shebangls.sh

$ ./shebangls.sh notfound
/bin/ls: cannot access 'notfound': No such file or directory
./shebangls.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why some people use &lt;code&gt;#!/usr/bin/env&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;You probably saw some scripts starting with &lt;code&gt;#!/usr/bin/env bash&lt;/code&gt; where you're used to see just &lt;code&gt;#!/bin/bash&lt;/code&gt;. The reason of this is to increase the portability of the script (even thought it's a debatable matter, as we're going to see below).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;env&lt;/code&gt; command, if used with no arguments, prints a (big) list with all the environment's variables. But if &lt;code&gt;env&lt;/code&gt; is used followed by a command, it runs that command in another instance of the shell.&lt;/p&gt;

&lt;p&gt;🤔 - &lt;strong&gt;OK, but how does that influence portability?!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you use &lt;code&gt;#!/bin/bash&lt;/code&gt; you're clearly saying that &lt;code&gt;bash&lt;/code&gt; is in the &lt;code&gt;/bin/&lt;/code&gt; directory. This seems to be the default in all Linux distributions, but there are other Unix flavors where it can possibly not happen (for example the &lt;code&gt;bash&lt;/code&gt; can be placed in the &lt;code&gt;/usr/bin/&lt;/code&gt;). In systems like that your script starting with &lt;code&gt;#!/bin/bash&lt;/code&gt; would cause a &lt;code&gt;bad interpreter: No such file or directory&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;env bash&lt;/code&gt;, the &lt;code&gt;env&lt;/code&gt; will search for &lt;code&gt;bash&lt;/code&gt; in your &lt;code&gt;$PATH&lt;/code&gt; variable, and then run the first one it finds. Usually &lt;code&gt;bash&lt;/code&gt; is in &lt;code&gt;/bin/&lt;/code&gt;, but a user running your script on some other system can have it in &lt;code&gt;/usr/bin/&lt;/code&gt; or even testing an alternative version in &lt;code&gt;/home/user/bin/bash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, in order to make the script have a greater reach and be used in environments other than Linux, some people recommend the use of the &lt;code&gt;env&lt;/code&gt; technique.&lt;/p&gt;

&lt;p&gt;🤔 - &lt;strong&gt;But wait! What guarantees that the &lt;code&gt;env&lt;/code&gt; will always be in the &lt;code&gt;/usr/bin/&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are no guarantees... 😇&lt;/p&gt;

&lt;p&gt;The recomendation is based in what is commonly seen in the Unix systems. I see &lt;code&gt;/usr/bin/env&lt;/code&gt; being used in some modern projects (like &lt;a href="https://github.com/RetroPie/RetroPie-Setup" rel="noopener noreferrer"&gt;RetroPie&lt;/a&gt;), but where it's specially useful is when you need to run a python or even a NodeJS script.&lt;/p&gt;

&lt;p&gt;Let's take this NodeJS usage as an example. I want to call a NodeJS script just by calling the script's filename. Then I could do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/usr/bin/node
&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World from NodeJS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is that I usually install node via &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;Node Version Manager&lt;/a&gt;, instead of using the the distribution's package manager. So, my &lt;code&gt;node&lt;/code&gt; is like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ which node
/home/meleu/.nvm/versions/node/v14.15.1/bin/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By any means I want to put &lt;code&gt;#!/home/meleu/.nvm/versions/node/v14.15.1/bin/node&lt;/code&gt; in my script!&lt;/p&gt;

&lt;p&gt;So, the solution here is to use &lt;code&gt;#!/usr/bin/env node&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  And if I don't want to use &lt;code&gt;#!&lt;/code&gt; at all?
&lt;/h2&gt;

&lt;p&gt;I strongly recommend you to never write neither run a shell script without a &lt;code&gt;#!&lt;/code&gt; shebang!&lt;/p&gt;

&lt;p&gt;As we said, the shebang tells to the kernel which interpreter is to be used to run the commands present in the file. If you run a script without specifying the interpreter, the shell will spawn another instance of itself and try to run the commands in the script. Which means that it will execute whatever commands found in the file, even if it was written for zsh, ksh, dash, fish, node, python, or whatever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summing up&lt;/strong&gt;: Always start your scripts with a &lt;code&gt;#!&lt;/code&gt; shebang. Preferably with &lt;code&gt;#!/usr/bin/env&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://mywiki.wooledge.org/BashProgramming#Shebang" rel="noopener noreferrer"&gt;http://mywiki.wooledge.org/BashProgramming#Shebang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.bash-hackers.org/scripting/basics#the_shebang" rel="noopener noreferrer"&gt;https://wiki.bash-hackers.org/scripting/basics#the_shebang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.in-ulm.de/~mascheck/various/shebang/4.0BSD_newsys_sys1.c.html" rel="noopener noreferrer"&gt;Here's an email from Dennis Ritchie&lt;/a&gt; in 1980, talking about these "magic characters".&lt;/li&gt;
&lt;li&gt;&lt;code&gt;man env&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://alexewerlof.medium.com/node-shebang-e1d4b02f731d" rel="noopener noreferrer"&gt;Node.js shebang&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>unix</category>
      <category>shellscript</category>
    </item>
  </channel>
</rss>
