<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rafał Piekara</title>
    <description>The latest articles on DEV Community by Rafał Piekara (@rafalpiekara).</description>
    <link>https://dev.to/rafalpiekara</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F748804%2Ff7df5628-aa79-4adf-85f4-a44066ebc4b4.jpeg</url>
      <title>DEV Community: Rafał Piekara</title>
      <link>https://dev.to/rafalpiekara</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rafalpiekara"/>
    <language>en</language>
    <item>
      <title>API tests in the repository? It can be done with HttpClient!</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Wed, 09 Feb 2022 06:32:55 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/api-tests-in-the-repository-it-can-be-done-with-httpclient-1bni</link>
      <guid>https://dev.to/rafalpiekara/api-tests-in-the-repository-it-can-be-done-with-httpclient-1bni</guid>
      <description>&lt;p&gt;If you create JSON API, you probably know by heart the support for tools such as Postman, Insomnia, Curl. However, when querying with them, it is not possible to store API tests in a repository and manage them with version control. I also thought it was impossible until I found this &lt;a href="https://www.youtube.com/watch?v=n8KCuKhDSZY" rel="noopener noreferrer"&gt;video&lt;/a&gt;. JetBrains tools have a built-in ingenious plugin - HttpClient. In this post, I have prepared for you a short demonstration of its capabilities using Ruby Mine and Ruby on Rails. API tests in the repository? Can be! Very much!&lt;/p&gt;

&lt;p&gt;As a demonstration environment I will use a simple application written in Ruby on Rails. It took me 7 minutes to create this simple API with simulated authorization! I was timing myself on purpose. That's why I love RoR! But to the point.&lt;/p&gt;

&lt;p&gt;The application has a simple structure. The main actor is the user who can own books and cars. Collector. Let's say it's such a typical directory application. Simply put.&lt;/p&gt;

&lt;h2&gt;
  
  
  I created the data structure with the following migrations.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7vfoocuabudu4hoq78f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7vfoocuabudu4hoq78f.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kjds65pdz4b39b5j2ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kjds65pdz4b39b5j2ma.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvp3fnj4p45wf5pituqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvp3fnj4p45wf5pituqf.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Model definition:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj9t3sac4qdg9ze2e48o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj9t3sac4qdg9ze2e48o.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hrfjh4ed5448k84fatu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hrfjh4ed5448k84fatu.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwio6xvaqhr7ri4m2cwlz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwio6xvaqhr7ri4m2cwlz.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  And controllers.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8v3r8mzchmpni98y9a2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8v3r8mzchmpni98y9a2.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7k4cmvghohnhph9ydzl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7k4cmvghohnhph9ydzl4.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmkfi8x51tnvvbqvn0gm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmkfi8x51tnvvbqvn0gm.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn3gl2vvhlgnv5grhbdct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn3gl2vvhlgnv5grhbdct.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  And &lt;code&gt;ApplicationController&lt;/code&gt;, into which I put practically all the logic.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpbiakkdwcshdo4a0hio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpbiakkdwcshdo4a0hio.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In API we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if the application is running (&lt;code&gt;home&lt;/code&gt; action).&lt;/li&gt;
&lt;li&gt;Download all books of a given user from the database.&lt;/li&gt;
&lt;li&gt;Download all cars of a given user from the database.&lt;/li&gt;
&lt;li&gt;Download a list of all users in the database.&lt;/li&gt;
&lt;li&gt;Log in to the application and obtain an authorization token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Access to specific user data is secured with a token that should be provided in the &lt;code&gt;Authorization&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;Before starting, I created a few users, a few books and a few cars in the database.&lt;/p&gt;

&lt;p&gt;We start our adventure with HttpClient. Just create a file with the &lt;code&gt;.http&lt;/code&gt; extension and RubyMine will do the rest and adjust the interface to fire queries.&lt;/p&gt;

&lt;p&gt;I have created the &lt;code&gt;api_test.http&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjdecvzr30sc52xsyiqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjdecvzr30sc52xsyiqg.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First requests. I check if the API works. One line is enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawm4ezbe225mxbshlnfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawm4ezbe225mxbshlnfx.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, but it probably won't end with one request. Fortunately, I don't have to enter the address in subsequent queries every time, what's more, I can have addresses configured for different environments and run my client in one of them.&lt;/p&gt;

&lt;p&gt;I add the &lt;code&gt;http-client.env.json&lt;/code&gt; file in which I set the environment and the &lt;code&gt;url&lt;/code&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now I can use a variable instead of a patched url. The IDE tells me everything beautifully.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m1nh2growh1dqk4cwty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m1nh2growh1dqk4cwty.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We separate subsequent queries with three hashes: &lt;code&gt;###&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gnga5gzryck0cyj8hav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gnga5gzryck0cyj8hav.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It's time to log in
&lt;/h2&gt;

&lt;p&gt;I am adding a new request, this time of the POST type. See how easy it is to define headers and parameters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F409zk58rzgmo6a6zlz2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F409zk58rzgmo6a6zlz2m.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authorization was successful and I got an &lt;code&gt;auth_token&lt;/code&gt; in response. Now it's time to capture it, assign it to a variable, and use it in subsequent queries. This is done in the code that we put in braces with the percentage &lt;code&gt;{%%}&lt;/code&gt;, which is just &lt;strong&gt;JavaScript&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="sr"&gt;/logi&lt;/span&gt;&lt;span class="err"&gt;n
&lt;/span&gt;&lt;span class="nx"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="nx"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user1@email.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
  &lt;span class="nx"&gt;auth_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;auth_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;###&lt;/span&gt;
&lt;span class="nx"&gt;GEThttp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//{{url}}/users/1&lt;/span&gt;
&lt;span class="nx"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="nx"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Bearer&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now authorize our inquiries with a token:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupgvkbq8alyzkpcekcy3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupgvkbq8alyzkpcekcy3.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HttpClient also has something for test fans. You can write automated tests for your queries! These tests are run together with queries, and their results are visible in the IDE runner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;###&lt;/span&gt;
&lt;span class="nx"&gt;GEThttp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//{{url}}/users/1&lt;/span&gt;
&lt;span class="nx"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="nx"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Bearer&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Get User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;books_count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Books count returned is wrong&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;})&lt;/span&gt;

 &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Response status is not 200&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;})&lt;/span&gt;
 &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F123mk6rvnyxz7yuvlz24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F123mk6rvnyxz7yuvlz24.png" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What now? Git commit, git push. And we have versioned tests of our API.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotch0lp4o9anegesy1p2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotch0lp4o9anegesy1p2.gif" alt="TestAPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the repository with the above code &lt;a href="https://github.com/rafpiek/httpclient-rubymine-sample" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>RSpec - clear test documentation</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Fri, 04 Feb 2022 07:02:50 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/rspec-clear-test-documentation-16n2</link>
      <guid>https://dev.to/rafalpiekara/rspec-clear-test-documentation-16n2</guid>
      <description>&lt;p&gt;If you are a Ruby on Rails developer, testing is your bread, it's in your blood. Or maybe you haven't had to deal with the tests yet, because you are just starting the adventure with the DHH child. Anyway, I have a tip for you that will make your testing much more readable and convenient. And every time you use the RSpec password, you will think "readable test documentation".&lt;/p&gt;

&lt;p&gt;For testing, I use the most popular library in the RoR world - &lt;strong&gt;RSpec&lt;/strong&gt;. Additionally, my setup complements &lt;strong&gt;DatabaseCleaner&lt;/strong&gt;, &lt;strong&gt;ShouldaMatchers&lt;/strong&gt;, and &lt;strong&gt;FactoryBotRails&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rspec-rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'factory_bot_rails'&lt;/span&gt;
    &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'shoulda-matchers'&lt;/span&gt;
    &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'database_cleaner'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"RAILS_ENV"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'spec_helper'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../../config/environment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rspec/rails'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'shoulda/matchers'&lt;/span&gt;

&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"spec/support/**/*.rb)].each { |f| require f }

RSpec.configure do |config|
  config.fixture_path = "&lt;/span&gt;&lt;span class="c1"&gt;#{::Rails.root}/spec/fixtures"&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use_transactional_fixtures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;infer_spec_type_from_file_location!&lt;/span&gt;

  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:suite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clean_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:truncation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:js&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="ss"&gt;:truncation&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:transaction&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:each&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;DatabaseCleaner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clean&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Shoulda&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Matchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integrate&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test_framework&lt;/span&gt; &lt;span class="ss"&gt;:rspec&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;library&lt;/span&gt; &lt;span class="ss"&gt;:rails&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code we will test looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Fotballer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
    &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;length: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;maximum: &lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:surname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;length: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;maximum: &lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:club&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;length: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;maximum: &lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:nationality&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;length: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;maximum: &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Footballer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :model&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"database columns"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_db_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;of_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_db_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:surname&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;of_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_db_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:club&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;of_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_db_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:nationality&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;of_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the basic configuration of RSpec, placed in the &lt;code&gt;spec_helper.rb&lt;/code&gt; file and performing tests, the console does not print too readable messages, and it is impossible to track the progress of individual tests. Let's just look at what we get.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F318m0j8xs4f9jakvptl6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F318m0j8xs4f9jakvptl6.png" alt="RSpec"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if we would like to monitor the test progress on an ongoing basis and check what has already been done and is green, and what has not passed? Just slightly change RSpec configuration in &lt;code&gt;spec_helper.rb&lt;/code&gt; and set &lt;code&gt;config.color&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;config.formatter&lt;/code&gt; to &lt;code&gt;:documentation&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:documentation&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test result looks much better than before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9ccfq5l3tayg98cfz5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9ccfq5l3tayg98cfz5r.png" alt="RSpec"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fii288cxrcs4sy9d2xm7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fii288cxrcs4sy9d2xm7s.png" alt="RSpec"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaaucfk7kq0afujqcjwi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaaucfk7kq0afujqcjwi.png" alt="RSpec"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Personally, I attach great importance to how the test is printed on the console. In the event of an error, it's much easier to find out where the problem lies. Besides, by checking the entire system, I am able to estimate how many more corrections are waiting for me while the tests are running.&lt;/p&gt;

