<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="https://www.rafaelmontas.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.rafaelmontas.com/" rel="alternate" type="text/html" /><updated>2024-06-03T11:15:02-04:00</updated><id>https://www.rafaelmontas.com/feed.xml</id><title type="html">Blog Rafael</title><subtitle>Passionate Software Developer. Currently improving my Ruby/Rails skills every signle day and sharing what I learn.</subtitle><entry><title type="html">Automate deployments with GitHub Actions and Docker Swarm - CI/CD</title><link href="https://www.rafaelmontas.com/automate-deployments-with-github-actions/" rel="alternate" type="text/html" title="Automate deployments with GitHub Actions and Docker Swarm - CI/CD" /><published>2024-05-12T00:00:00-04:00</published><updated>2024-05-12T00:00:00-04:00</updated><id>https://www.rafaelmontas.com/automate-deployments-with-github-actions</id><content type="html" xml:base="https://www.rafaelmontas.com/automate-deployments-with-github-actions/">&lt;p&gt;This is the second part of a series of posts on deploying a Rails app to a Docker Swarm
cluster on a remote VPS. In the first part, we set up the Swarm cluster on
Hetzner Cloud and deployed a Rails app to it from our local machine. If you haven’t read
it yet, you can find it &lt;a href=&quot;/deploy-rails-docker-swarm-hetzner&quot;&gt;here&lt;/a&gt;. In this post, we’ll
automate the  deployment process with GitHub Actions, so that every time you push your
code to GitHub a CI/CD pipeline will build and deploy your app to the Swarm.&lt;/p&gt;

&lt;p&gt;We are not going to cover linting and testing in this post, but if you want to add those
steps to your pipeline, you can check out this &lt;a href=&quot;https://github.com/rails/rails/pull/50508&quot;&gt;PR&lt;/a&gt; merged into Rails to add a workflow
that runs Brakeman, RuboCop, and the test suite on every push and pull request to the
main branch of the repository.&lt;/p&gt;

&lt;h2 id=&quot;handle-environment-variables&quot;&gt;Handle environment variables&lt;/h2&gt;

&lt;p&gt;Let’s review the stack file we used to deploy the app to the Swarm in the first part of
this series.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.7&apos;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;dockerhub_username&amp;gt;/swarm-demo:prod&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;database&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;80:3000&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;RAILS_MASTER_KEY=c51c56d33c031224c4678f44dd7eafa0&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_USER=swarm_demo&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_PASSWORD=production-secure-password&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node.labels.type == app&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;postgres:15&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_USER=swarm_demo&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_PASSWORD=production-secure-password&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;5432:5432&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node.labels.type == database&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;db_data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have some environment variables in the stack file that we don’t want to expose in the
repository but definitely need them to deploy the app. In order to handle this, we will use the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bitwarden CLI&lt;/code&gt; to fetch the secrets from Bitwarden and inject them into the stack file when
the CI/CD pipeline runs.&lt;/p&gt;

&lt;p&gt;First, update the stack file so that it references an environment file instead of hardcoded values:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.7&apos;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;dockerhub_username&amp;gt;/swarm-demo:prod&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;database&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;80:3000&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;env_file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;.env&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node.labels.type == app&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;postgres:15&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;env_file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;.env&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;5432:5432&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node.labels.type == database&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;db_data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Second, create a free &lt;a href=&quot;https://vault.bitwarden.com/#/register?layout=default&quot;&gt;Bitwarden account&lt;/a&gt;
if you don’t have one already and add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RAILS_MASTER_KEY&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POSTGRES_USER&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POSTGRES_PASSWORD&lt;/code&gt;
as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secure notes&lt;/code&gt; to the default collection:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/swarm-cicd/bitwarden-note.png&quot; alt=&quot;Bitward note&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now, install the Bitwarden CLI by following the instructions &lt;a href=&quot;https://bitwarden.com/help/cli/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have the Bitwarden CLI installed and authenticated, you can fetch the secured notes by running:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bw get notes &amp;lt;item-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;hydrate-env-file-with-bitwarden-secrets&quot;&gt;Hydrate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file with Bitwarden secrets&lt;/h3&gt;