&lt;p&gt;However, if you want to get off the console and editor and use the only valid RoR IDE at the moment, which is Ruby Mine, the tests are well served there. I prefer this tool to. One click is enough and the test progress is clear and understandable. It is important to choose something according to your own preferences.&lt;/p&gt;

&lt;p&gt;Anyway, for me, the statement: RSpec - clear test documentation will always be the same.&lt;/p&gt;

&lt;p&gt;Read about it in &lt;a href="https://rspec.info/documentation/" rel="noopener noreferrer"&gt;the RSpec documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Wordpress in docker is slow ... I have a solution for that!</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Tue, 01 Feb 2022 09:32:46 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/wordpress-in-docker-is-slow-i-have-a-solution-for-that-46of</link>
      <guid>https://dev.to/rafalpiekara/wordpress-in-docker-is-slow-i-have-a-solution-for-that-46of</guid>
      <description>&lt;p&gt;Docker WordPress is slow, terribly slow. But I have a way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See one simple trick! WordPress and Docker haters hate it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;docker-compose.yml&lt;/code&gt;, in the place where we configure the volumes, we will add the flag &lt;code&gt;:delegated&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;my_wordpress_db:/var/lib/mysql:delegated&lt;/span&gt;

&lt;span class="c1"&gt;###&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./wp-content:/var/www/html/wp-content:delegated&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;These two sites in &lt;br&gt;
&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;br&gt;
 do the job. It is possible to work, even quite comfortably 💪🐳&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3nys33wtvy6d1e5bel5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3nys33wtvy6d1e5bel5.gif" alt="WordpressDocker"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>docker</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Range and Date in Ruby on Rails</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Mon, 31 Jan 2022 06:50:11 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/range-and-date-in-ruby-on-rails-15nk</link>
      <guid>https://dev.to/rafalpiekara/range-and-date-in-ruby-on-rails-15nk</guid>
      <description>&lt;p&gt;Ruby on Rails has its own extension of the Date class, making it very comfortable to work with dates.&lt;/p&gt;

&lt;p&gt;No parsing, no conversion, we write our date helpers like a natural language, so we can read the code in fluent English and at times forget that we are dealing with a programming language. Today I'll show you how to use the combination of the Range and Date classes in Ruby on Rails to create a readable date check.&lt;/p&gt;

&lt;p&gt;The specificity of Ruby allows for one more great thing - expanding core classes. In this example, we will extend the Date class provided by Ruby on Rails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case:
&lt;/h2&gt;

&lt;p&gt;In the offer of report modules or dashboards, you can meet operations consisting of comparing data, filtering data from the previous year, discussion or week. Working with dates in RoR is super fun anyway, but the snippet below will make it even more fun.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_in?&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
    &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;today&lt;/span&gt;
      &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;previous_year&lt;/span&gt;
      &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_year&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_year&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_year&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_year&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_year&lt;/span&gt;
      &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_year&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_year&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;previous_month&lt;/span&gt;
      &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_month&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_month&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_month&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_month&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_month&lt;/span&gt;
      &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_month&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_month&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;previous_week&lt;/span&gt;
      &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_week&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_week&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_week&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_week&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_week&lt;/span&gt;
      &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_week&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_week&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We extend &lt;code&gt;the Date&lt;/code&gt; class here.&lt;/p&gt;

&lt;p&gt;First, I declare an instance method that will check if the date is within the given range. This is an instance method, which will call for instance, or in simpler terms - directly on the date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_in?&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;
  &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then extend &lt;code&gt;the Date&lt;/code&gt; class with static methods. I am overwriting &lt;code&gt;today&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;today&lt;/span&gt;
  &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I create a &lt;code&gt;previous_year&lt;/code&gt; method using a Range that returns a date range for the previous year.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;previous_year&lt;/span&gt;
  &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_year&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_year&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_year&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_year&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I create a &lt;code&gt;current_year&lt;/code&gt; method that returns a date range for the current year.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_year&lt;/span&gt;
    &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_year&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_year&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, the &lt;code&gt;previous_month&lt;/code&gt;, &lt;code&gt;current_month&lt;/code&gt;, &lt;code&gt;previous_week&lt;/code&gt;, and &lt;code&gt;current_week&lt;/code&gt; methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;previous_month&lt;/span&gt;
  &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_month&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_month&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_month&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_month&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_month&lt;/span&gt;
  &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_month&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_month&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;previous_week&lt;/span&gt;
  &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_week&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_week&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prev_week&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_week&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_week&lt;/span&gt;
  &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_week&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_week&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating these auxiliary methods, we can easily write date checking conditions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_in?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current_week&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_in?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;previous_year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current_week&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Combining the &lt;code&gt;Range&lt;/code&gt; and &lt;code&gt;Date&lt;/code&gt; classes in Ruby on Rails is a good idea to improve the readability of your code.&lt;/p&gt;

&lt;p&gt;In the documentation, you can read about &lt;a href="https://ruby-doc.org/core-2.7.1/Range.html"&gt;the Range class&lt;/a&gt; and &lt;a href="https://api.rubyonrails.org/classes/Date.html"&gt;the Date class&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Spread Operator in Ruby and Ruby Ranges</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Sun, 30 Jan 2022 11:06:44 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/spread-operator-in-ruby-and-ruby-ranges-5a5o</link>
      <guid>https://dev.to/rafalpiekara/spread-operator-in-ruby-and-ruby-ranges-5a5o</guid>
      <description>&lt;p&gt;We all remember the revolutionary in JavaScript world turned out to be the introduction of &lt;code&gt;spread operator&lt;/code&gt; with the ES6 standard. Working with the collection has become pleasant and easy. Joining arrays has become very simple. You might think that this makes JS unique in this regard… but no. &lt;strong&gt;We used the spread operator in Ruby before it became fashionable.&lt;/strong&gt; So, if you want to know what the spread operator in Ruby and Ruby Ranges looks like (a very interesting object), I invite you to read it.&lt;/p&gt;

&lt;p&gt;I've learned from experience that Ruby language has a well-developed API when it comes to operations on collections. All thanks to &lt;code&gt;the Enumerable&lt;/code&gt; module and &lt;code&gt;the Array&lt;/code&gt; class, which provide all interesting functionalities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concat
&lt;/h2&gt;

&lt;p&gt;And so Ruby has a &lt;code&gt;concat&lt;/code&gt; method that is used to join arrays together, so, to actions very often used in JS.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; [1, 2, 'a', 'b']&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Ruby Magic
&lt;/h2&gt;

&lt;p&gt;Let me show you an example that proves how great a language Ruby is. We'll use a few less obvious array methods and another cool tool such as Ruby Ranges.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fake password generator
&lt;/h2&gt;

&lt;p&gt;Let's write a simple password generator that we can use to seed the database, mock test data, or generate a password for the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the password may contain lowercase letters&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;password may contain uppercase letters&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the password may contain numbers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the password may contain special characters: $, #, *&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the password may contain a randomly generated &lt;a href="https://starwars.fandom.com/wiki/Wookiee" rel="noopener noreferrer"&gt;Wookie word&lt;/a&gt;, we will use the Faker gem&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s do this!&lt;/p&gt;
&lt;h2&gt;
  
  
  The password may contain lowercase letters
&lt;/h2&gt;

&lt;p&gt;You don't need to install anything, we will use &lt;code&gt;the Range&lt;/code&gt; object which allows us to generate a set of characters or numbers from a specified range. Then we'll convert this object to an array using the &lt;code&gt;to_a&lt;/code&gt; method.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;lowercase_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s1"&gt;'z'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;

&lt;span class="c1"&gt;#=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"g"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"j"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"k"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"u"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"z"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The password may contain uppercase letters
&lt;/h2&gt;

&lt;p&gt;Here we will also use &lt;code&gt;Range&lt;/code&gt; all we need to do is to change parameters to uppercase.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;capital_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s1"&gt;'Z'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;

&lt;span class="c1"&gt;#=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"E"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"G"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"H"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"I"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"J"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"K"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"M"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"O"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"P"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"R"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"T"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"U"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"V"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"W"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Z"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The password may contain numbers
&lt;/h2&gt;

&lt;p&gt;And &lt;code&gt;Range&lt;/code&gt; again.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;

&lt;span class="c1"&gt;#=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The password may contain special characters: $, #, *
&lt;/h2&gt;