&lt;p&gt;We will implement a rake task to fetch the secrets from Bitwarden and inject them into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file.
This is a similar but simplified version of what &lt;a href=&quot;https://kamal-deploy.org/docs/configuration&quot;&gt;Kamal&lt;/a&gt;
does when you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kamal envify&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create said rake task in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/tasks/env_variables.rake&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:env_variables&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# &quot;Creates .env by evaluating .env.erb&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:hydrate&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.env&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ERB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.env.erb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;perm: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env.erb&lt;/code&gt; file in the root of your project with the following content:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`bw unlock --passwordenv BW_PASSWORD --raw`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
RAILS_MASTER_KEY=&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`bw get notes &amp;lt;item-id&amp;gt; --session &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_token&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
POSTGRES_USER=&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`bw get notes &amp;lt;item-id&amp;gt; --session &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_token&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
POSTGRES_PASSWORD=&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`bw get notes &amp;lt;item-id&amp;gt; --session &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_token&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ArgumentError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;session_token token missing&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this setup, when you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake env_variables:hydrate&lt;/code&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file will be created
as a result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ERB.new(File.read(&quot;.env.erb&quot;)).result&lt;/code&gt; executing the embedded Ruby code in the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env.erb&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now that we can dynamically inject the secrets into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file, let’s handle the CI/CD pipeline.&lt;/p&gt;

&lt;h2 id=&quot;github-actions&quot;&gt;GitHub Actions&lt;/h2&gt;

&lt;p&gt;GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform
that allows you to automate your build, test, and deployment pipeline. GA uses the
concept of a &lt;strong&gt;Workflow&lt;/strong&gt; which is defined by a YAML file in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.github/workflows&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;We are going to configure a GitHub Actions workflow to be triggered when we push our changes
to the repository, deploying the app to the VPS using Docker Swarm.&lt;/p&gt;

&lt;p&gt;First, let’s create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.github/workflows&lt;/code&gt; directory and create a new file (workflow).
Let’s call it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.yml&lt;/code&gt; and add the following code. We will break down the code right after.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/ce72a7dd6c2cec8beba1cf1d25717ad1.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;Let’s break down the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run-name&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on&lt;/code&gt; keys:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Deploy&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;run-name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Deploying to Swarm cluster&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; key is the name of the workflow and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run-name&lt;/code&gt; key is the name for workflow
runs, which will appear in the list of workflow runs in the GitHub Actions tab. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on&lt;/code&gt; key
defines the events that trigger the workflow. In this case, the workflow will run when we push
to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jobs&lt;/code&gt; key defines the jobs that will run in the workflow. In this case, we have only one
job called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy&lt;/code&gt; that runs on an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubuntu-latest&lt;/code&gt; runner.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;steps&lt;/code&gt; key defines the steps that will run in the job. Each step is a task that can run
commands or actions. The &lt;strong&gt;first&lt;/strong&gt; step checks out the codebase, the &lt;strong&gt;second&lt;/strong&gt; step sets up Ruby on the runner,
the &lt;strong&gt;third&lt;/strong&gt; step sets up Node.js so we can use the Bitwarden CLI, which is installed in the &lt;strong&gt;fourth&lt;/strong&gt; step to
hydrate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file. The &lt;strong&gt;fifth&lt;/strong&gt; and &lt;strong&gt;sixth&lt;/strong&gt; steps set up Docker Buildx and login to Docker Hub, respectively so
that we can build and push the Docker image in the &lt;strong&gt;seventh&lt;/strong&gt; step. Finally, the &lt;strong&gt;last&lt;/strong&gt; step deploys the stack to the
Swarm cluster.&lt;/p&gt;

&lt;p&gt;In order to run the workflow, we need to add the secrets to the repository. Go to the repository settings, under &lt;strong&gt;Security&lt;/strong&gt;,
click &lt;strong&gt;Secrets and Variables&lt;/strong&gt; and then click &lt;strong&gt;Actions&lt;/strong&gt;. Add the following secrets:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/swarm-cicd/github-secrets.png&quot; alt=&quot;GitHub Secrets&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once you have set up the secrets, you can push your changes to the repository and the
workflow should run automatically deploying the app to the Swarm cluster.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/swarm-cicd/github-actions.png&quot; alt=&quot;GitHub Actions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s it! You have successfully automated the deployment process of your Rails app
to a Docker Swarm cluster on a remote VPS using GitHub Actions. Hopefullly, this post was helpful to you.
If you have any questions or suggestions, feel free to reach out to me on &lt;a href=&quot;https://twitter.com/rmontas&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;</content><author><name></name></author><summary type="html">Once you can deploy an app to a remote Docker Swarm cluster from your local machine, you might want to automate the process so that your app gets deployed every time you push your code to your repository.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.rafaelmontas.com/assets/images/swarm-cicd/swarm-cicd.png" /><media:content medium="image" url="https://www.rafaelmontas.com/assets/images/swarm-cicd/swarm-cicd.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Deploy a Rails app to a Docker Swarm cluster on Hetzner</title><link href="https://www.rafaelmontas.com/deploy-rails-docker-swarm-hetzner/" rel="alternate" type="text/html" title="Deploy a Rails app to a Docker Swarm cluster on Hetzner" /><published>2024-02-14T00:00:00-04:00</published><updated>2024-02-14T00:00:00-04:00</updated><id>https://www.rafaelmontas.com/deploy-rails-docker-swarm-hetzner</id><content type="html" xml:base="https://www.rafaelmontas.com/deploy-rails-docker-swarm-hetzner/">&lt;p&gt;In this post, I’ll show you how to set up a Docker Swarm cluster on Hetzner and deploy
a Rails app to it. We will be setting up two hosts, one for the web server acting
as manager and another for the database acting as worker.&lt;/p&gt;

&lt;p&gt;First, let’s create a new Rails app and prepare the database:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rails new swarm-demo &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; propshaft &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; postgresql &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; tailwind
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rails db:prepare
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should now be able to run the app locally with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin/dev&lt;/code&gt; and see the welcome page.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-swarm-hetzner/rails-welcome.png&quot; alt=&quot;Rails welcome page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Just so we can test our database connection and data persistency in the swarm, let’s scaffold
a simple Post resource and set the index action as the root route:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rails g scaffold Post title:string
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rails db:migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# config/routes.rb&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;posts#index&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;provisioning-the-servers-on-hetzner&quot;&gt;Provisioning the servers on Hetzner&lt;/h2&gt;

&lt;p&gt;We could do this through the Hetzner Cloud Console but we will use the hcloud CLI.
First, you need to &lt;a href=&quot;https://accounts.hetzner.com/login&quot;&gt;create an account&lt;/a&gt; on Hetzner, create
a project, and &lt;a href=&quot;https://docs.hetzner.com/cloud/api/getting-started/generating-api-token/&quot;&gt;generate an API token&lt;/a&gt;
(with read and write permissions). Then, install the &lt;a href=&quot;https://community.hetzner.com/tutorials/howto-hcloud-cli&quot;&gt;hcloud CLI&lt;/a&gt;
with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install hcloud&lt;/code&gt; on macOS.&lt;/p&gt;

&lt;p&gt;Once you have the token, you can authenticate with the CLI by creating a context:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud context create swarm-hetzner
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will be prompted to enter the API token and the context will be created. Now, you can start
provisioning the two servers.&lt;/p&gt;

&lt;p&gt;In order for us to be able to SSH into the servers, we need to create an SSH key in our local machine
and then associate it with Hetzner so we can use it when creating the servers:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;For this example, I will create a new SSH key called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id_rsa_personal&lt;/code&gt; without a passphrase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ssh-keygen &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; ~/.ssh/id_rsa_personal
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud ssh-key create &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; personal-key &lt;span class=&quot;nt&quot;&gt;--public-key-from-file&lt;/span&gt; ~/.ssh/id_rsa_personal.pub
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can list the SSH keys associated with Hetzner to make sure it was added successfully:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud ssh-key list

ID         NAME           FINGERPRINT                                       AGE
19362876   personal-key   cf:0b:89:00:00:5f:7d:e5:93:c8:17:16:68:64:38:b3   55s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we can create the two servers. We will use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cx11&lt;/code&gt; type for both, which is the cheapest
one. You can choose a different type if you want:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud server create &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; app-manager &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; cx11 &lt;span class=&quot;nt&quot;&gt;--image&lt;/span&gt; docker-ce &lt;span class=&quot;nt&quot;&gt;--ssh-key&lt;/span&gt; 19362876
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud server create &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; db-worker &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; cx11 &lt;span class=&quot;nt&quot;&gt;--image&lt;/span&gt; docker-ce &lt;span class=&quot;nt&quot;&gt;--ssh-key&lt;/span&gt; 19362876
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see the servers listed when you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hcloud server list&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud server list

ID         NAME          STATUS    IPV4             IPV6                      PRIVATE NET   DATACENTER   AGE
43107995   app-manager   running   37.27.34.249     2a01:4f9:c012:8df4::/64   -             hel1-dc2     4m
43108038   db-worker     running   95.217.128.149   2a01:4f9:c011:94ac::/64   -             hel1-dc2     1m
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Optionally, you can go on and add a new entry to the config file on your local device. With this you will be
able to simply use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh &amp;lt;unique-name&amp;gt;&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh &amp;lt;username&amp;gt;@&amp;lt;IP-address&amp;gt;&lt;/code&gt; to connect to the servers:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;nano ~/.ssh/config

Host swarm-manager
  HostName 37.27.34.249
  User root
  IdentityFile ~/.ssh/id_rsa_personal
  PreferredAuthentications publickey

Host db-worker
  HostName 95.217.128.149
  User root
  IdentityFile ~/.ssh/id_rsa_personal
  PreferredAuthentications publickey
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now you can connect to the server with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh swarm-manager&lt;/code&gt; and verify that Docker is installed:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ssh swarm-manager
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Docker version 25.0.1, build 29cf629
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;adding-a-firewall-to-both-servers&quot;&gt;Adding a firewall to both servers&lt;/h2&gt;

&lt;p&gt;Now, let’s create our firewall for the servers. We will create the firewall, add inbound
rules, and then apply it to both servers.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create the firewall&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall create &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; app-firewall
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Firewall 1245331 created

&lt;span class=&quot;c&quot;&gt;# Add inbound rules&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall add-rule 1245331 &lt;span class=&quot;nt&quot;&gt;--direction&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 22 &lt;span class=&quot;nt&quot;&gt;--protocol&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--source-ips&lt;/span&gt; 0.0.0.0/0
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall add-rule 1245331 &lt;span class=&quot;nt&quot;&gt;--direction&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 80 &lt;span class=&quot;nt&quot;&gt;--protocol&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--source-ips&lt;/span&gt; 0.0.0.0/0

&lt;span class=&quot;c&quot;&gt;# Docker related ports for nodes communication and overlay networks&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall add-rule 1245331 &lt;span class=&quot;nt&quot;&gt;--direction&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 2377 &lt;span class=&quot;nt&quot;&gt;--protocol&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--source-ips&lt;/span&gt; 0.0.0.0/0
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall add-rule 1245331 &lt;span class=&quot;nt&quot;&gt;--direction&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 7946 &lt;span class=&quot;nt&quot;&gt;--protocol&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--source-ips&lt;/span&gt; 0.0.0.0/0
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall add-rule 1245331 &lt;span class=&quot;nt&quot;&gt;--direction&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 4789 &lt;span class=&quot;nt&quot;&gt;--protocol&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;--source-ips&lt;/span&gt; 0.0.0.0/0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice that we don’t have to open the database port as the database server will only be accessible
from the web server and Docker Swarm will handle the communication between the services.&lt;/p&gt;

&lt;p&gt;Now we can apply the firewall to the servers by running the following commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall apply-to-resource 1245331 &lt;span class=&quot;nt&quot;&gt;--server&lt;/span&gt; 43107995 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; server
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;hcloud firewall apply-to-resource 1245331 &lt;span class=&quot;nt&quot;&gt;--server&lt;/span&gt; 43108038 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setting-up-the-docker-swarm-cluster&quot;&gt;Setting up the Docker Swarm cluster&lt;/h2&gt;

&lt;p&gt;We will start by initializing Swarm mode on the manager node and then join the worker node to the cluster.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ssh swarm-manager
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker swarm init &lt;span class=&quot;nt&quot;&gt;--advertise-addr&lt;/span&gt; 37.27.34.249

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Swarm initialized: current node &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;xyivupj1vs8j972fb789t3n08&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; is now a manager.
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; To add a worker to this swarm, run the following &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;:
  docker swarm &lt;span class=&quot;nb&quot;&gt;join&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--token&lt;/span&gt; SWMTKN-1-2z9r0ypycjcxesjr7vlyf4nd248xp7h83dy7127miwoyydszct-a04m5zkf3f6hd3ueeoj513tby 37.27.34.249:2377
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before joining the worker node to the cluster, let’s assign a label to the manager node so we can control
where the app container will be deployed. First, list the nodes to get the manager node ID and then assign
the label to the manager node:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker node &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker node update &lt;span class=&quot;nt&quot;&gt;--label-add&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;app xyivupj1vs8j972fb789t3n08
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we can join the worker node to the cluster:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ssh db-worker

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker swarm &lt;span class=&quot;nb&quot;&gt;join&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--token&lt;/span&gt; SWMTKN-1-2z9r0ypycjcxesjr7vlyf4nd248xp7h83dy7127miwoyydszct-a04m5zkf3f6hd3ueeoj513tby 37.27.34.249:2377

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; This node joined a swarm as a worker.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Assign a label to the worker node as well by going back to the manager node, list the nodes so you can
get the worker node ID and then assign the label to the worker node:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ssh swarm-manager
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker node &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker node update &lt;span class=&quot;nt&quot;&gt;--label-add&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;database wqb9dnx6otanxoc529qfwblvq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;deploying-the-rails-app-to-the-cluster&quot;&gt;Deploying the Rails app to the cluster&lt;/h2&gt;

&lt;p&gt;Since Rails 7.1, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails new&lt;/code&gt; command generates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;  tuned for production use with proper
caching layers and multi-stage building. We will use this file to build the image that will
be used by the web service in the stack.&lt;/p&gt;

&lt;p&gt;We will use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-stack.yml&lt;/code&gt; file to define the services and deploy the app to the cluster. Create the file
in the root of the Rails app and add the following content:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.7&apos;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;dockerhub_username&amp;gt;/swarm-demo:prod&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;database&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;80:3000&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;RAILS_MASTER_KEY=c51c56d33c031224c4678f44dd7eafa0&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_USER=swarm_demo&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_PASSWORD=production-secure-password&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node.labels.type == app&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;postgres:15&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_USER=swarm_demo&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POSTGRES_PASSWORD=production-secure-password&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;5432:5432&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;placement&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;constraints&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node.labels.type == database&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;db_data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Make sure to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RAILS_MASTER_KEY&lt;/code&gt; with the content of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/master.key&lt;/code&gt;. Also, this is for demonstration
purposes only, make sure not to expose sensitive information in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-stack.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/database.yml&lt;/code&gt; we need to set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;database&lt;/code&gt; as it is the name of the service in the stack. Also,
we need to set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;username&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password&lt;/code&gt; to the environment variables referenced in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-stack.yml&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;production&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;*default&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;swarm_demo_production&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;database&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV[&quot;POSTGRES_USER&quot;] %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV[&quot;POSTGRES_PASSWORD&quot;] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Starting from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails 7.1&lt;/code&gt; ssl is enforced by default, so we need to set the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.force_ssl = false&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/environments/production.rb&lt;/code&gt; file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;build-x86-images-on-m1-mac&quot;&gt;Build x86 images on m1 mac:&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker buildx build &lt;span class=&quot;nt&quot;&gt;--platform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;linux/amd64 &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; Dockerfile &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &amp;lt;dockerhub_username&amp;gt;/swarm-demo:prod &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;upload-image-to-registry&quot;&gt;Upload image to registry:&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker push &amp;lt;dockerhub_username&amp;gt;/swarm-demo:prod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we are ready to deploy the app to the cluster by creating a Docker Context for the manager node, switching to it, and then
running the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker stack deploy&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker context create swarm-demo &lt;span class=&quot;nt&quot;&gt;--docker&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ssh://swarm-manager
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker context use swarm-demo
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker stack deploy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; docker-stack.yml swarm-demo

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Creating network swarm-demo_default
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Creating service swarm-demo_database
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Creating service swarm-demo_web
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, you should be able to access the Rails app by visiting the IP address of the manager node in your browser:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-swarm-hetzner/index-page.png&quot; alt=&quot;Rails index page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To make shure the database is working, create a new post and verify that it persists after modifying the
page’s header, rebuilding the image and redeploying the stack:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker buildx build &lt;span class=&quot;nt&quot;&gt;--platform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;linux/amd64 &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; Dockerfile &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &amp;lt;dockerhub_username&amp;gt;/swarm-demo:prod &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker push &amp;lt;dockerhub_username&amp;gt;/swarm-demo:prod
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker stack deploy &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; docker-stack.yml swarm-demo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/docker-swarm-hetzner/new-index-page.png&quot; alt=&quot;Rails index page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I hope this post was helpful and that you were able to deploy your Rails app to a Docker Swarm cluster on Hetzner.
If you have any questions or suggestions, feel free to reach out to me on &lt;a href=&quot;https://twitter.com/rmontas&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;</content><author><name></name></author><summary type="html">Recently, I&apos;ve been working on a project using Ruby on Rails and decided to use Hetzner for hosting and Docker Swarm to handle the container orchestration in production.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.rafaelmontas.com/assets/images/docker-swarm-hetzner/swarm-hetzner.jpg" /><media:content medium="image" url="https://www.rafaelmontas.com/assets/images/docker-swarm-hetzner/swarm-hetzner.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Rails World 2023</title><link href="https://www.rafaelmontas.com/rails-world-2023/" rel="alternate" type="text/html" title="Rails World 2023" /><published>2023-10-12T00:00:00-04:00</published><updated>2023-10-12T00:00:00-04:00</updated><id>https://www.rafaelmontas.com/rails-world-2023</id><content type="html" xml:base="https://www.rafaelmontas.com/rails-world-2023/">&lt;p&gt;Rails World 2023 was an amazing conference. It was my first Rails conference ever
and I couldn’t be more excited about it with such &lt;a href=&quot;https://rubyonrails.org/world/speakers&quot;&gt;lineup of speakers&lt;/a&gt;.
Everything was so well organized, the venue was great, the food was delicious, and
the sponsor booths were nicely set up.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/rails-world/venue.png&quot; alt=&quot;Rails World Venue&quot; class=&quot;rails-world&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The conference kicked off with a keynote by &lt;a href=&quot;https://twitter.com/dhh&quot;&gt;DHH&lt;/a&gt; where
he talked about the future of Rails and new tools like &lt;a href=&quot;https://strada.hotwired.dev/&quot;&gt;Strada&lt;/a&gt;,
&lt;a href=&quot;https://kamal-deploy.org/&quot;&gt;Kamal&lt;/a&gt;, &lt;a href=&quot;https://github.com/rails/solid_cache&quot;&gt;Solid Cache&lt;/a&gt;,
Solid Queue and Turbo 8. I’m personally very excited about these new tools and eager
to try them out to see how they can help me build better Rails applications.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/rails-world/keynote.png&quot; alt=&quot;Rails World Venue&quot; class=&quot;rails-world&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After the keynote, followed a series of talks where the speakers shared their knowledge
and dug deep into specific topics. &lt;a href=&quot;https://github.com/jayohms&quot;&gt;Jay Ohms&lt;/a&gt; talked about
&lt;a href=&quot;https://strada.hotwired.dev/&quot;&gt;Strada&lt;/a&gt; and how it can help you build better Turbo Native
apps by bridging the gap between the web and native worlds and leveraging Stimulus.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jorgemanrubia&quot;&gt;Jorge Manrubia&lt;/a&gt; talked about Turbo 8 and specially
about &lt;a href=&quot;https://github.com/hotwired/turbo/pull/1019&quot;&gt;morphing&lt;/a&gt;, which is a new feature
that allows you to do &lt;a href=&quot;https://dev.37signals.com/a-happier-happy-path-in-turbo-with-morphing/&quot;&gt;smoother page updates and also simplifies
the broadcasting system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There were many more amazing talks by incredible speakers that I really enjoyed and learned
a lot from. The Rails Core AMA session was also very exciting and fun. Finally, thanks to
&lt;a href=&quot;https://www.linkedin.com/in/amandabrookeperino/&quot;&gt;Amanda Perino&lt;/a&gt;, The Rails Foundation,
contributors, sponsors, and everyone else involved for making this conference an amazing one.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/rails-world/core-ama.png&quot; alt=&quot;Rails World Venue&quot; class=&quot;rails-world&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’m looking forward to Rails World 2024 in Toronto!&lt;/p&gt;</content><author><name></name></author><summary type="html">A quick recap of the amazing Rails World 2023 and also my first Rails related conference ever.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.rafaelmontas.com/assets/images/rails-world-2023.png" /><media:content medium="image" url="https://www.rafaelmontas.com/assets/images/rails-world-2023.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Ruby’s method-lookup path and Object Individuation</title><link href="https://www.rafaelmontas.com/ruby-method-lookup-path/" rel="alternate" type="text/html" title="Ruby’s method-lookup path and Object Individuation" /><published>2023-06-13T00:00:00-04:00</published><updated>2023-06-13T00:00:00-04:00</updated><id>https://www.rafaelmontas.com/ruby%20method-lookup%20path</id><content type="html" xml:base="https://www.rafaelmontas.com/ruby-method-lookup-path/">&lt;p&gt;Objects, in Ruby, don’t “have” methods but, rather, find them by searching its
class and that class’s superclass, and onward, up to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; or even &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BasicObject&lt;/code&gt;
class, or in a module that has been mixed into any of those classes.&lt;/p&gt;

&lt;p&gt;Most of the time, you’ll use the dot operator “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt;” (There’s also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__send__&lt;/code&gt;, and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public_send&lt;/code&gt; alternatives) to “prompt” the object to go find a method
(send messages to objects). In practice, the message being sent is the name of a method.&lt;/p&gt;

&lt;h2 id=&quot;demonstration-of-basic-module-inclusion-and-inheritance&quot;&gt;Demonstration of basic module inclusion and inheritance&lt;/h2&gt;

&lt;p&gt;Let’s write some basic classes, modules, and methods so we can easily visualize the logic
and mechanics of method lookup and hopefully better understand how objects find methods.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;M&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello from module M&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;C&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;M&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;D&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Hello from module M&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The search ends when the method being searched for is found, or with an error condition
if it isn’t found. This error condition is triggered by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;method_missing&lt;/code&gt; method.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kernel&lt;/code&gt; module provides an instance method called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;method_missing&lt;/code&gt;. This method
is executed whenever an object receives a message that doesn’t match a method anywhere
in the object’s method-lookup path.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;how-far-does-the-method-search-go&quot;&gt;How far does the method search go?&lt;/h2&gt;

&lt;p&gt;However many classes and modules it may cross along the way, the search for a method
can always go as far up as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BasicObject&lt;/code&gt;, which has a few instance methods. But to
understand the common behavior of all Ruby objects, you have to look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; or
more precisely, you have to look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kernel&lt;/code&gt; where most of Ruby’s fundamental methods
are defined. And because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; mixes in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kernel&lt;/code&gt;, all instances of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; and
all descendants of it have access to the instance methods in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kernel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The illustration below show the method search path for the code example above all
the way up the chain.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/method-lookup-article/method-lookup.svg&quot; alt=&quot;Method-lookup path&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;overriding-methods&quot;&gt;Overriding methods&lt;/h2&gt;

&lt;p&gt;Since the method search process passes through multiple classes and modules, an
object can have multiple methods with the same name in its method-lookup path.
Still, if the object’s method-lookup path includes two or more same-named
methods, the first one encountered is executed.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Interest&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;calculate_interest&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;We are in module Interest&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Account&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Interest&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;calculate_interest&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;We are in class Account&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;calculate_interest&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# We are in class Account&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also, a class could mix in two or more modules and more than one implements
the same method being searched for. In that case, the most-recently mixed-in
module is searched first.&lt;/p&gt;

&lt;h2 id=&quot;how-prepend-and-extend-work&quot;&gt;How &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepend&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extend&lt;/code&gt; work&lt;/h2&gt;

&lt;p&gt;Even though &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include&lt;/code&gt; is the most common way of mixing in modules into a
class, Ruby provides two other ways to achieve that but with some differences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepend&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepend&lt;/code&gt; a module to a class, the object looks in that module first,
before it looks in the class. it basically inserts the module at the beginning of
the ancestors chain.&lt;/p&gt;

&lt;p&gt;You can see the difference between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepend&lt;/code&gt; reflected when calling
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ancestors&lt;/code&gt; on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt; class, which lists all the classes and modules where
an instance of the class will search for methods.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;LookHereFirst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;LookHereSecond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;prepend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LookHereFirst&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LookHereSecond&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ancestors&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [LookHereFirst, Person, LookHereSecond, Object, PP::ObjectMixin, Kernel, BasicObject]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You could use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepend&lt;/code&gt; when you want methods in a module to take precedence over
the versions defined in a given class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extend&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extend&lt;/code&gt; is another way of mixing a module into a class. The
difference is that the module’s methods will be available as class methods instead
of instance methods.&lt;/p&gt;

&lt;p&gt;Had we used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extend&lt;/code&gt; rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepend&lt;/code&gt; in our example above, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LookHereFirst&lt;/code&gt;
module would not have been inserted into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt;’s ancestors chain. Instead, Ruby
inserts the module in the ancestors chain of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Person&lt;/code&gt;’s &lt;em&gt;singleton class&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;where-do-singleton-methods-fit-in-the-method-lookup-path&quot;&gt;Where do singleton methods fit in the method-lookup path?&lt;/h2&gt;

&lt;p&gt;An object’s singleton methods live in the object &lt;em&gt;singleton class&lt;/em&gt; and so an object
can call instance methods from its class and from its singleton class. It has both.&lt;/p&gt;

&lt;p&gt;To solve a message into a method, an object looks in all the instance methods
defined in these two classes, along with methods available through ancestral classes
or through any modules that have been mixed in or prepended to any of these classes.&lt;/p&gt;

&lt;p&gt;Let’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepend&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include&lt;/code&gt; two modules in an object’s singleton class and then
update our diagram to see singleton classes taken into account in the method-lookup
path.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class &amp;lt;&amp;lt; object&lt;/code&gt; notation is a common way of opening an object’s singleton class.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;M&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello from module M&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;X&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello from module X in object&apos;s singleton class&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;D&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;prepend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;M&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;N&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;prepend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Y&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Hello from module X in object&apos;s singleton class&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In its search for the method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;object&lt;/code&gt; looks first for any module prepended
to its singleton class; then it looks in the singleton class itself. It then looks
in any modules that the singleton class has included. Finally, the search proceeds
up to the object’s original class, and so forth.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/method-lookup-article/method-lookup-singleton.svg&quot; alt=&quot;Method-lookup path with singleton classes&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;class-methods-are-singleton-methods&quot;&gt;Class methods are singleton methods&lt;/h2&gt;

&lt;p&gt;Class methods are singleton methods defined on objects of class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class&lt;/code&gt;.
Normally, when you define a singleton method on an object, no other object
can serve as the receiver in a call to that method. But, methods defined
as singleton methods of a class object can also be called on subclasses
of that class.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/method-lookup-article/singleton-class-relation.svg&quot; alt=&quot;Relationship among classes in method-lookup path&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The diagram above shows the relationship among classes and their singleton classes.&lt;/p&gt;

&lt;p&gt;In summary, now we better understand how an object looks for a method when
resolving a message.&lt;/p&gt;

&lt;p&gt;I really hope you find this article useful and thank you for taking the time.&lt;/p&gt;</content><author><name></name></author><summary type="html">Objects seek their methods in both classes and superclasses, all the way up the inheritance tree; let&apos;s see how this method-lookup process works when modules are also involved.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.rafaelmontas.com/assets/images/method-lookup-path.png" /><media:content medium="image" url="https://www.rafaelmontas.com/assets/images/method-lookup-path.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Getting to know Ruby’s Enumerable Module</title><link href="https://www.rafaelmontas.com/getting-to-know-ruby-enumerable-module/" rel="alternate" type="text/html" title="Getting to know Ruby’s Enumerable Module" /><published>2023-04-16T00:00:00-04:00</published><updated>2023-04-16T00:00:00-04:00</updated><id>https://www.rafaelmontas.com/getting%20to%20know%20%20ruby%20enumerable%20module</id><content type="html" xml:base="https://www.rafaelmontas.com/getting-to-know-ruby-enumerable-module/">&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerable&lt;/code&gt; is a module in the Ruby standard library. Classes that include it have
to define an instance method called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;each&lt;/code&gt;, which yields the elements of the collection
in succession. Once the iterator is defined and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerable&lt;/code&gt; is mixed in, the class
now supports all sorts of collection-related behavior. Also, keep in mind, that
although &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerable&lt;/code&gt; adds common functionality to each of the collection classes
that includes it, each of them actually overrides some of the methods.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyArray&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Enumerable&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# yield elements of the collection&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can query which methods &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerable&lt;/code&gt; provides by sending the message
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance_methods&lt;/code&gt; to it and passing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; argument so you get only methods
defined in the module itself.&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;irb(main):001:0&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;Enumerable.instance_methods&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to understand &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerable&lt;/code&gt; at a deeper level, let’s write a few of its
methods while trying to cover as many operations as posible.&lt;/p&gt;

&lt;h2 id=&quot;methods-for-querying&quot;&gt;Methods for Querying&lt;/h2&gt;

&lt;p&gt;Some Enumerable methods return information about the collection other than the elements
themselves. Some return either true or false if one or more element matches certain
criteria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include?&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; if the item yielded to the block is equal the argument passed, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;
otherwise.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (1..5).include?(2)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works just fine for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Arrays&lt;/code&gt; but if we were querying a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt;, we would need to
adjust for the fact that when you iterate through a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;each&lt;/code&gt; it yields back
one key/value pair at a time (two-element arrays). The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash#include?&lt;/code&gt; method checks
for key inclusion&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#any?&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; if any element meets a specified criteria, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; otherwise.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;any?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;

  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; (1..5).any? { |n| n &amp;gt; 3 }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#count&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns the count of elements based on a criteria passed as argument or a block, if
given.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;nb&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;warning: given block not used&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (1..5).count { |value| value &amp;gt; 3 }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#tally&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counts the ocurrences of each element. Returning a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; with the collection’s elements
as keys and corresponding counts as values.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tally&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tally&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tally&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tally&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# [1, 2, 2, 2, 3, 3, 4].tally&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {1=&amp;gt;1, 2=&amp;gt;3, 3=&amp;gt;2, 4=&amp;gt;1}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;methods-for-searching-and-filtering&quot;&gt;Methods for Searching and Filtering&lt;/h2&gt;

&lt;p&gt;It’s common to want to filter a collection of objects based on a selection criteria. We’ll
look at several facilities for filtering and searching collections. All of them
expect a code block, where you difine your selection criteria (your tests for inclusion
or exclusion).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#find&lt;/code&gt; aliased as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#detect&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns the first element in the collection for which the code block returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;. If no
code block is provided, it returns an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerator&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enum_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__method__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:detect&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:find&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (1..5).find {|value| value &amp;gt; 2}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#find_all&lt;/code&gt; aliased as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#select&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; containing all the elements of the original collection that matched
the criteria in the code block. If no matching elements are found, it returns an empty
collection. Also, if no code block is provided, it returns an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerator&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find_all&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enum_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__method__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:find_all&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (1..9).find_all {|value| value % 3 == 0 }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [3, 6, 9]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#find_index&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns the index of the first element that meets the specified criteria, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; if
no element matches the criteria. It returns an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerator&lt;/code&gt; if neither a code
block nor an argument are provided.&lt;/p&gt;

&lt;p&gt;For this method to work, make sure your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each&lt;/code&gt; implementation returns an
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerator&lt;/code&gt; when no code block is provided. This will allow us to chain methods, as
in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.each.with_index&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enum_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__method__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;

  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (1..5).find_index(2)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#group_by&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When given a code block, it returns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt;. For each unique value returned by the
block, the results hash gets a key; the value for that key is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; of all the
elements of the collection for which the block returned that value. If no code block is
given, it returns an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerator&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;group_by&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enum_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__method__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([])&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# colors = [{group: &apos;primary&apos;}, {group: &apos;secondary&apos;}, {group: &apos;primary&apos;}]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# colors.group_by { |value| value[:group] }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {&quot;primary&quot;=&amp;gt;[{:group=&amp;gt;&quot;primary&quot;}, {:group=&amp;gt;&quot;primary&quot;}], &quot;secondary&quot;=&amp;gt;[{:group=&amp;gt;&quot;secondary&quot;}]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#map&lt;/code&gt; aliased as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#collect&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Returns an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; when given a block. Returns and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerator&lt;/code&gt; otherwise. The returned
array is always the same size as the original collection. Its elements are the result
of calling the code block on each element in the original object.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enum_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__method__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:collect&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:map&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (1..5).map { |value| value * value }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [1, 4, 9, 16, 25]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#inject&lt;/code&gt; aliased as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#reduce&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Works by initializing an accumulator object, performs a calculation on each iteration
and reset the accumulator to the result of that calculation. Returns the return value
from the last block call.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;operand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operand&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:reduce&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:inject&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (1..5).inject { |sum, value| sum + value }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ve gotten to know &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerable&lt;/code&gt; in a more detailed way and it will better
positioned us to handle everyday programming as we’ll use the enumeration-related
facilities of the language virtually every time we write a Ruby program.&lt;/p&gt;</content><author><name></name></author><summary type="html">Collection classes in Ruby typically include (or extend) Enumerable. If it has an #each method it probably mixes in the Enumerable Module.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.rafaelmontas.com/assets/images/getting-to-know-rubys-enumerable-module.png" /><media:content medium="image" url="https://www.rafaelmontas.com/assets/images/getting-to-know-rubys-enumerable-module.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Implementing Data Structures in Ruby: Arrays</title><link href="https://www.rafaelmontas.com/arrays-from-scratch-in-ruby/" rel="alternate" type="text/html" title="Implementing Data Structures in Ruby: Arrays" /><published>2023-03-11T00:00:00-04:00</published><updated>2023-03-11T00:00:00-04:00</updated><id>https://www.rafaelmontas.com/arrays%20from%20scratch%20in%20ruby</id><content type="html" xml:base="https://www.rafaelmontas.com/arrays-from-scratch-in-ruby/">&lt;p&gt;Just recently, I transitioned careers to become a Software Developer using mainly Ruby and Ruby on Rails and wanted to strengthen my understanding of Data Structures &amp;amp; Algorithms, which I am sure would allow me to become a better programmer. So with this in mind, I decided to read &lt;a href=&quot;https://www.manning.com/books/the-well-grounded-rubyist-third-edition&quot;&gt;The Well-Grounded Rubyist, Third Edition&lt;/a&gt; to better understand the basics of the Ruby language and &lt;a href=&quot;https://pragprog.com/titles/jwdsal2/a-common-sense-guide-to-data-structures-and-algorithms-second-edition/&quot;&gt;A Common-Sense Guide to Data Structures and Algorithms, Second Edition&lt;/a&gt; to start implementing algorithms with Space and Time Complexity in mind.&lt;/p&gt;

&lt;p&gt;While working through these books and a few blog posts from amazing people, I learned how to implement data structures from scratch in Ruby and in this post, we will do just that by trying to replicate the inner workings and methods of the &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-is-an-array&quot;&gt;What is an Array?&lt;/h2&gt;
&lt;p&gt;When a program declares an array, it allocates a contiguous set of empty cells for use in the program (Ruby implements dynamic arrays). This translates to an ordered collection of objects.&lt;/p&gt;

&lt;p&gt;Ruby provides us with the class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; which we can instantiate, among other ways, by explicitly calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array.new&lt;/code&gt; or by using the literal constructor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;building-an-array-from-scratch&quot;&gt;Building an Array from scratch&lt;/h2&gt;
&lt;p&gt;Let’s begin by creating and initializing our class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray&lt;/code&gt; using a &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Hash.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt;&lt;/a&gt; to keep track of the elements within the collection. Also, Arrays keep track of the number of objects the collection contains at all times. We will implement an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;attr_reader&lt;/code&gt; to be able to query instances of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray&lt;/code&gt; about this information using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray#length&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyArray&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:length&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We initialize our class with two instance variables, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@length&lt;/code&gt;, set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; by default and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@elements&lt;/code&gt; which is set to an empty &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt;. Also, with this implementation, we can create a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray&lt;/code&gt; containing the elements of a given enumerable object, increasing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@length&lt;/code&gt; on each iteration.&lt;/p&gt;

&lt;p&gt;Before we move on, let’s replicate even more the behavior and terminal output by creating a method that will allow us to instantiate our class like the way we instantiate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arrays&lt;/code&gt; with literal constructors and specially similar to the class &lt;a href=&quot;https://ruby-doc.org/stdlib-2.7.1/libdoc/set/rdoc/Set.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;#&amp;lt;%s: [%s]&amp;gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;inspect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self.[](*ary)&lt;/code&gt; defines a class method and thanks to &lt;a href=&quot;https://blog.appsignal.com/2018/02/20/ruby-magic-syntactic-sugar-methods.html&quot;&gt;Ruby’s syntactic sugar&lt;/a&gt;, we can now create instances of our class by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray[&apos;foo&apos;, &apos;bar&apos;]&lt;/code&gt;. The implementation of &lt;a href=&quot;https://www.rubyguides.com/2018/12/ruby-inspect-method/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inspect&lt;/code&gt;&lt;/a&gt; was inspired by the way the &lt;a href=&quot;https://github.com/ruby/set/blob/master/lib/set.rb&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set&lt;/code&gt;&lt;/a&gt; class implements it. Resulting in a terminal output as shown below.&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;irb(main):001:0&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;MyArray[&lt;span class=&quot;s1&quot;&gt;&apos;foo&apos;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&apos;bar&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#&amp;lt;MyArray: [&quot;foo&quot;, &quot;bar&quot;]&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, let’s start creating the methods we are going to need in order to cover the basic operations of reading, searching, inserting and deleting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#[] (aliased as #slice)&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you have objects in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt; you can retrieve those objects by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#[]&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#slice(index)&lt;/code&gt; methods. Retrieving single elements like this takes constant time in terms of Time Complexity analysis: O(1).&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Returns the element at the given index.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#[]=(index, element)&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s now implement its setter equivalent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#[]=(index, element)&lt;/code&gt; which allows us to set an element at a given index. In the case the given index is out of range for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray&lt;/code&gt; we set those slots between the given index and the last element to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;[]=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#push(element) (aliased as #&amp;lt;&amp;lt;)&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To add an element to the end of the collection, you can use &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-push&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#push(element)&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-3C-3C&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&amp;lt;&amp;lt;&lt;/code&gt;&lt;/a&gt;. Returning the collection itself. Here, knowing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arrays&lt;/code&gt; have zero based indexing, we can implement it by setting the given element at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@length&lt;/code&gt; index, which is one slot to the right of the last element in the collection.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Constant Time to add element to the end of collection&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Time Complexity: O(1)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#pop&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here we remove the last element of the collection, reduce the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@length&lt;/code&gt; instance variable by 1, and return the deleted element back which is accomplished by saving said element in a variable before removing it.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Constant time to remove last element. Time Complexity: O(1)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pop&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;latest_element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;latest_element&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#unshift(value)&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#shift&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As you have seen, appending and removing elements from the end of the collection is fairly straight forward. Now, to accomplish the same operations at the beginning of the collection, we have to shift the remaining elements either to the right (if we are appending &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-unshift&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#unshift(value)&lt;/code&gt;&lt;/a&gt;) or to the left (if we are removing &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-shift&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#shift&lt;/code&gt;&lt;/a&gt;). So, we will be creating a couple of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; methods that will help us do just that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#unshift(value)&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyArray&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# Linear time to add at the beginning of collection.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Moves other values. Time Complexity: O(n)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unshift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unshift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, when we call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#unshift(value)&lt;/code&gt;, we start shifting by 1 index to the right all elements of the collection, starting from the last one so we don’t lose any value in the process. Once all elements are shifted, we set the element at index 0 to the value being inserted and increment the collection’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;length&lt;/code&gt; by 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#shift&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similarly, to remove the first element from the collection, we need to shift all elements but this time to the left. Basically, we start shifting left from index 1 until we have shifted the last element which will be duplicated, so we remove it and decrease our collection’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;length&lt;/code&gt; by 1.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyArray&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linear time to remove at the beginning of the collection.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Shifts other values. Time Complexity: O(n)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first_element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_element&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;iterating-over-myarray&quot;&gt;Iterating over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;In order to iterate over the collection, we need to implement the &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-each&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each&lt;/code&gt;&lt;/a&gt; method. The idea behind &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-each&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each&lt;/code&gt;&lt;/a&gt; is simple: by calling it on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#MyArray&lt;/code&gt; collection it will yield back each item in it to the code block provided, one at a time. The return value of &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-each&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each&lt;/code&gt;&lt;/a&gt;, when it’s given a block, is its receiver, the original collection. When it isn’t given a block, it returns an enumerator, which is what allows us to chain other methods like &lt;a href=&quot;https://ruby-doc.org/core-2.5.0/Enumerator.html#method-i-with_index&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enumerator#with_index&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Calls the given block once for each element in the collection, passing&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# the element as a parameter. Return an enumerator if no block is given.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enum_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__method__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Having done that, we can implement the method &lt;a href=&quot;https://ruby-doc.org/core-2.7.0/Array.html#method-i-delete&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#delete&lt;/code&gt;&lt;/a&gt;, which makes use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each&lt;/code&gt; by first finding the index of the given element, removing it from the collection, and then shifting all remaining elements to the left.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#delete(element)&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Linear time to remove at an arbitrary location. Shifts other values.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Time Complexity: O(n)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The journey of learning the basics of Ruby and the inner working of collection classes like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; has been an amazing experience and I’m looking forward to share all my learnings in subsequent posts like this one. I’ll let you with the code for our entire &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyArray&lt;/code&gt; class below and a link to the &lt;a href=&quot;https://github.com/rafaelmontas/ds-algorithms-ruby&quot;&gt;Github repo&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyArray&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:length&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;#&amp;lt;%s: [%s]&amp;gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;inspect&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Returns the element at the given index.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;[]=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Constant Time to add element to the end of collection&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Time Complexity: O(1)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Constant time to remove last element. Time Complexity: O(1)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pop&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;latest_element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;latest_element&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linear time to add at the beginning of collection.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Moves other values. Time Complexity: O(n)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unshift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linear time to remove at the beginning of the collection.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Shifts other values. Time Complexity: O(n)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first_element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_element&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Calls the given block once for each element in the collection, passing&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# the element as a parameter. Return an enumerator if no block is given.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enum_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__method__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linear time to remove at an arbitrary location. Shifts other values.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Time Complexity: O(n)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unshift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shift_elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;sources-of-inspiration&quot;&gt;Sources of Inspiration&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/torianne02/data-structures-from-scratch-array-24d5&quot;&gt;Data Structures From Scratch: Array&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://dev.to/isalevine/exploring-data-structures-from-a-ruby-background-pt-1-arrays-5bma&quot;&gt;Exploring Data Structures From a Ruby Background, Pt. 1: Arrays&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/ruby/set/blob/master/lib/set.rb&quot;&gt;Ruby’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set&lt;/code&gt; source code&lt;/a&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">Let&apos;s strengthen our understanding of Arrays by implementing them from scratch in Ruby. Building a solid foundation in Data Structures and Algorithms.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.rafaelmontas.com/assets/images/default-card.png" /><media:content medium="image" url="https://www.rafaelmontas.com/assets/images/default-card.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>