&lt;p&gt;A simple board is enough here&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;special_characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'#'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It's easy to make a typo and forget the apostrophe, let's use more fancy syntax.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;special_characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w{ $ # * }&lt;/span&gt;

&lt;span class="c1"&gt;#=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'#'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The password may contain a randomly generated Wookie word
&lt;/h2&gt;

&lt;p&gt;Seems like the hardest part, right?&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;wookie_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Movies&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StarWars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wookiee_sentence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;

&lt;span class="c1"&gt;#=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Ru"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ooma"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"nng"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"roooarrgh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"roooarrgh!"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I use &lt;code&gt;the split&lt;/code&gt; method, which takes space as a default separator and breaks the generated sentence into an array of words understood by Chewbacci.&lt;/p&gt;

&lt;h2&gt;
  
  
  Password generation
&lt;/h2&gt;

&lt;p&gt;Now we have the components, it's time to create a password. First, let's sort all the criteria into one array.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;password_matrix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lowercase_letters&lt;/span&gt;
                      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capital_letters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;special_characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wookie_words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Shuffle
&lt;/h2&gt;

&lt;p&gt;Let's mix it up with &lt;strong&gt;the bang method&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;password_matrix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffle!&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Sample
&lt;/h2&gt;

&lt;p&gt;Let's pick 20 random pieces and mix it up again.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;password_matrix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password_matrix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Join
&lt;/h2&gt;

&lt;p&gt;Now we have to connect and we have the password ready.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;password_matrix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;

&lt;span class="c1"&gt;#=&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;"r4gP#Tsga.0aBbKc$kabukkmCYhnn-rowr"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Spread Operator
&lt;/h2&gt;

&lt;p&gt;All the code, with a small, refactor to simplify the steps, looks like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fake_password&lt;/span&gt;
  &lt;span class="n"&gt;lowercase_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s1"&gt;'z'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;
  &lt;span class="n"&gt;capital_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s1"&gt;'Z'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;
  &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;
  &lt;span class="n"&gt;special_characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w{ $ # * }&lt;/span&gt;
  &lt;span class="n"&gt;wookie_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Movies&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StarWars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wookiee_sentence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;

  &lt;span class="n"&gt;password_matrix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lowercase_letters&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capital_letters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capital_letters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;special_characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wookie_words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A lot of this code, and I promised you a spread operator. Well, to combine arrays into one, all you need is &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;password_matrix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lowercase_letters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;capital_letters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;special_characters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;wookie_words&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Final code looks like that:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fake_password&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;lowercase_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s1"&gt;'z'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;capital_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s1"&gt;'Z'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;special_characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w{ $ # * }&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;wookie_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Movies&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;StarWars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wookiee_sentence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;password_matrix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&lt;em&gt;&lt;/em&gt;&lt;/span&gt;&lt;span class="n"&gt;lowercase_letters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&lt;/span&gt;&lt;span class="n"&gt;capital_letters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&lt;em&gt;&lt;/em&gt;&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&lt;/span&gt;&lt;span class="n"&gt;special_characters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;wookie_words&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;password_matrix&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  It work a treat!&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxddula3sqr14rxq9r3vi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxddula3sqr14rxq9r3vi.gif" alt="Spread_Operator"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The curse of versatility</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Tue, 25 Jan 2022 07:23:13 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/the-curse-of-versatility-2h39</link>
      <guid>https://dev.to/rafalpiekara/the-curse-of-versatility-2h39</guid>
      <description>&lt;p&gt;Versatility is supposedly a desirable feature that can stand out in the labor market. A programmer who knows many technologies becomes a tasty morsel for recruiters not only because they can send him offers for various positions, but also because his experience may be very necessary in the project. I like to describe myself as a versatile programmer. I have prepared some insights drawn from my own experiences.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to understand versatility?
&lt;/h2&gt;

&lt;p&gt;I understand it not only as knowledge of different languages, frameworks, technologies. Versatility is also the ability to find yourself in various styles of project and team management. It certainly includes experience in various types of business. I consider myself versatile, not only because I know Ruby, React, ReactNative, Flutter, Amazon Web Services, but also because I have worked  on corporate projects, software houses, product companies and ran my own business.&lt;/p&gt;




&lt;h2&gt;
  
  
  Thanks to its versatility:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You are more attractive on the job market&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Often, the specificity of projects requires broader experience in various domains. Additionally, for example, in Ruby, Java and C # programmers find their way very well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will not die&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is easy to adapt, you will not get lost in the labor market, because there will always be a company that needs a commando, what the backend will do, the design will be implemented, and the server is able to configure. Needless to say, such a commando has a good chance of negotiating a slightly higher rate, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You are not closed to one solution to the problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Having some experience and knowledge of different technologies, you can propose several solutions for the same problem and choose the most appropriate one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can eliminate rubbish&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You know what works and what doesn't. You can catch the firing of the tank faster to kill the fly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You never get bored&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can easily change projects, types of tasks. You easily find yourself in the new reality. You enjoy experimenting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DPWD-FvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5dozj2xkn1xybdwarzx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DPWD-FvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5dozj2xkn1xybdwarzx.jpeg" alt="Versatility" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, but it's not quite that easy, is it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Being a comprehensive developer in your company:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;you are stopgap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You do everything that someone else doesn't want to or can't do. You are a budget option to carry out a project, which may not be particularly crucial, but recruiting a dedicated person would take time and burn money, and you are still paid your salary for that time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You are constantly learning new things&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The speed of learning is a feature of versatile people. You learn very quickly. So what? Won't you learn a new thing? Even one you never wanted to touch? You will learn, because you are versatile and have a good understanding of the business and dependencies of this world. You will learn because you like the employer, because you want to do this project and do something else. And so you learn new things over and over again that, in most cases, you'll use it once in your life.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can do what you don't like&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even the most versatile programmer has something that feels good, has his / her golden zone, favorite language, framework, piece of application, but also knows a lot more things that others do not like. It is very possible that you will meet the finale where you keep doing things that nobody likes. For example, you are a full stack with a frontend flair, but still get the smack from query optimization instead of new frontend animations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;they pay little&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I said above that there is a good chance that such a versatile programmer can negotiate a higher salary rate, but ... But it may be that you will be doing a lot of things that others on the team can't or won't do, and your stake won't be much at all deviate from the others on this level. But how? But you are so versatile that you should earn more. Well, your company's payroll policy may think otherwise… Frustration is around the corner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You are not a specialist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You know a lot of different things, but you never really had time to seriously go deep into one technology, into one issue, because you have to keep jumping all the time. There's a good rule of thumb: Know everything about something and something about everything. It's fun to know a lot, but don't forget to specialize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impostor syndrome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The cheat syndrome comes in very easily in such a situation. After all, you know a lot, but in fact you can be bent on any topic, because… well, you lack this specialization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will be the bottleneck&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You handle a lot of different things in a project that no one else can do. At some point it starts to rain. You start to be a bottleneck, because nobody apart from you is able to push work forward. People are starting to ask each other. The questions start to get frustrating, and then it is very possible that ...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Burnout&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dissatisfaction with work in such a situation is the minimum that can await you. Jumping on topics, pressure to be the one, deadlines, questions, fatigue.&lt;/p&gt;

&lt;p&gt;These are just dangers that you may encounter if you consider yourself a comprehensive developer and are viewed as such on the team. I'm not saying it will happen, but it's always a good idea to have warning lights on the back of your head.&lt;/p&gt;

&lt;p&gt;A versatile developer. Experience in various business categories and team structures. Knowledge of many technologies from backend, through devops, fronted and mobile. This profile is perfectly tailored for a startup, especially in the initial phase, where &lt;strong&gt;the entire team consists of multitasking commandos&lt;/strong&gt; trying to bring unique value to the market as soon as possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZnPPi19R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sp9hcwaykv0ipuwt756v.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZnPPi19R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sp9hcwaykv0ipuwt756v.jpeg" alt="Versatility" width="880" height="924"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fullstack developer - versatile programmer.&lt;/strong&gt; We live in a time of technology fission. Maybe fewer and fewer such fullstacks will develop due to the strong separation of layers in backend and frontend applications? Or maybe not, as shown in the world of Javascript with Node and frontend frameworks, where Node teams in most cases do not have a hard division into frontend and backend developers.&lt;/p&gt;

&lt;p&gt;Versatility is a blessing. Versatility is a curse.&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>management</category>
      <category>career</category>
      <category>programming</category>
    </item>
    <item>
      <title>The symbol in Ruby - Explanation</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Mon, 24 Jan 2022 10:06:45 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/the-symbol-in-ruby-explanation-3m14</link>
      <guid>https://dev.to/rafalpiekara/the-symbol-in-ruby-explanation-3m14</guid>
      <description>&lt;p&gt;Everybody knows how to use it, everybody knows where, but why and what is its basis? What is a symbol in Ruby - I explain to myself and everyone who used it unknowingly so far. A few years ago, when I moved from .Net and C # to the Ruby world, I initially had trouble understanding what the symbols really were about. In one of the interviews, I got a question about the difference between a Symbol and a String and couldn't explain it. After total freaking out, I decided to explore the topic and now I am sharing with you the knowledge that I gained once and for all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Symbol?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;an immutable object that is the name of another object&lt;/li&gt;
&lt;li&gt;unique for each name&lt;/li&gt;
&lt;li&gt;not associated with a specific instance of a given name while the program is running&lt;/li&gt;
&lt;li&gt;is a string that cannot be changed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Symbol vs String
&lt;/h2&gt;

&lt;p&gt;In Ruby, everything is an object, symbols and strings are objects, and instances of the Symbol class and the String class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The string is declared using double or single quotation marks.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The symbol is defined by a colon before the literal.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;:symbol&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Symbols can also contain quotation marks and apostrophes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;:"symbol"&lt;/span&gt; &lt;span class="ss"&gt;:'symbol'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that such an entry means Symbol, not String.&lt;/p&gt;

&lt;p&gt;If we use the above notation, the symbol may contain spaces or other special characters. In traditional notation, &lt;em&gt;underscore&lt;/em&gt; is used as the separator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symbols cannot be modified&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Strings can be modified, symbols are not. Symbols do not have &lt;em&gt;bang methods&lt;/em&gt; that change the object that calls them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "STRING"&lt;/span&gt;

&lt;span class="ss"&gt;:symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; :SYMBOL&lt;/span&gt;

&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase!&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "STRING"&lt;/span&gt;

&lt;span class="ss"&gt;:symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase!&lt;/span&gt;
&lt;span class="no"&gt;NoMethodError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="s1"&gt;'upcase!'&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="ss"&gt;:symbol:Symbol&lt;/span&gt;

&lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"string"&lt;/span&gt;
&lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;" sample"&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "string sample"&lt;/span&gt;

&lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:symbol&lt;/span&gt;
&lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;" sample"&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; NoMethodError: unfined method '&amp;lt;&amp;lt;' for :symbol:Symbol&lt;/span&gt;
&lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:sampel&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; NoMethodError: unfined method '&amp;lt;&amp;lt;' for :symbol:Symbol&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The role of symbols and strings
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The symbol&lt;/strong&gt; identifies something important, it is an object for unique identifiers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The string&lt;/strong&gt; is intended for storing words or pieces of text, it is a type dedicated for text data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symbols and strings can be converted to each other&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; :string&lt;/span&gt;

&lt;span class="ss"&gt;:symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "string"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Symbol and memory
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F115v4itbcgf7clkedrqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F115v4itbcgf7clkedrqx.png" alt="The_symbol_in_Ruby"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same string has a different &lt;strong&gt;object_id&lt;/strong&gt; every time, while the same symbol invoked three times returns the same value.&lt;/p&gt;

&lt;p&gt;This is a key feature, plump meat, sweet flesh, a whole lot of symbols in Ruby.&lt;/p&gt;

&lt;p&gt;Each string, although having the same value, is a separate instance, has its own &lt;strong&gt;object_id&lt;/strong&gt; and its own memory location. &lt;strong&gt;The symbol&lt;/strong&gt;, on the other hand, is unique, created only once while the program is running. Every time a symbol with the same value is called, one and the same instance is called.&lt;/p&gt;

&lt;p&gt;This has an impact on code performance. Each such string takes additional memory space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Historical curiosity!&lt;/strong&gt; As of Ruby 2.2.0, Garbage Collector deals with symbols. Previously, the performance issue between String and Symbol was tricky. Namely, the symbols were stored in memory for the entire duration of the program, which in the case of dynamic symbol generation, e.g. from responses from external services in the application running without restart, for a long time led to a memory leak. As of Ruby 2.2.0 there is no need to worry about memory with numerous symbols. In the case of strings, the situation remains unchanged.&lt;/p&gt;

&lt;p&gt;To understand how Garbage Collector deals with symbols, you need to understand the difference between explicitly declared symbols and dynamically created symbols.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicitly Declared Symbols vs Dynamically Created Symbols
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;:symbol&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; deklaracja&lt;/span&gt;
&lt;span class="s2"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; dynamiczna kreacja&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Garbage Collector only cleaned up dynamically created symbols.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepzbybsvzem25u5o67l6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepzbybsvzem25u5o67l6.png" alt="The_symbol_in_Ruby"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Garbage Collector implementation in Ruby 2.2.0 and higher allows defending against the phenomenon called &lt;strong&gt;DoS symbol - denial of service attack symbol.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Dos symbol&lt;/strong&gt; is when the system dynamically creates a lot of symbols, eg by processing the Json response from an API. Memory is leaking.&lt;/p&gt;

&lt;p&gt;Despite the improvement of the Garbage Collector mechanism, creating symbols from the received data will never be completely safe, e.g. when creating a method dynamically from parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:method&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This symbol was dynamically created to trigger the method. When it is further used, after being destroyed by the Garbage Collector, it will no longer be possible to call this method.&lt;/p&gt;

&lt;p&gt;The same String, used several times, will be instantiated and destroyed each time, and &lt;strong&gt;Symbol&lt;/strong&gt;, because it occupies one, permanent place in memory, will use the same instance for the entire duration of the program. It is similar to the case of a &lt;strong&gt;symbol&lt;/strong&gt; created dynamically until it is marked for destruction by the Garbage Collector.&lt;/p&gt;

&lt;h2&gt;
  
  
  The efficiency with equality operators
&lt;/h2&gt;

&lt;p&gt;Memory issues become apparent when comparing Strings and Symbols. Since strings are variable and each string has an &lt;strong&gt;object_id&lt;/strong&gt;, Ruby never really knows what the value of a particular String is, so it has to check character by character. When comparing two Strings, Ruby must check both sequences of characters to see if they have the same values and if they are arranged in the same order. &lt;strong&gt;Comparing object identifiers will produce a skewed result because two identical strings with the same value have different object_id.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Comparing &lt;strong&gt;the Symbols&lt;/strong&gt; is completely different. The symbols do not change. &lt;strong&gt;Two symbols with the same value have the same object_id.&lt;/strong&gt; Due to this immutability, Ruby is sure that &lt;strong&gt;the Symbol has not changed&lt;/strong&gt; over the course of the program, so there is no need to compare character sequences. All you need is a quick comparison of object identifiers. The whole operation happens much faster than with strings.&lt;/p&gt;

&lt;p&gt;Let the numbers speak for themselves…&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="s2"&gt;"string"&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;total&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 0.07&lt;/span&gt;

&lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="ss"&gt;:symbol&lt;/span&gt;
          &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;total&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 0.39999999999999994&lt;/span&gt;

&lt;span class="n"&gt;string_comparison&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                        &lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                            &lt;span class="s2"&gt;"string"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"string"&lt;/span&gt;
                        &lt;span class="k"&gt;end&lt;/span&gt;
                    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;total&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 0.13&lt;/span&gt;

&lt;span class="n"&gt;symbol_comparison&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                        &lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                            &lt;span class="ss"&gt;:symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:symbol&lt;/span&gt;
                        &lt;span class="k"&gt;end&lt;/span&gt;
                    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;total&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 0.4999999999999999&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Storage of Symbols
&lt;/h2&gt;

&lt;p&gt;There is one more performance aspect worth noting. All symbols are stored in memory in one collection.&lt;/p&gt;

&lt;p&gt;We have access to it via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_symbols&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How does this impact the performance? Every time the same String is called, it is instantiated and destroyed after use.&lt;/p&gt;

&lt;p&gt;When calling symbols, it looks like Ruby checks the global collection first, and if it finds the symbol there, returns it immediately. If it does not find it, then it creates a new instance, also placed in the symbol collection, and returns it faster the next time, because it will be available there. &lt;strong&gt;Symbols are efficient to compare, store, and use.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Symbol Simulation
&lt;/h2&gt;

&lt;p&gt;Ruby gives you the ability to simulate the behaviour of a Symbol on a String by calling &lt;code&gt;the freeze&lt;/code&gt; method. This makes string an invariant constant. However, this does not impact the memory. Two frozen strings are still two different instances. A frozen object, like a Symbol, cannot be modified. It is instantiated only once for each individual instance, then it is called for use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Curiosity!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Symbol, fixnum, bignum, float are frozen by default. By using frozen strings as Hash keys, we can get better code performance than with symbols.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to use the Symbols?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  There is no clear definition of when to use Strings and when to use Symbols.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9tjrx1aaan1vlenr4a8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9tjrx1aaan1vlenr4a8.gif" alt="The_symbol_in_Ruby"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most common example of using symbols are Hash keys. &lt;br&gt;
The allowed notation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;old_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:symbol_key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"some value"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;cool_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;symbol_key: &lt;/span&gt;&lt;span class="s2"&gt;"some value"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second example shows the currently adopted &lt;em&gt;new&lt;/em&gt; notation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is it better to use symbols as keys?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because they present unique values that are not static, while strings are the default containers for data. Therefore, &lt;strong&gt;Symbol fits better as an identifier&lt;/strong&gt;. As is the case with Hash keys. If we use a String as a key, Ruby will create a new instance each time it is invoked. In the case of symbols, one and the same object will be used.&lt;/p&gt;

&lt;p&gt;If we have a hash declared with symbols as keys, we cannot access them with strings, the other way around is the same.&lt;/p&gt;

&lt;p&gt;There is an object in Ruby on Rails that allows you to get to values using symbols and strings on a single Hash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HashWithIndifferentAccess&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The object is &lt;strong&gt;HashWithIndifferentAccess&lt;/strong&gt;. Using symbols with this object is much faster than using a regular Hash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; {}&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:symbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 1&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:symbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 1&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'symbol'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; nil&lt;/span&gt;

&lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;HashWithIndifferentAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; {}&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:symbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 1&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:symbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 1&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'symbol'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Symbols are also keywords for method arguments&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;age: &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Symbols are used to define attributes in classes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:age&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Symbols indicate an instance of classes or methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When declaring a class, method or variable, Ruby automatically creates its name in the form of a Symbol, hence the following entries are possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:pop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;my_array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interestingly, if we have a class called &lt;strong&gt;Controller&lt;/strong&gt;, a method of &lt;strong&gt;controller&lt;/strong&gt;, and a variable &lt;strong&gt;controller&lt;/strong&gt;, and although in different contexts this name will refer to different values, this object will be called every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symbols in enum in Ruby on Rails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is an enum object in Ruby on Rails that uses symbols to define acceptable values for a particular field.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is worth remembering?
&lt;/h2&gt;

&lt;p&gt;I have encountered a case of confusing symbols with variables, which is a shameful mistake. &lt;strong&gt;The symbol is not a variable but a name&lt;/strong&gt; or otherwise &lt;strong&gt;named object&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is important to remember that Symbol is a special class in Ruby that is used to define permanent, unique names.&lt;/p&gt;

&lt;p&gt;Variables, on the other hand, are names that refer to objects. At the moment when the object ceases to exist - the variable also ceases to exist.&lt;/p&gt;

&lt;p&gt;Different with the Symbol. It exists even if the object it is named does not exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A symbol is not a variable - you cannot assign it a value.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another interesting thing is that although the Symbol is not a String, it has a string representation which is a constant. If we have a Symbol written with quotation marks, then its string representation will also have spaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;:"it is some symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"it is some symbol"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "it is some symbol"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, symbols with spaces are not commonly used and when there is no other possibility of writing, they are used as a last resort.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few simple rules
&lt;/h2&gt;

&lt;p&gt;Finally, a few more simple rules when using Strings and Symbols, if that was still a problem. Therefore, in addition to the examples above, please note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when we want to display something we should choose String&lt;/li&gt;
&lt;li&gt;if we want to process the name somehow, use modifying methods on it, we know that we use String&lt;/li&gt;
&lt;li&gt;when the name is meant to be a unique identifier, we use Symbol&lt;/li&gt;
&lt;li&gt;when the same name is to be used multiple times, we use Symbol&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Symbols are very noble objects in the Ruby world. Their skilful use gives only advantages, from code readability to performance and memory savings.&lt;/p&gt;

&lt;p&gt;For more details, please refer to &lt;a href="https://ruby-doc.org/core-2.7.1/Symbol.html" rel="noopener noreferrer"&gt;the Symbol class documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7kgmekoouc194amnepqy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7kgmekoouc194amnepqy.gif" alt="The_symbol_in_Ruby"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The protected modifier in Ruby</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Thu, 20 Jan 2022 22:59:34 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/the-protected-modifier-in-ruby-aa</link>
      <guid>https://dev.to/rafalpiekara/the-protected-modifier-in-ruby-aa</guid>
      <description>&lt;p&gt;Recruitment interviews, especially their technical part, usually follow a specific pattern. It is easy to anticipate the questions that may be asked. It is often the case that the developer who asks them is taken out of the project and busy with solving problems on a daily basis and does not have time to prepare some original and surprising questions (unless he is a sadist and likes to bully candidates, but who of us did not recruit and did not have a killer question up his sleeve?), so google for example "Ruby interview questions". The second possibility is that this developer is already on the nth interview, always asking the same questions out of pure routine. He may also ask what he himself was asked about when he was the candidate. I want to present to you and explain an issue that will appear in 90% of a job interview for a Ruby on Rails developer, and &lt;strong&gt;it is about the Protected modifier in Ruby&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the difference between Public, Private, and Protected, which are access modifiers?
&lt;/h2&gt;

&lt;p&gt;Sounds familiar?&lt;/p&gt;

&lt;p&gt;You may encounter these words in other languages. To understand their slightly different meaning in Ruby, let's take a look at how they function in Java, C # and PHP for comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Public&lt;/strong&gt; - access to a method in a given package and in any other package&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private&lt;/strong&gt; - access only within classes and not inheritable&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protected&lt;/strong&gt; - This is almost identical to &lt;em&gt;private&lt;/em&gt;, with one subtle difference, &lt;em&gt;protected&lt;/em&gt; methods can be inherited&lt;/p&gt;

&lt;h2&gt;
  
  
  "C#"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Public&lt;/strong&gt; - access to the method is unlimited from anywhere in the application&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private&lt;/strong&gt; - methods available only within the class or structure in which they are defined&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protected&lt;/strong&gt; - the method is available in the child class only if accessed through the child class&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Public&lt;/strong&gt; - the method is visible from the inside of the class, derived classes and outside the class&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private&lt;/strong&gt; - methods available only from inside the class&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protected&lt;/strong&gt; - the method is visible in all classes that inherit from the base class, including the base class&lt;/p&gt;

&lt;h2&gt;
  
  
  RUBY 💖💋💪
&lt;/h2&gt;

&lt;p&gt;First, to be perfectly clear, these three words: &lt;strong&gt;public&lt;/strong&gt;, &lt;strong&gt;private&lt;/strong&gt;, &lt;strong&gt;protected&lt;/strong&gt;, commonly referred to as &lt;strong&gt;access modifiers&lt;/strong&gt;, are not really keywords, but ... &lt;strong&gt;methods&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Remember that in Ruby, the code which does something is called &lt;strong&gt;method&lt;/strong&gt;, and is defined by the words def and end at the beginning and end of a given batch of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Public in Ruby
&lt;/h2&gt;

&lt;p&gt;It is no different from any other language. In Ruby, all methods not explicitly specified by the other two modifiers are public, except for the class constructor, &lt;strong&gt;the initialize&lt;/strong&gt; method, which is always private.&lt;/p&gt;

&lt;p&gt;Public methods can be invoked by anyone, anywhere, and are therefore not subject to any restrictions. For the method to be public, no keyword is required, it is enough to declare it above the &lt;strong&gt;private&lt;/strong&gt; and &lt;strong&gt;protected&lt;/strong&gt; declarations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interesting fact!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Globally declared public methods outside of all classes are actually private methods of an instance of &lt;strong&gt;Object&lt;/strong&gt;, Ruby's super extra mother class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Private in Ruby
&lt;/h2&gt;

&lt;p&gt;The recipient of a private method is always &lt;strong&gt;self&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They cannot be called for any instance of the class in which they are defined, because they operate only inside that class, which means that they can only be called in the context of a given object.&lt;/p&gt;

&lt;p&gt;They can only be called in other instance methods of the same class and its subclasses. &lt;strong&gt;Private methods in Ruby are inherited&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When using private methods in the body of other methods, remember that we always do it in a function style, that is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;private_method ()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;not&lt;/p&gt;

&lt;p&gt;&lt;code&gt;instance.private_method ()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;&lt;code&gt;self.private_method ()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It also follows that the private methods of another object cannot be accessed, even if that object is of the same class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protected in Ruby
&lt;/h2&gt;

&lt;p&gt;Access to &lt;strong&gt;protected&lt;/strong&gt; methods is restricted to the family only, but, compared to other languages, they can be invoked by objects of the same class but inside those objects.&lt;/p&gt;

&lt;p&gt;They can always be called on behalf of any instance of a class or a subclass of it, so unlike private, they are not limited to only implicit calls on behalf of self.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protected&lt;/strong&gt; is used to operate on the internal state of other objects of the same class.&lt;/p&gt;

&lt;p&gt;It is an access method that allows an instance of a given class to share the internal state, but at the same time prevents consumers of that class from accessing this state from the outside.&lt;/p&gt;

&lt;p&gt;To quote &lt;strong&gt;Matz, the creator of Ruby&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;,,A protected method defined in class C can be called on behalf of an O object by a method in P if classes O and P are subclasses of class C or are equal to it.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here are some examples to better understand the &lt;strong&gt;Protected&lt;/strong&gt; modifier in Ruby.&lt;/p&gt;

&lt;p&gt;We have &lt;strong&gt;the Employee&lt;/strong&gt; class and two employees who symbolize its instances. Suppose a scenario where the boss wants to compare their salaries without exposing them to the outside world.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:salary&lt;/span&gt;
  &lt;span class="kp"&gt;protected&lt;/span&gt; &lt;span class="ss"&gt;:salary&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greater_salary_than&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other_employee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@salary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;other_employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;salary&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;first_employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;second_employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;first_employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grater_salary_than&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;second_employee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;older_than?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other_person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;other_person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;protected&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;age&lt;/span&gt;&lt;span class="vi"&gt;@age&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can clearly see what I wrote about above. &lt;strong&gt;A protected method is not available outside the context of a given object, but is available inside the context of another object, if and only if the object is of the same type.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffspbvqot6fvyrykdmg2l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffspbvqot6fvyrykdmg2l.gif" alt="The_protected_modifier"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional information about Protected in Ruby and other modifiers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;protected method can be called in the context of the given object as &lt;code&gt;method ()&lt;/code&gt; or &lt;code&gt;self.method ()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Access modifiers can be declared in two ways:&lt;/li&gt;
&lt;li&gt;all methods after the word private will be private unless we use protected somewhere along the way. Similarly, all methods after this declaration will be protected, unless we use the private modifier somewhere along the way&lt;/li&gt;
&lt;li&gt;the second way is to first declare all the methods and then establish their access by listing their names in conjunction with the appropriate access modifier
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# I way&lt;/span&gt;
&lt;span class="kp"&gt;private&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method&lt;/span&gt;

&lt;span class="kp"&gt;protected&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method&lt;/span&gt; 

&lt;span class="c1"&gt;# II way&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kp"&gt;protected&lt;/span&gt; &lt;span class="ss"&gt;:method&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;calling &lt;code&gt;respond_to?&lt;/code&gt; for a protected method it will return &lt;code&gt;false&lt;/code&gt;. For clarification, &lt;code&gt;respond_to?&lt;/code&gt; is a method that returns &lt;code&gt;true&lt;/code&gt; if the object implements the method given as an argument. By default, it does not include private methods. They can be considered by passing the second argument to this method as &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;let's go back to private methods for a moment. Although I wrote that we do not have access to them, there is one exception here. A trick known only to those who don't speak Rabi. Namely, you can get to them by calling the private method with the &lt;code&gt;send&lt;/code&gt; method or by evaluating the block in the context of the object using the &lt;code&gt;instance_eval&lt;/code&gt; method
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt; &lt;span class="ss"&gt;:some_private_method&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_private_method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a topic for another lecture, treat it as a Swiss curiosity, don't try it at home.&lt;/p&gt;

&lt;p&gt;BTW, there is also a &lt;code&gt;public_send&lt;/code&gt; method which works like &lt;code&gt;send&lt;/code&gt;, except that private methods are omitted. It's easy to get confused.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Definition Spec in Ruby - implementation in RSpec</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Mon, 17 Jan 2022 05:34:24 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/definition-spec-in-ruby-implementation-in-rspec-3pi8</link>
      <guid>https://dev.to/rafalpiekara/definition-spec-in-ruby-implementation-in-rspec-3pi8</guid>
      <description>&lt;p&gt;Imagine this situation. Ruby on Rails project. You are working with your team on a mega-important business feature. You did three days. Everything flashes great. You give it back. Goes into production. Management opens Prosecco, Marketing starts ad words. Complete success 🎉🎉🎉🔥💪.&lt;/p&gt;




&lt;p&gt;Meanwhile, an hour after the key release, a colleague from the other team deploys a feature he has been working on for 3 weeks. The feature might have waited another day if it had waited so long. Well, it's going to be in production, because QA was busy testing my key feature, and it's not a business change, some dashboard views and queries, nothing can be spoiled. It will fly straight into production. Pipelines turn green, but ... the application is lying, Puma does not get up. Fuckup. Clients call, support in panic, Prosecco is gasping.&lt;/p&gt;

&lt;p&gt;It turns out that by some miracle a code entered the production, in which in one of the classes, at the very end, a small, stray, almost imperceptible letter "s" appeared. Probably a colleague was saving the file, he missed a finger and the letter was written. Nobody noticed during the code review, there was no time to enter the QA, tested in local, but the application crashed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bMYwKJHT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k352hu2x1to4eay8e2p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bMYwKJHT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k352hu2x1to4eay8e2p8.png" alt="DefinitionSpec" width="650" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sounds weird? Well, no, it's a case study from a project my friend is working on. &lt;strong&gt;A real, authentic fact that really happened.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Wait, but how everything worked locally, how pipelines went through since there was a character in the code that should never be there.&lt;/p&gt;

&lt;p&gt;Three issues are to blame for this incident:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;specificity of interpreted languages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;specificity of Ruby on Rails&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;lack of adequate, minimum test coverage in the project&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The specificity of interpreted languages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The difference between interpreted languages and compiled languages is that in interpreted languages, the code is executed on the fly, there is no build phase to allow the compiler to check that the project is at all building. Hence, any typos, syntax errors, and undeclared methods will only come to light when the dirty code fragment is executed. Nobody will warn us sooner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MHdP2okH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgefydim35upkmg9rp1r.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MHdP2okH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgefydim35upkmg9rp1r.jpeg" alt="DefinitionSpec" width="880" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The specificity of Ruby on Rails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RoR has a lazy loading mechanism in development and test modes. This means that it only loads the classes that are needed to execute the given batch of code. Only in production mode, the entire application code is loaded. As a result, unless there is a bug in the key RoR files responsible for initializing the application, Puma will always stand up in the development environment, and the tests, as long as they do not touch contaminated code, will always pass. The application will not get up on production. Puma won't get up if there is a syntax error in the code, or if a method that is not declared is executing.&lt;/p&gt;

&lt;h2&gt;
  
  
  No minimum test coverage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It just so happened that the flawed class in this example did not have any tests written.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PgIPrUNC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elov82lygcpnjb2vem5y.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PgIPrUNC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elov82lygcpnjb2vem5y.gif" alt="DefinitionSpec" width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other tests did not touch this class, so it gave the impression that nothing was broken and that there is backward compatibility. Tests passed locally, passed in pipelines, and yet it was faulty.&lt;/p&gt;

&lt;p&gt;Apparently, every programmer and every programmer worked on at least one project, in which they heard one of three variations: "We do not write tests because"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"... the client does not pay for writing tests"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"... there's no time, deadlines are chasing."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"... it's a simple feature, what to test here."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Who has never had such a fuckup, be the first to throw a stone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of my favourite thoughts at work is "Know how is important but the most important is to know how not."&lt;/p&gt;

&lt;p&gt;Well, now both me and my friend and his bandmates, and you know "how not". It is time to formulate a short Know How.&lt;/p&gt;

&lt;p&gt;If you don't write tests because there is some super important business reason (yes, super important one), it's always worth writing one test that saves your butt in cases like the one above.&lt;/p&gt;

&lt;h2&gt;
  
  
  I call it the definition spec.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;MailingService&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'is defined'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It consists in the fact that the first test that I write when creating a new class is checking whether such a class is defined at all, which forces it to be loaded in test mode. These are 4 lines, and they really allow you to ensure a minimum of security and avoid typos. &lt;strong&gt;The definition spec in Ruby&lt;/strong&gt; seems to be a tool tailored to this problem.&lt;/p&gt;

&lt;p&gt;Look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OR8cV8qH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zirvxqi57zv3lus5yoq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OR8cV8qH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zirvxqi57zv3lus5yoq.png" alt="DefinitionSpec" width="502" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not much, but when he sees the green colour, I become calmer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uFpIR7Dy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3s8xdcq3uz35dxcjpk6w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uFpIR7Dy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3s8xdcq3uz35dxcjpk6w.gif" alt="DefinitionSpec" width="480" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created a module to avoid typing the same code every time. You can also use your own matcher. Here are some examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Own module:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/support/test_helpers.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;TestHelpers&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;definition_spec&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# w rails_helper.rb&lt;/span&gt;
&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TestHelpers&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#Potem w teście&lt;/span&gt;
&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;PaymentService&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'is defined'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;definition_spec&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;SomeClass&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'is defined'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;definition_spec&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test result for red:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BPx_54_A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/js9ee7f3710tv2w974sg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BPx_54_A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/js9ee7f3710tv2w974sg.png" alt="DefinitionSpec" width="880" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test result for green:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B9WKglfo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4yybdrqktdnjihcr84u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B9WKglfo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4yybdrqktdnjihcr84u.png" alt="DefinitionSpec" width="548" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Defining your own matcher&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#spec/support/matchers.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rspec/expectations'&lt;/span&gt;

&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Matchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="ss"&gt;:be_defined&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Potem w teście&lt;/span&gt;
&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;PaymentService&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_defined&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;SomeClass&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_defined&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test result for red:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kw5Dh6FU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hv3ljh58p5pa0hx1dfcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kw5Dh6FU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hv3ljh58p5pa0hx1dfcl.png" alt="DefinitionSpec" width="549" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test result for green:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V-_SVf20--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kyyeixnhqm7ovf8vpz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V-_SVf20--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kyyeixnhqm7ovf8vpz5.png" alt="DefinitionSpec" width="525" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the case of TDD, I guarantee a dopamine incentive. You are writing a definition spec. it's red. You add the file and define the class. It’s Green. And you want to keep working 😃&lt;/p&gt;

&lt;p&gt;If you want and have time for it, you can test if the public methods you want to use are defined. No mocking, no extensive scenarios. Minimal coverage that protects against trivial fuckups&lt;/p&gt;

&lt;p&gt;Just as startups have the concept of MPV - Minimum Viable Product, I suggest you MVC, but understood as Minimally Verified Class. Something like this can help you introduce a &lt;strong&gt;Ruby definition spec&lt;/strong&gt; into your routine.&lt;/p&gt;

&lt;p&gt;Someone wise from the Ruby world (&lt;a href="https://www.instagram.com/andrzejkrzywda_po_polsku/"&gt;Andrzej Krzywda&lt;/a&gt; - you can find a broader context &lt;a href="https://devstyle.pl/2016/03/07/4-sposoby-na-to-zeby-biznes-cie-pokochal-post-goscinny/"&gt;here&lt;/a&gt;) said that he works in Ruby because he likes to correct typos in production.&lt;/p&gt;

&lt;p&gt;Let's not fix typos in production, let's do it earlier, much earlier.&lt;/p&gt;

&lt;p&gt;When adding a definition spec, the tests crash if there is an unwanted letter in the class being tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write definition spec in Ruby, seriously
&lt;/h2&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>testing</category>
      <category>programming</category>
    </item>
    <item>
      <title>Dunning-Kruger developer</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Fri, 14 Jan 2022 15:08:16 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/dunning-kruger-developer-5504</link>
      <guid>https://dev.to/rafalpiekara/dunning-kruger-developer-5504</guid>
      <description>&lt;p&gt;I suppose you are familiar with this feeling when, after completing one course or training, you have the impression that you have complete knowledge, expert knowledge. Be careful! You may have just been caught by Mr. Dunning and Mrs. Kruger. Simply put, the Dunning-Kruger effect is that when you know little you feel as if you know everything.&lt;/p&gt;

&lt;p&gt;It is easy to fall under the illusion that 2 weeks may be enough to master a programming language well. Stuffing yourself with a large dose of knowledge puts you in a state of omnipotence. You have the feeling that there is no problem that cannot be solved, that you can compete in senior positions today.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Theory&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A little theory about &lt;a href="https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect" rel="noopener noreferrer"&gt;the Dunning-Kruger effect&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Symptoms&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Being in such a state becomes full of boldness and pride. It seems that there is no such recruitment question that you do not know the answer to. Unfortunately, this is only an illusion, so characteristic at the beginning of learning any thing. It is then easy for a total flop, an absolute failure, because there will always be someone at the recruitment interview who will be better than you. Who will crush you and drag you across the floor, so that you will be left for a long time to make any changes or apply for a new project.&lt;/p&gt;

&lt;p&gt;This is how the Dunning-Kruger effect works. It throws us from the extreme to the extreme. The worst part about it is the lack of awareness of this state. Not understanding that you are only at the beginning of the road, that the more you know, the more you know, that you don't know, right?&lt;/p&gt;

&lt;p&gt;That is why it is worth remembering at every step that there will always be someone who will crush us, be it in the company, during recruitment or even at a conference. Even if you have the feeling that your code is already awesome, it's "there is always a bigger fish".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8wblu6x6uhwhmnepuv2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8wblu6x6uhwhmnepuv2.jpeg" alt="Dunink-Kruger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How might the person with Dunning-Kruger affect colleagues? Absolutely destructive. Such a person breaks up the team. It's hard to work with someone who believes they have all the available knowledge. And if there is someone in the team who will not give up and will always try to demonstrate wrong thinking - a toxic atmosphere is guaranteed.&lt;/p&gt;

&lt;p&gt;The path of self-reflection is priceless, remember that others can evaluate you. If you are blindly convinced of your own coolness, such an evaluation can be very painful. Nobody will take you seriously, because your shortcomings will be clearly visible on the palm of your hand.&lt;/p&gt;

&lt;p&gt;Rewriting the course doesn't make you an expert. The only thing you can get out of it is a very narrow view of the problems or technology discussed by the author. I mentioned the limits of knowledge above. Let me explain this a little more. There is such a thing as the circle of knowledge and the limits of ignorance. &lt;/p&gt;

&lt;p&gt;Imagine a small circle one centimeter in diameter. Can you calculate the circumference of this circle? You surely remember the pattern. And the field of the circle? Sure. So the area of the circle is the boundary of your knowledge, its length is the amount of knowledge that you currently believe you lack. You start learning, you do courses, bootcamps, training. Your circle of knowledge begins to grow, but with the circle, the circumference begins to increase with the circle. The boundaries of your ignorance are becoming more and more extensive. &lt;/p&gt;

&lt;p&gt;As you learn new content, you start to see new areas for exploration. The more you know, the more you don't know.&lt;/p&gt;

&lt;p&gt;What if I told you that there is no limit point, that this wheel can grow forever? Does it scare you? Frightens? And it shouldn't! The only feeling that should accompany you is humility, such simple, simple humility, humility in front of the fact that in a world filled with information, on the threshold of such a dynamically changing and developing IT industry, so many things remain to be known, while we still know little. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Are you a course addict?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The Dunning-Kurger Effect often affects course addicts. There is &lt;strong&gt;this development addiction phenomenon&lt;/strong&gt;. We buy course after course, book after book, preferably from several different fields. Courses, such as courses, either give a very general overview of an issue and in fact, we only learn the basics, or they touch on a very narrow specialist section of the issue. In both scenarios, just completing the course, completing training, reading a book does not make us experts. And yet it is easy to get the feeling that after this specific course we can deal with any project, any problem that comes up before us. &lt;strong&gt;Expertise is determined by the experience&lt;/strong&gt;, number and weight of solved problems, experienced crises and victories. An expert does not need to have a certificate and a litany of training sessions listed on their Linkedin profile. An expert must have poured liters of sweat, blood and tears behind him. &lt;strong&gt;Expertise is like a precious metal, it is forged under extreme conditions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I have conducted trainings for people who want to change into programmers. In the middle of the course, which lasted 12 weeks, the students asked me questions about their financial requirements during recruitment interviews, because they would like to look for a job. 6 weeks after starting the programming course, completely from scratch. &lt;strong&gt;Then I was shocked! Today I understand it more!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I was shocked because I was entering the industry even before being a programmer became fashionable. There were no bootcamps and all these programming schools. There were no such developed frameworks. Programming wasn't as sexy as it is now. There was no React, Vue etc, it was revolutionary to use jQuery instead of Vanilla. My learning was difficult, access to the materials was more difficult. For this reason, it is easier today to see similar differences in perceiving knowledge and falling into a state of overconfidence and enthusiasm. I have nothing to do with this type of bootcamp or training, I would probably use it myself, if it was possible. However, when deciding on such training, &lt;strong&gt;you must have a certain mindset&lt;/strong&gt;, certain assumptions that &lt;strong&gt;you will be bombarded with knowledge&lt;/strong&gt;, if the course is actually as intense as promised in the advertisements and worth its considerable price, you will be overwhelmed by a mass of material that will not be able to effectively convert .&lt;/p&gt;

&lt;p&gt;You will end the training with confidence, because you have covered a lot of issues during the course, but in fact none of them were remembered well enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first interview is enough to get a verbal splash of cold water&lt;/strong&gt; that will either sober up or nail down. May he sober up.&lt;/p&gt;

&lt;p&gt;As we are already recruiting. You probably know from stories or anecdotes that sometimes stupid questions are asked during job interviews. I thought it was just a joke, that it couldn't be true, because what kind of company asks a programmer what kind of animal he feels or what he would take to a desert island. And not so long ago, when I changed my job, a very nice recruiter asked me what kind of fruit I am. Get it? What the fucking fruit I am. How important in this process was it that I replied "with a banana"? How important was it that this was the first fruit that came to my mind? These kinds of questions are of no use, and neither are theoretical questions of technology. Okay, they're important because we're able to get to know a candidate's body of knowledge, but that body of knowledge might as well have been learned, and mostly misunderstood. It doesn't really matter if you know the design patterns from theory. It is important if you know the problems that can be solved by applying them. Hence, I am a supporter of questions related to experience, challenges, successes, failures and problems. Perhaps it is worth the effort to inquire about the cache, performance, and understanding legacy problems you encounter. Questions presenting a real design problem are fantastic, for example:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"You have a task that must be delivered on Wednesday at 12:00. It's Tuesday 15:00. What will you do? You prefer to deliver what you can on Wednesday, but knowing that it will be incomplete, or will you give information to the client / team, that there is no chance that it will be on Wednesday and that you will miss the deadline, but you will deliver all the requirements? "&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A classic problem, is it better to be on time and fail, or is it better to be late and deliver everything.&lt;/p&gt;

&lt;p&gt;These types of questions will quickly expose the Dunning-Kruger delinquent, as it will turn out that superficial knowledge is not enough to make up for inexperience.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Let's summarize&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The Dunning-Kruger effect, that's okay. I experienced it, probably your friends experienced it. If this has not happened to you yet, sooner or later you will feel &lt;strong&gt;this feeling of world domination&lt;/strong&gt;, while what you have is not even suitable for ruling over a glass of water. Humility is such a grandiose word, and it can change so much. It is humility that will give you the opportunity to deal with the effect as soon as possible. Humility doesn't mean feeling like shit here, but it does mean knowing there's always something I may not know and it's easy to get hit for it. There can always be someone to put you out of the way and show you your place in the row.&lt;/p&gt;

&lt;p&gt;Let Master Qui-Gon Jin remind you of all this:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;There’s always a bigger fish&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcen85thg9fh6ug6cjeof.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcen85thg9fh6ug6cjeof.jpeg" alt="Dunning-Kruger"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>career</category>
      <category>management</category>
    </item>
    <item>
      <title>Simple Command</title>
      <dc:creator>Rafał Piekara</dc:creator>
      <pubDate>Fri, 14 Jan 2022 14:44:45 +0000</pubDate>
      <link>https://dev.to/rafalpiekara/simple-command-35g0</link>
      <guid>https://dev.to/rafalpiekara/simple-command-35g0</guid>
      <description>&lt;p&gt;Who ever worked in a rails project must have seen the so-called fat controllers, where the logic of individual actions is packed directly into controllers that automatically have hundreds of private methods and thousands of lines of code, and the actions look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;
    &lt;span class="vi"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_template_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;page_levels_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;page_levels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;saved_levels_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page_levels_ids&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                          &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page_levels_ids&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="k"&gt;else&lt;/span&gt;
                          &lt;span class="p"&gt;[]&lt;/span&gt;
                        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;ids_to_save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saved_levels_ids&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;page_levels_ids&lt;/span&gt;
    &lt;span class="n"&gt;ids_to_remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page_levels_ids&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;saved_levels_ids&lt;/span&gt;
    &lt;span class="n"&gt;ids_to_remove&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;PageLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;page_template_id: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;ids_to_save&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;PageLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;page_template_id: &lt;/span&gt;&lt;span class="vi"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="vi"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;
    &lt;span class="no"&gt;PageProcessor&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TemplateService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;edit_page_template_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have such good practice that I transfer all logic from controllers to external domain classes of services, commands, use cases - whatever you call it. When testing such controllers, I only care about the shape of the responses that return individual actions and whether the appropriate website was called with the appropriate parameters. That's all.&lt;/p&gt;

&lt;p&gt;To use such a solution, &lt;strong&gt;PORO&lt;/strong&gt; (Plain Old Ruby Object) is enough, while I like to use a small, nice library called Simple Command, which extends our PORO with a few things that improve the convenience and testing of such classes.&lt;/p&gt;

&lt;p&gt;Link to &lt;a href="https://github.com/nebulab/simple_command"&gt;library&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;From the documentation of the gem, we can read that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
to use &lt;code&gt;SimpleCommand&lt;/code&gt; in your class you should (here I have a bit of a problem with the proper translation of it into Polish), precede it with the &lt;code&gt;SimpleCommand&lt;/code&gt; class
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;prepend&lt;/span&gt; &lt;span class="no"&gt;SimpleCommand&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to know what &lt;code&gt;prepend&lt;/code&gt; is all about, check here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;we will be able to call our class through the &lt;code&gt;.call&lt;/code&gt; method defined in it&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;our class will have two attributes that indicate the success of the operation: &lt;code&gt;success?&lt;/code&gt; and &lt;code&gt;failure?&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if the operation is successful, the value returned by the &lt;code&gt;call&lt;/code&gt; method will be available under the &lt;code&gt;result&lt;/code&gt; attribute&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if the operation fails, the errors from this operation can be read from the &lt;code&gt;errors&lt;/code&gt; attribute&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Testing such a class is very simple. We really only test 3 cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;if the call will be successful if the correct parameters are given&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if we get an error when entering incorrect parameters&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;whether the command will return the expected result on a positive end of the operation&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, we can dive in and see if there are any operations on other classes inside the command, or if array &lt;code&gt;errors&lt;/code&gt; contain information about specific errors, or if the command throws exceptions suitable for our test cases. However, these three points above are enough to feel comfortable with the implementation of the logic contained in the command.&lt;/p&gt;

&lt;p&gt;Now let's move on to the specific case of user login to the API. The code that I prepared is &lt;strong&gt;the agnostic framework&lt;/strong&gt;, it shows that &lt;strong&gt;SimpleCommand&lt;/strong&gt; and &lt;strong&gt;the command pattern&lt;/strong&gt; it supports can also be used outside of Ruby on Rails, in scripts, console applications, automations, etc.&lt;/p&gt;

&lt;p&gt;Classic example according to &lt;strong&gt;rails way&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'./auth_token'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BadAuthController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero?&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="s1"&gt;'Email not valid'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;422&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;auth_token: &lt;/span&gt;&lt;span class="no"&gt;AuthToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :ok&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="s1"&gt;'User not found'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="s1"&gt;'Invalid password'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;user&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;auth_params&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:auth&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;login&lt;/code&gt; method is quite long. There are some ifs, some complex conditions, some renders. What if we add, for example, 2 Factor Authentication to the application? This logic will have to be tied down somewhere between the ifs. Distributing this code to private methods won't quite work. What if another action uses the same method and in the meantime, we modify the method to meet the new requirements?&lt;/p&gt;

&lt;p&gt;Let's move all the logic to the &lt;code&gt;LoginUser&lt;/code&gt; command. For the purposes of the example, the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;AuthToken&lt;/code&gt; classes are plugs, we are not interested in their implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'simple_command'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'./user'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'./auth_token'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginUser&lt;/span&gt;
  &lt;span class="n"&gt;prepend&lt;/span&gt; &lt;span class="no"&gt;SimpleCommand&lt;/span&gt;

  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvalidEmail&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvalidPassword&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserNotFound&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="vi"&gt;@email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="vi"&gt;@password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;InvalidEmail&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;email_valid?&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;UserNotFound&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;InvalidPassword&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;user_authenticated?&lt;/span&gt;
    &lt;span class="n"&gt;logged_user_payload&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;InvalidEmail&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Invalid email given'&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;InvalidPassword&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Invalid password'&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;UserNotFound&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'User not found'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;logged_user_payload&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;auth_token: &lt;/span&gt;&lt;span class="n"&gt;auth_token&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;user_authenticated?&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;user&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;email_valid?&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;auth_token&lt;/span&gt;
    &lt;span class="no"&gt;AuthToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do we have here? The command accepts the parameters needed to log in. As logic is enforced, it throws its own exceptions, catches those exceptions, and sets error codes and error responses accordingly. There are a few private methods dedicated to make the code clearer.&lt;/p&gt;

&lt;p&gt;Now let's see a test of such a command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'../lib/login_user'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'spec_helper'&lt;/span&gt;

&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;LoginUser&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'is defined'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'logging'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s1"&gt;'email@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'succeeds'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_success&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'logs in user'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_key&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_key&lt;/span&gt; &lt;span class="ss"&gt;:auth_token&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'when no email given'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'fails'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_failure&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'raises error'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="s1"&gt;'Invalid email given'&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'when no password given'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s1"&gt;'email@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'fails'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_failure&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'raises error'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="s1"&gt;'Invalid password'&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'when user not found'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:find_by&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'fails'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_failure&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'raises error'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="s1"&gt;'User not found'&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'when invalid password'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;allow_any_instance_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:authenticate&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'fails'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_failure&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'raises error'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="s1"&gt;'Invalid password'&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests are very simple. We check &lt;strong&gt;the happy path&lt;/strong&gt; first, then check how the command behaves in the event of invalid credentials. Only this and so much.&lt;/p&gt;

&lt;p&gt;And this is how invoking the command in the controller and testing for the login action will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'./command_helpers'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthController&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;CommandHelpers&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;
    &lt;span class="n"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;LoginUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;422&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;auth_params&lt;/span&gt;
    &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:auth&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'spec_helper'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'../lib/auth_controller'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'../lib/login_user'&lt;/span&gt;

&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;AuthController&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'is defined'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s1"&gt;'email@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:login&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;instance_double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;LoginUser&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;LoginUser&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:success?&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anything&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'logs user via command'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;LoginUser&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'checks for command status'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:success?&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'gets command result'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'returns command result'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:data&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'when login failed'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:success?&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:failure?&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anything&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'checks for failure'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:failure?&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'checks for errors'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'returns command errors'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:errors&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple scenario. At the controller level, we only check the correct execution of the command with the appropriate parameters. And the responsibility for the logic test and its correctness is delegated to another layer.&lt;/p&gt;

&lt;p&gt;Well, what now? The moment we have more of these actions that use commands, we will have a good idea. We can grasp it through auxiliary methods. For the sake of example, I have thrown them into the included &lt;strong&gt;CommandHelpers&lt;/strong&gt; module. The command is caught by handle, and it is already responsible for handling its responses or errors properly. This handler is always more expandable and customizable. However, I present to you the minimum version of the implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;CommandHelpers&lt;/span&gt;

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

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;command_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;command_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then something like this is enough in the controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_with_handler&lt;/span&gt;
  &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="no"&gt;LoginUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it. 😃&lt;/p&gt;

&lt;p&gt;As a result, we have the encapsulation of logic in a pleasant class that additionally contains information about the success or interruption of the action as well as clean and transparent controllers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attention!&lt;/strong&gt; In the &lt;strong&gt;SimpleCommand&lt;/strong&gt; repository on Github, you may notice that there have been no new commits there for several years. The library appears to be unmaintained, so you may be concerned about using it. &lt;strong&gt;Do not worry&lt;/strong&gt;. Just look at the gem code and see that the entire &lt;strong&gt;SimpleCommand&lt;/strong&gt; is really pure &lt;strong&gt;PORO&lt;/strong&gt; without any dependencies. Equally, instead of installing the gem, we can include this code in some helper class in a rails application.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>architecture</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
