<?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: Tom de Bruijn</title>
    <description>The latest articles on DEV Community by Tom de Bruijn (@tombruijn).</description>
    <link>https://dev.to/tombruijn</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%2F32721%2F9e8b0cec-cc31-4355-a867-a97b29173e2a.jpg</url>
      <title>DEV Community: Tom de Bruijn</title>
      <link>https://dev.to/tombruijn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tombruijn"/>
    <language>en</language>
    <item>
      <title>Expand Your Monitoring Capabilities with AppSignal's Standalone Agent Docker Image</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Tue, 04 Jul 2023 11:44:14 +0000</pubDate>
      <link>https://dev.to/appsignal/expand-your-monitoring-capabilities-with-appsignals-standalone-agent-docker-image-4alb</link>
      <guid>https://dev.to/appsignal/expand-your-monitoring-capabilities-with-appsignals-standalone-agent-docker-image-4alb</guid>
      <description>&lt;p&gt;Want to monitor all of your application's services? Our Standalone Agent allows you to monitor processes our standard integrations don't monitor by default, helping you effortlessly expand your monitoring capabilities.&lt;/p&gt;

&lt;p&gt;To help simplify the process of configuring our standalone agent, we're excited to announce the launch of our Standalone Agent's Docker image, available on Docker Hub under the name &lt;a href="https://hub.docker.com/r/appsignal/agent"&gt;appsignal/agent&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the AppSignal Standalone Agent?
&lt;/h2&gt;

&lt;p&gt;Based on the same software that powers our Ruby, Elixir, and JavaScript integrations, the standalone agent can be used to monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure:&lt;/strong&gt; machines that are part of our system but do not run application code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background jobs:&lt;/strong&gt; Think intensive cron jobs or long-running data-processing scripts. You can use the standard integration if these background jobs are written in a supported language (Ruby, Elixir, or Node.js).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More languages:&lt;/strong&gt; Programs written in languages other than those supported by an AppSignal integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, with the standalone agent, you can track a machine learning model written in Java, instrument backup scripts, or monitor Kafka brokers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitor Traces, Custom Metrics, and More
&lt;/h2&gt;

&lt;p&gt;The AppSignal standalone agent is a powerful addition to monitoring your applications. With the standalone agent Docker image, you can report OpenTelemetry traces, StatsD metrics, and NGINX metrics to a single endpoint within your internal network.&lt;/p&gt;

&lt;p&gt;You can view all this information on AppSignal alongside your application's core metrics, giving you a bird's eye view of the performance of your application and its services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tmONpAZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-06/statsd-metrics.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tmONpAZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-06/statsd-metrics.png" alt="StatsD Metrics" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with AppSignal's Docker Image
&lt;/h2&gt;

&lt;p&gt;Previously, running the AppSignal standalone agent required running it as another process on a Docker container for your application or infrastructure like NGINX. However, with our new docker image, you can run the AppSignal standalone agent in an isolated container, making it easier to manage and more efficient to use.&lt;/p&gt;

&lt;p&gt;Ready to get started? You can find more information on how to install and configure the AppSignal standalone docker image in our &lt;a href="https://docs.appsignal.com/standalone-agent/installation/docker-image.html"&gt;installation&lt;/a&gt; and &lt;a href="https://docs.appsignal.com/standalone-agent/configuration/options.html"&gt;configuration&lt;/a&gt; documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  AppSignal, The Developer Driven APM
&lt;/h2&gt;

&lt;p&gt;AppSignal's standalone agent is just one of our many developer-driven tools designed to help you to monitor your application. Developers also enjoy using our monitoring because we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An intuitive interface that is easy to navigate.&lt;/li&gt;
&lt;li&gt;Simple and predictable pricing.&lt;/li&gt;
&lt;li&gt;Developer-to-developer support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're new to AppSignal, remember to &lt;a href="mailto:support@appsignal.com"&gt;ask us&lt;/a&gt; for some free stroopwafels! They taste almost as good as it feels to have all of your application's metrics at your fingertips 😉🍪&lt;/p&gt;

</description>
      <category>docker</category>
      <category>elixir</category>
      <category>ruby</category>
      <category>node</category>
    </item>
    <item>
      <title>Write your own Domain Specific Language in Ruby</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Mon, 06 Feb 2023 12:36:00 +0000</pubDate>
      <link>https://dev.to/tombruijn/write-your-own-domain-specific-language-in-ruby-15ki</link>
      <guid>https://dev.to/tombruijn/write-your-own-domain-specific-language-in-ruby-15ki</guid>
      <description>&lt;p&gt;Let's do some metaprogramming in Ruby! This article assumes you have some familiarity with writing Ruby and are interested in learning how to use metaprogramming.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is also available as a &lt;a href="https://tomdebruijn.com/talks/ruby-write-your-own-domain-specific-language/"&gt;video recording of a talk&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's a DSL?
&lt;/h2&gt;

&lt;p&gt;Let's start with some definitions on what we're going to be looking at. The abbreviation &lt;em&gt;DSL&lt;/em&gt; stands for &lt;em&gt;Domain Specific Language&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A DSL is a sub-language within a Ruby app (or any other programming language) that is specific to a certain domain: like a Ruby gem or part of an app. Without that gem or app, the DSL won't work. It's specific to that domain.&lt;/p&gt;

&lt;p&gt;In Ruby there's a gem named &lt;a href="https://rubygems.org/gems/rake"&gt;Rake&lt;/a&gt;. This gem provides a DSL to create tasks to be run from the command line. A small example 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="c1"&gt;# Rakefile&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:hello&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Hello there"&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 call this task from the terminal with the following command. When called, it will perform the block we've given to the &lt;code&gt;task&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rake hello
Hello there
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the power of a DSL. We don't need to know how to listen to arguments given to Ruby from the command line. Rake does this for us. We only need to define the commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use a DSL?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;One of the most common reasons to create your own DSL is for configuration, for an app or part of a gem. In Rails, the &lt;code&gt;Application&lt;/code&gt; class contains configuration for the different gems that make up Rails. It's even possible to define your own &lt;a href="https://guides.rubyonrails.org/configuring.html#custom-configuration"&gt;custom config options&lt;/a&gt; specific to your app.&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;# config/application.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyApp&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&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;load_defaults&lt;/span&gt; &lt;span class="mf"&gt;7.0&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;time_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"UTC"&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;custom_option&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"some value"&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;Within the Application class, the &lt;code&gt;config&lt;/code&gt; object can be used to set config options or load defaults, like shown above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automate writing code
&lt;/h3&gt;

&lt;p&gt;A DSL can be used to abstract away a bunch of repetitive code. In a Rails app there can be many different HTTP endpoints the app listens to. To write a Ruby app that listens to these endpoints can require a lot of code. In Rails, we can declare several different routes with one method: &lt;code&gt;resources&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;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:posts&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:comments&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="s2"&gt;"homepage#show"&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;resources&lt;/code&gt; method will do several things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create several endpoints like &lt;code&gt;GET /posts&lt;/code&gt;, &lt;code&gt;GET /posts/new&lt;/code&gt;, &lt;code&gt;POST /posts&lt;/code&gt;, &lt;code&gt;DELETE /posts&lt;/code&gt;, etc.;&lt;/li&gt;
&lt;li&gt;nest endpoints, if they are nested within another &lt;code&gt;resources&lt;/code&gt; method call's block, like in the example above for &lt;code&gt;comments&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;route the request data on the endpoint to the relevant controller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is all defined with one method call. We don't need to go through several files and methods to make sure these steps are all done for every route. This makes, what would be high churn code, more maintainable*.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*: At times, we may be swapping out a lot of code with less code, but that code is more complex because of the metaprogramming involved.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing your own Ruby DSL
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The start of a DSL
&lt;/h3&gt;

&lt;p&gt;The first thing that usually gets a DSL is configuration. A gem ships with a configuration class or a part of an app does. A new &lt;code&gt;Config&lt;/code&gt; class gets created with some config options. (In this case a CLI tool that has options to print more information with &lt;code&gt;verbose&lt;/code&gt; and a particular output format called &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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Config&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="ss"&gt;:verbose&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;:format&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:documentation&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Config:...&lt;/span&gt;
&lt;span class="c1"&gt;#        @options={:verbose=&amp;gt;true, :format=&amp;gt;:documentation}&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example is usually enough for a small component.&lt;/p&gt;

&lt;p&gt;Let's look how we can make this DSL feel more like some of the DSLs we've seen. In the example below we don't configure the Config class with a Hash of options, but use method calls like the &lt;code&gt;verbose=&lt;/code&gt; attribute writer.&lt;/p&gt;

&lt;p&gt;Ruby has helpers for defining reader and writer methods on a class for instance variables. Calling &lt;code&gt;attr_accessor :verbose&lt;/code&gt; in a class definition will define the &lt;code&gt;verbose&lt;/code&gt; or &lt;code&gt;verbose=&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;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;
  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:format&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Config&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verbose&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;verbose&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;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;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:documentation&lt;/span&gt;

&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Config:...&lt;/span&gt;
         &lt;span class="vi"&gt;@format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;:documentation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="vi"&gt;@verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this is quick to set up, it has some downsides. Like before, we want to store all config options on a &lt;code&gt;@options&lt;/code&gt; Hash instead of on their own instance variables. To export the config options as a Hash, we would need to export them all manually. Now there are more places that need to be updated the more config options are added. Easily forgotten, easily broken.&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;Config&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;options&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;:verbose&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:format&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@format&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="n"&gt;pp&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;options&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; {:verbose=&amp;gt;true, :format=&amp;gt;:documentation}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make the Config class work with a Hash of options, we can define our own methods for each config option. In these methods we set the values on the &lt;code&gt;@options&lt;/code&gt; Hash, using the key of the config option we want to set. Great! We now can export our configuration with ease.&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;Config&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:options&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;=&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;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&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;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Config&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verbose&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;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:documentation&lt;/span&gt;

&lt;span class="n"&gt;pp&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;options&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; {:verbose=&amp;gt;true, :format=&amp;gt;:documentation}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, we run into a familiar problem. Every time a new config option is added we need to add another method for that config option. As more config options are added, the Config class grows and grows, becoming more difficult to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamically define methods in Ruby
&lt;/h2&gt;

&lt;p&gt;Instead of defining a method per config option, we can dynamically define these methods. Dynamically defining methods allow us to quickly define several methods that share almost the same implementation.&lt;/p&gt;

&lt;p&gt;In the example below I've created a new class method, as indicated with the &lt;code&gt;def self.def_options&lt;/code&gt; syntax (1). This method, "define options", receives an array of option names to define methods for (2). In the &lt;code&gt;def_options&lt;/code&gt; method it will loop through these option names (3). In each iteration of the loop it will call the &lt;a href="https://ruby-doc.org/core-3.1.2/Module.html#define_method-method"&gt;&lt;code&gt;define_method&lt;/code&gt; method&lt;/a&gt; (4). With this method we can define a new method, like with the &lt;code&gt;def &amp;lt;method name&amp;gt;&lt;/code&gt; syntax, but with a dynamic method name.&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;Config&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;def_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;option_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 1&lt;/span&gt;
    &lt;span class="n"&gt;option_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&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;option_name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# 3&lt;/span&gt;
      &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;option_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;="&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# 4&lt;/span&gt;
        &lt;span class="vi"&gt;@options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;option_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="c1"&gt;# 5&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="n"&gt;def_options&lt;/span&gt; &lt;span class="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:format&lt;/span&gt; &lt;span class="c1"&gt;# 2&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;=&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;options&lt;/span&gt;
    &lt;span class="vi"&gt;@options&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Config&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verbose&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;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:documentation&lt;/span&gt;

&lt;span class="n"&gt;pp&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;options&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; {:verbose=&amp;gt;true, :format=&amp;gt;:documentation}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;define_method&lt;/code&gt; method receives the name of the method, and a block (4). This block will be the implementation of the method we are defining. In this case, it will call the &lt;code&gt;@options&lt;/code&gt; instance variable to receive the Hash of options configured, and add a new value for the option name we've declared (5). The DSL syntax for the end-user remains the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Ruby blocks
&lt;/h2&gt;

&lt;p&gt;In my opinion, no Ruby DSL is complete without blocks*. They look good for one, but they also provide a new scope of context to users of our DSL, in which our new DSL rules apply.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*: It's perfectly fine to have a DSL without blocks.&lt;/em&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;Config&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;verbose&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;format&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;In the next example, I've created a new class method called &lt;code&gt;configure&lt;/code&gt;. To interact with blocks given to a method, we can use the &lt;code&gt;yield&lt;/code&gt; keyword. If a method has been given a block, &lt;code&gt;yield&lt;/code&gt; will call that block. If we give a value to &lt;code&gt;yield&lt;/code&gt;, it will make it so that the block receives that value as an argument in the block, as is shown with &lt;code&gt;|config|&lt;/code&gt; in the example above.&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;Config&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="c1"&gt;# Create a new instance of the Config class&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="c1"&gt;# Call the block and give the Config instance as an argument&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using instance_eval
&lt;/h3&gt;

&lt;p&gt;We can make this shorter, and in my opinion, feel more like a DSL with its own block context. We can drop the &lt;code&gt;|config|&lt;/code&gt; block argument and avoid having to call &lt;code&gt;config.&lt;/code&gt; in front of every config option.&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;Config&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="n"&gt;verbose&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="nb"&gt;format&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;&lt;em&gt;I've omitted the equals sign (&lt;code&gt;=&lt;/code&gt;) from the example here. More on that later.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To make this work we go back to our &lt;code&gt;configure&lt;/code&gt; class method. Instead of &lt;code&gt;yield&lt;/code&gt;, we'll use &lt;a href="https://ruby-doc.org/core-3.1.2/BasicObject.html#instance_eval-method"&gt;&lt;code&gt;instance_eval&lt;/code&gt;&lt;/a&gt;. (Eval may sound scary, and it has some things to look out for, but in this small example it's quite safe.)&lt;/p&gt;

&lt;p&gt;To call &lt;code&gt;instance_eval&lt;/code&gt; we need to pass in the block given to the method. We can't use &lt;code&gt;yield&lt;/code&gt; for this. We need to explicitly specify the block argument of the &lt;code&gt;configure&lt;/code&gt; method with &lt;code&gt;&amp;amp;block&lt;/code&gt;. The key part being the ampersand (&lt;code&gt;&amp;amp;&lt;/code&gt;) of the argument name &lt;code&gt;&amp;amp;block&lt;/code&gt;, telling Ruby it's the block argument.&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;Config&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="n"&gt;instance&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;(In Ruby 3.1 and newer the &lt;code&gt;&amp;amp;block&lt;/code&gt; argument can also be written as only the ampersand &lt;code&gt;&amp;amp;&lt;/code&gt;, the name is optional.)&lt;/p&gt;

&lt;p&gt;When called on another object, like our Config class instance, &lt;code&gt;instance_eval&lt;/code&gt; will execute that block within the context of the Config instance. The context of that block is changed from where it was defined to the Config instance. When a method is called within that block, it will call it directly on the Config instance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Local variable assignment gotcha&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remember how in the example above I omitted the equals sign from the method names? When calling a method name ending with an equals sign in &lt;code&gt;instance_eval&lt;/code&gt;, Ruby will interpret it as a local variable assignment instead. It will not call the method on the Config instance. That's how Ruby works, and we can't change that. I omitted the equals sign to make the DSL still work.&lt;/p&gt;


&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Config&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="c1"&gt;# This won't work&lt;/span&gt;
  &lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="nb"&gt;format&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;p&gt;It's possible to work around this by explicitly calling the methods on &lt;code&gt;self.&lt;/code&gt;, but this syntax becomes basically the same as using &lt;code&gt;yield&lt;/code&gt;. Instead, I removed the equals sign from the method name.&lt;/p&gt;


&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Config&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="c1"&gt;# This works, but requires `self.` in front of every method call&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verbose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&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;/blockquote&gt;

&lt;h3&gt;
  
  
  When to use yield or instance_eval?
&lt;/h3&gt;

&lt;p&gt;I've shown two ways of calling blocks in Ruby. Which one should be used is up to the authors of the DSL. I have my personal preference for using &lt;code&gt;instance_eval&lt;/code&gt;, but there are definitely scenarios where using &lt;code&gt;yield&lt;/code&gt; works better.&lt;/p&gt;

&lt;p&gt;When something needs to be configured, using a lot of methods with an equals sign (writer methods), using &lt;code&gt;yield&lt;/code&gt; with a block argument is quite common.&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;Config&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;verbose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Set a value&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When defining something or calling actions, I see the &lt;code&gt;instance_eval&lt;/code&gt; approach used a lot.&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;Config&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="n"&gt;load_defaults!&lt;/span&gt; &lt;span class="c1"&gt;# Perform an action&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That doesn't mean one excludes the other. Gems like &lt;a href="https://github.com/puma/puma"&gt;Puma&lt;/a&gt; use the &lt;code&gt;instance_eval&lt;/code&gt; method for their configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/puma.rb&lt;/span&gt;
&lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;preload_app!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the approach you feel works best for your DSL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Share DSL behavior with modules
&lt;/h2&gt;

&lt;p&gt;With the above methods you can start building your DSL. This gives us a good toolbox. As the DSL grows, or more DSLs get added to the domain, it's good to share behavior between the DSL classes.&lt;/p&gt;

&lt;p&gt;For example, this domain has two separate configuration classes: a Config and an Output class. One configures how the gem works, the other how it outputs results to the terminal.&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;# Multiple configuration classes&lt;/span&gt;
&lt;span class="no"&gt;Config&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="n"&gt;enabled&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Output&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="n"&gt;verbose&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="nb"&gt;format&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;We don't want to repeat ourselves, so we move the DSL definition behavior to a module called Configurable. When that module is included the class method &lt;code&gt;def_options&lt;/code&gt; is made available with the class definition.&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;Config&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Configurable&lt;/span&gt;

  &lt;span class="n"&gt;def_options&lt;/span&gt; &lt;span class="ss"&gt;:enabled&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;Output&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Configurable&lt;/span&gt;

  &lt;span class="n"&gt;def_options&lt;/span&gt; &lt;span class="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:format&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the Configurable module is included, it adds the &lt;code&gt;options&lt;/code&gt; method to the class. The module also extends the class it's included in, using the &lt;a href="https://ruby-doc.org/core-3.1.2/Module.html#included-method"&gt;&lt;code&gt;included&lt;/code&gt; callback in Ruby modules&lt;/a&gt;. In that callback, the class is extended with the ClassMethods module, defined inside the Configurable module. This module will add the class methods (&lt;code&gt;def_options&lt;/code&gt; and &lt;code&gt;configure&lt;/code&gt;) to the class. This is also how things like &lt;a href="http://api.rubyonrails.org/classes/ActiveSupport/Concern.html"&gt;ActiveSupport::Concern&lt;/a&gt; work.&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;Configurable&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;included&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ClassMethods&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;def_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;option_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&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;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;options&lt;/span&gt;
    &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;||=&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 all the logic moved to the Configurable module, we now have a reusable module to create as many config classes as the domain needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nesting DSLs
&lt;/h2&gt;

&lt;p&gt;The Output class is really a sub domain of the Config class though. It's part of the gem config: the configurations should be nested within one another.&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;Config&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="n"&gt;enabled&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

  &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt; &lt;span class="ss"&gt;:documentation&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;Rather than Output being a top-level config class, we store it on the Config class. In the &lt;code&gt;output&lt;/code&gt; method in the example below, the method creates a new Output instance. When a block is given, it will &lt;code&gt;instance_eval&lt;/code&gt; the block on the &lt;code&gt;@output&lt;/code&gt; object. The method will always return the created &lt;code&gt;@output&lt;/code&gt; object so the sub-config can be accessed.&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;Config&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Configurable&lt;/span&gt;

  &lt;span class="n"&gt;def_options&lt;/span&gt; &lt;span class="ss"&gt;:enabled&lt;/span&gt;

  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Output&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Configurable&lt;/span&gt;

    &lt;span class="n"&gt;def_options&lt;/span&gt; &lt;span class="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:format&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;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@output&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
    &lt;span class="vi"&gt;@output&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;block_given?&lt;/span&gt;
    &lt;span class="vi"&gt;@output&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;h2&gt;
  
  
  Module builder pattern
&lt;/h2&gt;

&lt;p&gt;The Module builder pattern is a really neat design pattern in Ruby that allows us to do away with the two step process of including a module and then calling methods included by it. This pattern is described in more detail in &lt;a href="https://dejimata.com/2017/5/20/the-ruby-module-builder-pattern"&gt;The Ruby Module Builder Pattern by Chris Salzberg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the example below, a new &lt;code&gt;ConfigOption&lt;/code&gt; module is used to include a dynamically defined module. For the end-user, the resulting DSL remains the same.&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;Config&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ConfigOption&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="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:format&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;When &lt;code&gt;ConfigOption.new&lt;/code&gt; is called, the desired config option names are given to the &lt;code&gt;initialize&lt;/code&gt; method. Like before, we iterate over this list. Using &lt;code&gt;define_method&lt;/code&gt; the necessary methods are defined on the module. It's possible to do so in this &lt;code&gt;initialize&lt;/code&gt; method, because it's creating a new implementation of the ConfigOption module.&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;ConfigOption&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Module&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;option_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="ss"&gt;:options&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;||=&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;option_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&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;option_name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="n"&gt;option_name&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;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;option_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&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;For a much more in-depth look, I can highly recommend reading &lt;a href="https://dejimata.com/2017/5/20/the-ruby-module-builder-pattern"&gt;The Ruby Module Builder Pattern by Chris Salzberg&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create DSL objects
&lt;/h2&gt;

&lt;p&gt;Another step I recommend is to separate the behavior of the DSL itself and the actual app code that uses it, by creating DSL classes. These classes are only used when the end-user interacts with the DSL, like configuring a gem. When the configuration is done, the options are read from the DSL class and set on whatever config object the gem uses.&lt;/p&gt;

&lt;p&gt;Like before, we have a Config class. When configured using &lt;code&gt;Config.configure&lt;/code&gt;, it creates a ConfigDSL class (1). This ConfigDSL class will become the context of the block given to the &lt;code&gt;configure&lt;/code&gt; class 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;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;dsl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConfigDSL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 1&lt;/span&gt;
   &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 2&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:options&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;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&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;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigDSL&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ConfigOption&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="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="n"&gt;instance&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&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;After the &lt;code&gt;configure&lt;/code&gt; block has been called, the Config class reads the options from the ConfigDSL and initializes a new instance of itself with these options (2).&lt;/p&gt;

&lt;p&gt;With this approach the DSL that configures the gem is only used when the app starts. The app doesn't carry around all that extra weight of how the DSL works all the time. The separation of this behavior makes it easier to not accidentally call the configure DSL when it should not be available.&lt;/p&gt;

&lt;p&gt;This approach also solves a downside of using &lt;code&gt;instance_eval&lt;/code&gt;. When calling blocks this way, private methods are accessible inside the block. That's something we usually don't want to allow.&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;Config&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="n"&gt;instance&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&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;secret_method&lt;/span&gt;
    &lt;span class="s2"&gt;"super secret method"&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;Config&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="c1"&gt;# This should raise an error about calling&lt;/span&gt;
  &lt;span class="c1"&gt;# a private method, but it doesn't&lt;/span&gt;
  &lt;span class="n"&gt;secret_method&lt;/span&gt;
  &lt;span class="c1"&gt;# =&amp;gt; "super secret method"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Private methods can be accessed in blocks called using &lt;code&gt;instance_eval&lt;/code&gt;, because the block is evaluated in the context of the instance. It's as if it's being run from a method within that object. With separate DSL classes you have to worry less about private methods that you don't want anyone to call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now that our toolbox is complete we can create our own Domain Specific Language using Ruby. We have the following tools at our disposal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;define_method&lt;/code&gt; to dynamically define new methods on classes.&lt;/li&gt;
&lt;li&gt;Use Ruby blocks to give your DSL that real DSL feeling and create a context wherein your DSL shines.

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;yield&lt;/code&gt; to return a DSL object as a block argument, or;&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;instance_eval&lt;/code&gt; to change how to block works, and allow end-users to directly call methods on the new context of new block.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Use Modules to:

&lt;ul&gt;
&lt;li&gt;share behavior between many classes, and;&lt;/li&gt;
&lt;li&gt;use the &lt;a href="https://dejimata.com/2017/5/20/the-ruby-module-builder-pattern"&gt;Module builder pattern&lt;/a&gt; to remove any logic of how the DSL is constructed from the class that uses the DSL.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;DSL objects separate the logic of how the DSL works and how the rest of the gem works. Creating a better separation of responsibilities in your code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now go forth, and build your own DSL!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>dsl</category>
      <category>metaprogramming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Calculating String length and width – Fun with Unicode</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Thu, 16 Jun 2022 11:01:14 +0000</pubDate>
      <link>https://dev.to/tombruijn/calculating-string-length-and-width-fun-with-unicode-150c</link>
      <guid>https://dev.to/tombruijn/calculating-string-length-and-width-fun-with-unicode-150c</guid>
      <description>&lt;p&gt;Let's calculate how string length in Rust¹! How many characters there really are and how much space these strings take up when displayed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;¹: This article may also apply to other languages. This article will only focus on strings with the Rust default UTF-8 encoding. There's an appendix for how it works in Ruby at the end of the article. I'm simplifying this content to keep the article short.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post was &lt;a href="https://tomdebruijn.com/posts/rust-string-length-width-calculations/"&gt;first published on my own blog&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  String.len()
&lt;/h2&gt;

&lt;p&gt;The first function you'll probably come across is &lt;a href="http://doc.rust-lang.org/1.61.0/std/string/struct.String.html#method.len"&gt;&lt;code&gt;String.len()&lt;/code&gt;&lt;/a&gt;/&lt;a href="http://doc.rust-lang.org/1.61.0/core/primitive.str.html#method.len"&gt;&lt;code&gt;str/len()&lt;/code&gt;&lt;/a&gt;, or length of string. Given the string &lt;code&gt;"abc"&lt;/code&gt; it will returns the length of three. All looks good so far.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="s"&gt;"abc"&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is, until we take a closer look at the docs for this function. It says the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Returns the length of this string, in bytes, not &lt;code&gt;char&lt;/code&gt;s or graphemes. In other words, it might not be what a human considers the length of the string.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="http://doc.rust-lang.org/1.61.0/std/string/struct.String.html#method.len"&gt;&lt;code&gt;String.len()&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Rust docs are giving us a warning here that it may not always return the number we'd expect. It will return the string length in bytes, and it sounds like not all characters are counted as one byte.&lt;/p&gt;

&lt;p&gt;Let's try something that's not just plain "a" through "z", but something like a character with an accent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="s"&gt;"é"&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 2 bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see here that the result is a larger number than what we consider the string length to be. A lot of characters are comprised of multiple bytes. There are only so many characters we can make from an eight number byte, this is &lt;a href="https://en.wikipedia.org/wiki/ASCII"&gt;what ASCII is&lt;/a&gt;. To support all characters of all languages in the world in 256 possible different bytes wouldn't fit. Let's try another approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chars.count()
&lt;/h2&gt;

&lt;p&gt;Rust has a built-in "Chars" module we can use to split up the string into a list of characters, this gives a more accurate result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="s"&gt;"abc"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 3 characters&lt;/span&gt;
&lt;span class="s"&gt;"é"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// =&amp;gt; 1 characters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we ask the &lt;a href="http://doc.rust-lang.org/1.60.0/core/primitive.str.html#method.chars"&gt;&lt;code&gt;str.chars()&lt;/code&gt;&lt;/a&gt; method to give us a breakdown of what it considers characters we get a pretty good result. The character with the accent is seen as one character.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="s"&gt;"é"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; Chars(['é'])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've learned that characters can be composed of multiple bytes. Relying on the string byte length for the actual length is not accurate enough.&lt;/p&gt;

&lt;p&gt;Will Chars always return an accurate string length? This depends on your use-case. If you're looking for the number of characters in a string, probably yes, but also no. If you're looking for the actual string display width as rendered, the size it takes up on screen, then very much no.&lt;/p&gt;

&lt;p&gt;If we look at the documentation again it will give us another warning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's important to remember that &lt;code&gt;char&lt;/code&gt; represents a Unicode Scalar Value, and might not match your idea of what a 'character' is. Iteration over grapheme clusters may be what you actually want.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="http://doc.rust-lang.org/1.60.0/core/primitive.str.html#method.chars"&gt;&lt;code&gt;str.chars()&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Graphemes
&lt;/h2&gt;

&lt;p&gt;What if the string being checked doesn't only contain numbers and letters, accents or not? Emojis are very popular nowadays and present in every kind of string. Emojis can have a byte size of much more than two bytes, but also consist of multiple &lt;em&gt;characters&lt;/em&gt; even though it looks like one object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Person emoji&lt;/span&gt;
&lt;span class="s"&gt;"🧑"&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;// =&amp;gt; 4 bytes&lt;/span&gt;
&lt;span class="s"&gt;"🧑"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 1 characters&lt;/span&gt;

&lt;span class="c1"&gt;// Woman scientist emoji&lt;/span&gt;
&lt;span class="s"&gt;"👩‍🔬"&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;// =&amp;gt; 11 bytes&lt;/span&gt;
&lt;span class="s"&gt;"👩‍🔬"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 3 characters&lt;/span&gt;

&lt;span class="c1"&gt;// Family: Man, Man, Girl, Boy emoji&lt;/span&gt;
&lt;span class="s"&gt;"👨‍👨‍👧‍👦"&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;// =&amp;gt; 25 bytes&lt;/span&gt;
&lt;span class="s"&gt;"👨‍👨‍👧‍👦"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 7 characters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://emojipedia.org/woman-scientist/"&gt;"woman scientist" emoji&lt;/a&gt; shown above takes up eleven bytes and three characters. The family takes up 27 bytes and seven characters, even though we only see one item in the string.&lt;/p&gt;

&lt;p&gt;If we print the list of characters we'll get a better idea of what is happening.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="s"&gt;"👩‍🔬"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; Chars(['👩', '\u{200d}', '🔬'])&lt;/span&gt;

&lt;span class="s"&gt;"👨‍👨‍👧‍👦"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; Chars([&lt;/span&gt;
&lt;span class="c1"&gt;//   '👨',&lt;/span&gt;
&lt;span class="c1"&gt;//   '\u{200d}',&lt;/span&gt;
&lt;span class="c1"&gt;//   '👨',&lt;/span&gt;
&lt;span class="c1"&gt;//   '\u{200d}',&lt;/span&gt;
&lt;span class="c1"&gt;//   '👧',&lt;/span&gt;
&lt;span class="c1"&gt;//   '\u{200d}',&lt;/span&gt;
&lt;span class="c1"&gt;//   '👦'&lt;/span&gt;
&lt;span class="c1"&gt;// ])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Emoji can consists of multiple characters, that together construct another emoji and tell computers what to render. In the example above, we first see the &lt;a href="https://emojipedia.org/woman/"&gt;"woman" emoji&lt;/a&gt;, then what is called a &lt;a href="https://en.wikipedia.org/wiki/Zero-width_joiner"&gt;"Zero Width Joiner" character&lt;/a&gt;, and finally the &lt;a href="https://emojipedia.org/microscope/"&gt;microscope emoji&lt;/a&gt;. For the family we see the whole list of different genders and ages joined together in the same way.&lt;/p&gt;

&lt;p&gt;The Zero Width Joiner character used by these combined emoji is, as the name describes, a Unicode character with zero width (which makes it invisible). This character is used to &lt;a href="https://unicode.org/emoji/charts/emoji-zwj-sequences.html"&gt;join together multiple emoji to make a new one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These additional emoji characters do mess up our string length calculation. Luckily we can use the &lt;a href="https://crates.io/crates/unicode-segmentation"&gt;unicode-segmentation Rust crate&lt;/a&gt; to do more accurate character counting. We can ask the crate to split the string based on something called Graphemes and return the list of characters. A grapheme cluster in this context is a group of Unicode codepoints that consist of &lt;a href="https://www.unicode.org/reports/tr29/"&gt;"user-perceived character"&lt;/a&gt;, what we consider a character when we type it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;unicode_segmentation&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UnicodeSegmentation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="s"&gt;"abc"&lt;/span&gt;&lt;span class="nf"&gt;.graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 3&lt;/span&gt;
&lt;span class="s"&gt;"é"&lt;/span&gt;&lt;span class="nf"&gt;.graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt;   &lt;span class="c1"&gt;// =&amp;gt; 1&lt;/span&gt;
&lt;span class="s"&gt;"🧑"&lt;/span&gt;&lt;span class="nf"&gt;.graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.count&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="s"&gt;"👩‍🔬"&lt;/span&gt;&lt;span class="nf"&gt;.graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.count&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="s"&gt;"👨‍👨‍👧‍👦"&lt;/span&gt;&lt;span class="nf"&gt;.graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.count&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;(The &lt;code&gt;true&lt;/code&gt; argument given to &lt;a href="https://unicode-rs.github.io/unicode-segmentation/unicode_segmentation/trait.UnicodeSegmentation.html#tymethod.graphemes"&gt;&lt;code&gt;graphemes&lt;/code&gt; function&lt;/a&gt; means we want to count it using the Unicode extended grapheme clusters and not the legacy clusters. Let's use the non-legacy cluster.)&lt;/p&gt;

&lt;p&gt;Finally! We have an accurate string length. Right?&lt;/p&gt;

&lt;p&gt;Yes. For the scenarios in which you want to know the number of characters in a string, I'd say yes.&lt;/p&gt;

&lt;p&gt;But...&lt;/p&gt;

&lt;h2&gt;
  
  
  Graphemes widths
&lt;/h2&gt;

&lt;p&gt;As you can see in the code example below, emoji aren't shown one character column wide. Most emoji are rendered with a display width of two columns, two other Latin characters, like A through Z. For illustration purposes I'll be using a monospaced font so that the latin characters have a predicable width.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// These two lines should render with the same width&lt;/span&gt;
&lt;span class="s"&gt;"ab"&lt;/span&gt;
&lt;span class="s"&gt;"🧑"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the graphemes-count-method (shown in the previous section) will give you a correct string length in terms of how many characters you see, it's not always same as the horizontal space in columns a string takes up.&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://github.com/tombruijn/lintje/"&gt;Lintje project&lt;/a&gt; (a Git linter) I ran into this string length vs display width problem for the program's rules and output formatting. The terminal output didn't align properly when a string in a Git commit message included a emoji. In the example output below, the &lt;code&gt;^&lt;/code&gt; marker should be aligned with the last character of the string, but with an emoji in the string it wouldn't be properly aligned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Badly aligned output&lt;/span&gt;
String with a ❌ emoji
                    ^ End of sentence
&lt;span class="c"&gt;# Well aligned output&lt;/span&gt;
String with a ✅ emoji
                     ^ End of sentence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For rules that checked string length, I decided to count the display width of how every character is rendered as the string length. If a string has a max length of 50 characters, because of readability and width constraints, it should not be allowed to jam that string full with 50 emoji. It would take up double the horizontal space of a string with the same length without emoji.&lt;/p&gt;

&lt;p&gt;Using the &lt;a href="https://crates.io/crates/unicode-width"&gt;unicode-width Rust crate&lt;/a&gt; we can calculate a more accurate string display width.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;UnicodeWidthStr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"🧑"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 2&lt;/span&gt;
&lt;span class="nn"&gt;UnicodeWidthStr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"👩‍🔬"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 4&lt;/span&gt;
&lt;span class="c1"&gt;// Consists of 👩, a Zero Width Joiner and 🔬&lt;/span&gt;
&lt;span class="nn"&gt;UnicodeWidthStr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"👨‍👨‍👧‍👦"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 8&lt;/span&gt;
&lt;span class="c1"&gt;// Consists of multiple face emoji and Zero Width Joiner characters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is, the display width that every character is defined as being part of each grapheme cluster in Unicode. As you can see, the emoji with a Zero Width Joiner characters are as wide as the number of emoji they join times two.&lt;/p&gt;

&lt;p&gt;There are also "emoji" that only return a display width of one, not two, columns. These one column display width characters are considered to have a "narrow" display width. The two column wide characters are "wide". This difference is something you can see if your terminal and other applications, as it sometimes overlaps with the next character. This will not be visible in the browser you're reading this in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="s"&gt;"❤️"&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;// =&amp;gt; 6 bytes&lt;/span&gt;
&lt;span class="s"&gt;"❤️"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 2 characters&lt;/span&gt;
&lt;span class="s"&gt;"❤️"&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;         &lt;span class="c1"&gt;// =&amp;gt; Chars(['❤', '\u{fe0f}'])&lt;/span&gt;
&lt;span class="nn"&gt;UnicodeWidthStr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"❤️"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 1 display width&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The heart emoji ❤️ is a &lt;a href="https://en.wikipedia.org/wiki/Dingbat"&gt;"Heavy black heart" character&lt;/a&gt; &lt;span&gt;❤&lt;/span&gt; from the dingbat collection combined with what's called a &lt;a href="https://en.wikipedia.org/wiki/Variation_Selectors_(Unicode_block)"&gt;"Variation Selector-16" character&lt;/a&gt;. This is another invisible character in graphemes clusters to indicate certain characters should be displayed as their emoji counterparts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  And the actual width is?
&lt;/h2&gt;

&lt;p&gt;Why is this happening? From what I understand the unicode-width library is following the Unicode reference to the letter, counting only the base character's display width and not the emoji variation. That results in output that I would not have expected. It's not something that can be fixed, unless you change something in Unicode first.&lt;/p&gt;

&lt;p&gt;Unfortunately I don't have another function or library to call on to fix this and return what we see as the actual display width.&lt;/p&gt;

&lt;p&gt;What I did in my Lintje project was first split up the string into graphemes clusters, then scan every sub string for Zero Width Joiner characters, and then only return "two" as the width. This is somewhat more accurate to what we see displayed, but it's not 100% accurate. It's good enough for my purpose right now. There probably are better ways out there to do this, but I fear that it will mean maintaining a list of the display width of all emojis. At least the exceptions with a display width of one. Let me know if you know of a better solution!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Very simplified example&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"👨‍👨‍👧‍👦"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;unicode_chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="nf"&gt;.graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;unicode_chars&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&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;character&lt;/span&gt;&lt;span class="nf"&gt;.contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\u{200d}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&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="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nn"&gt;UnicodeWidthStr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;character&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="n"&gt;width&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full implementation with additional checks for other modifier characters can be found in the &lt;a href="https://github.com/tombruijn/lintje/blob/501aab06e19008e787237438a69ac961f38bb4b7/src/utils.rs#L22-L71"&gt;Lintje GitHub project's utils module&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;We've learned that what we humans consider string length is not the byte length. Characters can be multiple characters joined together, like emoji. Not all characters have the same display width. Some characters take up more horizontal space than others and some don't even take up any horizontal space.&lt;/p&gt;

&lt;p&gt;So what should you use to calculate string length or display width?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do you want the length of a string in bytes? Use &lt;a href="http://doc.rust-lang.org/1.61.0/std/string/struct.String.html#method.len"&gt;&lt;code&gt;String.len()&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Do you want the number of characters in a string? The &lt;a href="http://doc.rust-lang.org/1.60.0/std/str/struct.Chars.html#method.count"&gt;&lt;code&gt;Chars.count()&lt;/code&gt;&lt;/a&gt; method is an option, but I suggest the next solution.&lt;/li&gt;
&lt;li&gt;Do you want the visible number of characters in a string? Use &lt;a href="https://crates.io/crates/unicode-segmentation"&gt;&lt;code&gt;str.graphemes(true).count()&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Do you want the somewhat accurate width of the string? Use &lt;a href="https://crates.io/crates/unicode-width"&gt;&lt;code&gt;UnicodeWidthStr.width(str)&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you're like me an what the string display width calculated more accurately? You'll have to write something yourself I'm afraid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Appendix: Ruby
&lt;/h2&gt;

&lt;p&gt;I write a lot of Ruby code, so here's how the above applies to Ruby, as much as I looked into it.&lt;/p&gt;

&lt;p&gt;When calling Ruby's &lt;a href="https://ruby-doc.org/core-3.1.2/String.html#length-method"&gt;&lt;code&gt;String#length&lt;/code&gt;&lt;/a&gt;, it returns the length of characters like Rust's &lt;code&gt;Chars.count&lt;/code&gt;. If you want the length in bytes you need to call &lt;a href="https://ruby-doc.org/core-3.1.2/String.html#bytesize-method"&gt;&lt;code&gt;String#bytesize&lt;/code&gt;&lt;/a&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;"abc"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; 3 characters&lt;/span&gt;
&lt;span class="s2"&gt;"abc"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bytesize&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 3 bytes&lt;/span&gt;
&lt;span class="s2"&gt;"é"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;     &lt;span class="c1"&gt;# =&amp;gt; 1 characters&lt;/span&gt;
&lt;span class="s2"&gt;"é"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bytesize&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; 2 bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling the length on emoji will return the individual characters as the length. The 👩‍🔬 emoji is three characters and eleven bytes in Ruby as well.&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;"👩‍🔬"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; 3 characters&lt;/span&gt;
&lt;span class="s2"&gt;"👩‍🔬"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bytesize&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 11 bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you want grapheme clusters instead? You're in luck: it's built-in to Ruby with &lt;a href="https://ruby-doc.org/core-3.1.2/String.html#grapheme_clusters-method"&gt;&lt;code&gt;String#grapheme_clusters&lt;/code&gt;&lt;/a&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;"👩‍🔬"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grapheme_clusters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 1 cluster&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To calculate the display with, we can use the &lt;a href="https://rubygems.org/gems/unicode-display_width"&gt;unicode-display_width gem&lt;/a&gt;. The same multiple counting of emoji in the grapheme cluster still applies here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"unicode/display_width"&lt;/span&gt;

&lt;span class="no"&gt;Unicode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DisplayWidth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"👩‍🔬"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 4&lt;/span&gt;
&lt;span class="no"&gt;Unicode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DisplayWidth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"❤️"&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;



</description>
      <category>rust</category>
      <category>unicode</category>
      <category>ruby</category>
      <category>programming</category>
    </item>
    <item>
      <title>When not to use instance variables in RSpec</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Tue, 02 Feb 2021 13:06:58 +0000</pubDate>
      <link>https://dev.to/tombruijn/when-not-to-use-instance-variables-in-rspec-3jb9</link>
      <guid>https://dev.to/tombruijn/when-not-to-use-instance-variables-in-rspec-3jb9</guid>
      <description>&lt;p&gt;Using RSpec there is some confusion about the differences between &lt;code&gt;let&lt;/code&gt;, &lt;code&gt;let!&lt;/code&gt;, and instance variables in specs. I'd like to focus on how instance variables work in RSpec in combination with &lt;code&gt;before :context&lt;/code&gt; blocks, and in what kind of scenarios you should and should not use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use instance variables?
&lt;/h2&gt;

&lt;p&gt;The advantage of declaring instance variables in &lt;code&gt;before :context&lt;/code&gt; (or &lt;code&gt;before :all&lt;/code&gt;) blocks is that whatever value is assigned is only queried or calculated once for many specs. The &lt;code&gt;before :context&lt;/code&gt; block is only executed once for all specs in that context. Those specs can use the instance variable without repeating the same setup for every spec, which should speed up the test suite.&lt;/p&gt;

&lt;p&gt;Reading the above it might be tempting to put a lot of spec setup in &lt;code&gt;before :context&lt;/code&gt; blocks. A fast test suite creates happy developers, right? But there's a downside to using instance variables in RSpec, which could make for very unhappy developers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;From the &lt;a href="https://github.com/rspec/rspec-core/blob/c6315d6e899796d3d0203dc8b656708a3ebca9a1/lib/rspec/core/hooks.rb#L122-L138"&gt;RSpec docs&lt;/a&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;It is very tempting to use &lt;code&gt;before(:context)&lt;/code&gt; to speed things up, but we recommend that you avoid this as there are a number of gotchas, as well as things that simply don't work.&lt;/p&gt;

&lt;p&gt;[...]&lt;/p&gt;

&lt;p&gt;Instance variables declared in &lt;code&gt;before(:context)&lt;/code&gt; are shared across all the examples in the group. This means that each example can change the state of a shared object, resulting in an ordering dependency that can make it difficult to reason about failures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The RSpec docs give us a warning about changing values of the instance variable. State can leak between specs using instance variables defined in a &lt;code&gt;before :context&lt;/code&gt; block this way.&lt;/p&gt;

&lt;p&gt;Let's look at some examples of specs using instance variables and in what scenarios in will break.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specs sharing instance variables
&lt;/h2&gt;

&lt;p&gt;In the example below specs only assert if the value of the instance variable matches the expected value. Since the instance variable is not changed, all the specs will pass. If the instance variable value took a long time to query or calculate we have saved that time for two specs in this file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/lib/example_1_spec.rb&lt;/span&gt;
&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"Example 1"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="ss"&gt;:context&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Imagine this being a complex value to prepare&lt;/span&gt;
    &lt;span class="c1"&gt;# This block is only run once in the `describe "Example 1"` block&lt;/span&gt;
    &lt;span class="vi"&gt;@my_instance_variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:my_value&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"spec 1"&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="vi"&gt;@my_instance_variable&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;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_value&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="s2"&gt;"spec 2"&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="vi"&gt;@my_instance_variable&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;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_value&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bundle exec rspec spec/lib/example_1_spec.rb --order defined
Finished in 0.00223 seconds
2 examples, 0 failures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;em&gt;I'm using &lt;code&gt;--order defined&lt;/code&gt; in the examples in this post so that the spec execution order is predictable and reproducible.&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;But specs can be more complicated than this. They may pass the instance variable to some other part of the app, which modifies the given value. This is where things go wrong, what the RSpec docs warn us about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reassigning the instance variable
&lt;/h2&gt;

&lt;p&gt;If changing the instance variable is the problem, let's reassign it and see what happens in other specs.&lt;/p&gt;

&lt;p&gt;In the example below the "spec 1" spec changes the instance variable to test a slightly different scenario.&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/lib/example_2_spec.rb&lt;/span&gt;
&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"Example 2"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="ss"&gt;:context&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Imagine this being a complex value to prepare&lt;/span&gt;
    &lt;span class="vi"&gt;@my_instance_variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:my_value&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"spec 1"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@my_instance_variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:new_value&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@my_instance_variable&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;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:new_value&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="s2"&gt;"spec 2"&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="vi"&gt;@my_instance_variable&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;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_value&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bundle exec rspec spec/lib/example_2_spec.rb --order defined
Finished in 0.00223 seconds
2 examples, 0 failures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example "spec 2" does not fail, even though "spec 1"—which runs before "spec 2"—changes the instance variable. There was no need for us to reset the original value of the instance variable at the end of the spec even though we changed it.&lt;/p&gt;

&lt;p&gt;The way that RSpec runs the specs ensures that every spec uses the original instance variables. Every spec in RSpec is its own Ruby class, in which the spec is performed. Before the spec class run, RSpec sets the instance variables from the &lt;code&gt;before :context&lt;/code&gt; block on the spec class. When an instance variable is reassigned in a spec, it only reassigns it on that spec class instance. It doesn't not reassign the instance variable on the same scope as the &lt;code&gt;before :context&lt;/code&gt; instance variables are stored, and so does not interfere with any other specs. An example of how this looks can be found later on in this post.&lt;/p&gt;

&lt;p&gt;This behavior doesn't always quite work though. Let's see what happens if we use a bit more complex value. That way we know the limitations of using instance variables in RSpec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modifying instance variable values
&lt;/h2&gt;

&lt;p&gt;In the next example the &lt;code&gt;@my_instance_variable&lt;/code&gt; is assigned a more complex value: an array with multiple values. We will intentionally break the spec in this scenario.&lt;/p&gt;

&lt;p&gt;In "spec 1" we're testing a slightly different scenario again, modifying the value before running the assertion. Instead of reassigning the variable we're adding a value to the array on &lt;code&gt;@my_instance_variable&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/lib/example_3_spec.rb&lt;/span&gt;
&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"Example 3"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="ss"&gt;:context&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@my_instance_variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:two&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="s2"&gt;"spec 1"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@my_instance_variable&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:three&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@my_instance_variable&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;eql&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:three&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="s2"&gt;"spec 2"&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="vi"&gt;@my_instance_variable&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;eql&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:two&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bundle exec rspec spec/lib/example_3_spec.rb
Failures:

  1) Example 3 spec 2
     Failure/Error: expect(@my_instance_variable).to eql([:one, :two])

       expected: [:one, :two]
            got: [:one, :two, :three]

       (compared using eql?)

       Diff:
       @@ -1 +1 @@
       -[:one, :two]
       +[:one, :two, :three]

     # ./spec/lib/example_3_spec.rb:14:in `block (2 levels) in &amp;lt;top (required)&amp;gt;'

Finished in 0.01596 seconds (files took 0.10576 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/lib/example_3_spec.rb:12 # Example 3 spec 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike before, the "spec 2" spec has now failed. It fails because the instance variable still has the value from the first spec. State has leaked from "spec 1" into "spec 2". Let's look at how the values from these instance variables have moved between specs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How instance variables work in RSpec
&lt;/h2&gt;

&lt;p&gt;To recap what we learned from the examples earlier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assigning instance variables in &lt;code&gt;before :context&lt;/code&gt; means they'll only be assigned once, as the &lt;code&gt;before :context&lt;/code&gt; block is only once run before all specs in the spec context.&lt;/li&gt;
&lt;li&gt;Every spec in RSpec is performed as its own class, with its own scope. Instance variable from the &lt;code&gt;before :context&lt;/code&gt; block are set on the spec class before it is performed.&lt;/li&gt;
&lt;li&gt;Instance variable values do not leak between specs when the values are basic Ruby objects such as Symbols, numbers, etc.&lt;/li&gt;
&lt;li&gt;Instance variable values do leak between specs when the values are more complex objects such as Arrays, Strings, Class instances, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a closer look at how RSpec handles instance variables for spec classes to see how this could break in our test suite.&lt;/p&gt;

&lt;h3&gt;
  
  
  How RSpec handles instance variables
&lt;/h3&gt;

&lt;p&gt;When RSpec runs specs in a context, it first runs the &lt;code&gt;before :context&lt;/code&gt; blocks. After a &lt;code&gt;before :context&lt;/code&gt; block is executed RSpec then stores the list of the instance variables on the class it creates for the context.&lt;/p&gt;

&lt;p&gt;When RSpec then starts a spec in that context it creates a new class for that spec and sets instance variables of that context on the spec class.&lt;/p&gt;

&lt;p&gt;Let's look at how this works using the same scenario from the second example, where we reassigned the instance variables.&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;Context&lt;/span&gt; &lt;span class="c1"&gt;# RSpec context class&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before_context_ivars&lt;/span&gt;
    &lt;span class="c1"&gt;# Where the `before :context` instance variables are stored&lt;/span&gt;
    &lt;span class="vi"&gt;@ivars&lt;/span&gt; &lt;span class="o"&gt;||=&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="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_before_context_ivars_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Set instance variables from `before :context` on spec instance&lt;/span&gt;
    &lt;span class="n"&gt;before_context_ivars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&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;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_variable_set&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;value&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="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Spec&lt;/span&gt; &lt;span class="c1"&gt;# RSpec spec class&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="c1"&gt;# During spec&lt;/span&gt;
    &lt;span class="vi"&gt;@var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# Reassign instance variable&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;# Mock a `before :context` block and&lt;/span&gt;
&lt;span class="c1"&gt;# store an instance variable on the Context class&lt;/span&gt;
&lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before_context_ivars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:@var&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;# Basic Ruby object value&lt;/span&gt;
&lt;span class="c1"&gt;# Initialize the spec class&lt;/span&gt;
&lt;span class="n"&gt;spec_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Spec&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;# Set the `before :context` instance variables on the spec&lt;/span&gt;
&lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_before_context_ivars_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Context @var before spec:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before_context_ivars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:@var&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;

&lt;span class="c1"&gt;# Run the spec&lt;/span&gt;
&lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Spec @var:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_variable_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:@var&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Context @var after spec:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before_context_ivars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:@var&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Simplified example for demonstration purposes.)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context @var before spec:
1
Spec1 @var:
2
Context @var after spec:
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RSpec sets the original value of the instance variable on every spec class instance. Reassigning the instance variable in the spec class does not modify the value of the instance variable on the context. It only changes it on the spec class instance.&lt;/p&gt;

&lt;p&gt;When the instance variable value was modified however, the value stored on the Context class is also modified, as it is still the same value.&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;# Using the same context class as from the previous example&lt;/span&gt;

&lt;span class="c1"&gt;# Mock a `before :context` block and&lt;/span&gt;
&lt;span class="c1"&gt;# store an instance variable on the Context class&lt;/span&gt;
&lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before_context_ivars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:@var&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="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="c1"&gt;# More complex Ruby object&lt;/span&gt;
&lt;span class="c1"&gt;# Initialize the spec class&lt;/span&gt;
&lt;span class="n"&gt;spec_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Spec&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;# Set the `before :context` instance variables on the spec&lt;/span&gt;
&lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_before_context_ivars_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Context @var before spec:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before_context_ivars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:@var&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;

&lt;span class="c1"&gt;# Run the spec&lt;/span&gt;
&lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Spec @var:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spec_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_variable_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:@var&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Context @var after spec:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="no"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;before_context_ivars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:@var&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context @var before spec:
[1, 2]
Spec @var:
[1, 2, 3]
Context @var after spec:
[1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we can see the instance variable's value has changed, because the value was modified, rather than the instance variable being reassigned. This value was modified in memory, also changing the value in the context instance variable storage, which causes the modified state to leak into other specs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pointers
&lt;/h3&gt;

&lt;p&gt;What happens is, RSpec (or rather Ruby) is assigning pointers to the values in memory when it sets the instance variable values on the spec class instance. Variables in Ruby are pointers to a place in the application's memory. Assigning a value to another variable does not make a copy of it, but points to the same location in memory.&lt;/p&gt;

&lt;p&gt;When RSpec sets the instance variables, it doesn't set a copy of the original Array value. Instead it sets the pointer to the Array value in memory. If the Array in memory has changed during the spec run, it will set not the original value for the next spec, but the modified Array instead. This is part of how Ruby works, this is not something RSpec can "fix". And which is why the RSpec docs warn us about using instance variables in &lt;code&gt;before :context&lt;/code&gt; blocks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;To prevent state from leaking into other specs by modified values, it's possible to &lt;a href="https://ruby-doc.org/core-2.7.1/Object.html#freeze-method"&gt;"freeze" objects in Ruby&lt;/a&gt;. If we freeze an Array, String or other object instance, Ruby will not allow any modifications.&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;var&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;freeze&lt;/span&gt;
&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="c1"&gt;# Raises an error to prevent modification&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; FrozenError (can't modify frozen Array: [1, 2])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this will be more difficult to do for larger objects with nested objects, as it only freezes the top object and not all nested objects.&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;var&lt;/span&gt; &lt;span class="o"&gt;=&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="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="nf"&gt;freeze&lt;/span&gt;
&lt;span class="n"&gt;var&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="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [[1, 2, 3], [4, 5]] # The nested value was modified&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively it's possible to &lt;a href="https://api.rubyonrails.org/v5.2.4/classes/Object.html#method-i-deep_dup"&gt;deep clone or dup&lt;/a&gt; the object. The problem with this is that it will take up a lot more memory, as every object will be kept in memory multiple times, so I can't recommend it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;RSpec scoping instance variables between specs in classes is a great help from RSpec for basic Ruby objects, but this behavior shouldn't be relied upon for more complex Ruby objects such as Arrays, Strings, and other object instances.&lt;/p&gt;

&lt;p&gt;If a spec is modifying an instance variable value, you can't be sure what the value of that instance variable will be in the next spec. State may leak to other specs, breaking them in unexpected ways. This will be especially difficult to track down when the specs are run in a random order each time.&lt;/p&gt;

&lt;p&gt;Make sure that if you use instance variables, you absolutely do &lt;em&gt;not&lt;/em&gt; modify any value set on the instance variable if you want a predictable and reproducible test suite. And that's something we should all want. I'm all for fast test suites, but what I like more is a stable test suite.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A big thanks to &lt;a href="https://twitter.com/Benoit_Tgt"&gt;Benoit Tigeot&lt;/a&gt; for fact checking this article!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>rspec</category>
      <category>testing</category>
    </item>
    <item>
      <title>Git: Review changes before committing</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Mon, 26 Oct 2020 12:52:32 +0000</pubDate>
      <link>https://dev.to/tombruijn/git-review-changes-before-committing-470l</link>
      <guid>https://dev.to/tombruijn/git-review-changes-before-committing-470l</guid>
      <description>&lt;p&gt;Making a git commit can be as quick as &lt;code&gt;git add --all &amp;amp;&amp;amp; git commit -m "WIP"&lt;/code&gt;. The problem with this approach is that we didn't check what changes we committed. Who knows what got committed that shouldn't have. Usually we find out when it's too late.&lt;/p&gt;

&lt;p&gt;While working on an issue, I personally make a lot of changes that don't belong in the same commit. For that reason the approach of "now commit everything I have changed" rarely works for me.&lt;/p&gt;

&lt;p&gt;Let's look at the things we don't want to commit first and then improve the way we make commits by reviewing what we commit first and how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things we don't want to commit
&lt;/h2&gt;

&lt;p&gt;Some things that we don't want stored in git commits are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App secrets

&lt;ul&gt;
&lt;li&gt;Tokens, passwords, personal information, etc. These are things we don't want to commit to the git history, especially public repositories. A bot will scrape our hosting provider credentials and spin up a lot of machines on our dime before we know what happened.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Debugging code

&lt;ul&gt;
&lt;li&gt;Some code may still be present in the project that helped debug an issue, such as a &lt;code&gt;print&lt;/code&gt;/&lt;code&gt;puts&lt;/code&gt;, a &lt;code&gt;console.log&lt;/code&gt;, or a &lt;code&gt;binding.pry&lt;/code&gt;/&lt;code&gt;debugger&lt;/code&gt;-statement. While not necessarily harmful it creates a lot of output or hangs the process while running the app and test suites. It creates unwanted noise.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Removing these changes from commits isn't always as easy. Force pushing branches can mess up the team's flow and commits in public repositories don't disappear. Someone with a direct link can still access the old commits.&lt;/p&gt;

&lt;p&gt;To go through the process of creating new app secrets, rolling those out across the app is very time consuming and cumbersome. Removing debugging code isn't as much trouble but it does require another commit, which adds noise to the git history. This doesn't help &lt;a href="https://tomdebruijn.com/posts/git-is-about-communication/"&gt;communicating in git&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review what to commit
&lt;/h2&gt;

&lt;p&gt;To avoid including things that shouldn't be committed and create better commits, let's look at ways to create commits.&lt;/p&gt;

&lt;p&gt;This is the process I recommend going through when creating a commit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with reviewing changes:

&lt;ul&gt;
&lt;li&gt;Are we about to stage files we should not be staging, such as credential files?&lt;/li&gt;
&lt;li&gt;Are there debug statements in the changes we should remove first?&lt;/li&gt;
&lt;li&gt;Are there changes that are not required to fix the bug or add the feature? In a commit where a bug is fixed, don't include code style changes in an unrelated part of the code.&lt;/li&gt;
&lt;li&gt;Finally, this is also a review for you, the committer, to double check the changes that were made are actually all necessary and correct. Are there tests for every logic change? Did we add or update the docs?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Stage the changes that you approve and are necessary.&lt;/li&gt;
&lt;li&gt;Only after this review, commit the changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main idea of this is that we look at what files we stage, but more importantly, we review the changes in each file before we stage them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commit tools
&lt;/h2&gt;

&lt;p&gt;Let's look at some tools that help with creating git commits. These are alternatives to &lt;code&gt;git add --all&lt;/code&gt; command from the beginning of this post, which stages all changes: modifications, additions and deletions.&lt;/p&gt;

&lt;p&gt;There are some basic tools that git provides us and there are third party tools we can use to make staging specific changes easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Git add file
&lt;/h3&gt;

&lt;p&gt;Using the &lt;code&gt;git add&lt;/code&gt; command it's possible to add one file at a time with &lt;code&gt;git add path/to/file.md&lt;/code&gt;. This makes sure we don't add files we shouldn't commit, such as secret files, which is good.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git status
On branch main
Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  modified:   path/to/file.md

&lt;span class="nv"&gt;$ &lt;/span&gt;git add path/to/file.md

&lt;span class="nv"&gt;$ &lt;/span&gt;git status
On branch master
Changes to be committed:
  modified:   path/to/file.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what about the changes in those files? We still don't know exactly what changes are being staged and will end up getting committed. We need a more detailed staging process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactively stage changes
&lt;/h3&gt;

&lt;p&gt;To review and select changes &lt;em&gt;within a file&lt;/em&gt; we want to stage we can use &lt;code&gt;git add --patch&lt;/code&gt;. This opens a basic selection interface in the terminal with which we can select "hunks" to be staged. Hunks are groups of changed lines in a file that git can easily stage and unstage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; git add --patch
&lt;span class="gh"&gt;diff --git a/app/models/blog_post.rb b/app/models/blog_post.rb
index 8b13789..257cc56 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/app/models/blog_post.rb
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/app/models/blog_post.rb
&lt;/span&gt;&lt;span class="p"&gt;@@ -154,6 +154,12 @@&lt;/span&gt; class BlogPost &amp;lt; ActiveRecord::Base
   end
&lt;span class="gi"&gt;+
+  def published?
+    binding.pry
+    Time.now &amp;gt;= published_at
+  end
&lt;/span&gt;
   def active?
&lt;span class="err"&gt;(1/10)&lt;/span&gt; Stage this hunk [y,n,q,a,d,e,?]?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above we run &lt;code&gt;git add --patch&lt;/code&gt; and it prompts us with the question if we want to "Stage this hunk". What's useful here is that we can see the "hunk" it's referring to in the preview above it, and review if it's any code we actually want to commit.&lt;/p&gt;

&lt;p&gt;Choosing "y" for "yes", or "n" for "no", we can step by step stage changes or skip them. Git will take us through all the changes one "hunk" at a time until we've reviewed them all.&lt;/p&gt;

&lt;p&gt;But maybe we spot an issue with the hunk. We can "q" for "quit" and open the file in our editor to fix the issue and then restart the process by running &lt;code&gt;git add --patch&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;This interface is quite limiting. If we don't agree with git's hunk boundaries we can't easily change them. It's not very easy to only stage one line or omit a line. If we stage the hunk in the example above we also commit some debugging code that will break things for us later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Git GUI
&lt;/h3&gt;

&lt;p&gt;A git GUI can help give us more control over what we commit. Apps that give us humans a more easy to digest interface for git and may even help with more advanced tools such as merge conflict resolution and rebasing.&lt;/p&gt;

&lt;p&gt;Git GUIs are great! Don't let anyone tell you otherwise.&lt;/p&gt;

&lt;p&gt;When making commits it's important to have a view of the current changes, stage them interactively, and commit knowing we only commit those changes that were selected. A GUI can display very detailed changes in a concise way, and the selection process for staging changes is more precise.&lt;/p&gt;

&lt;p&gt;Personally I use &lt;a href="https://jonas.github.io/tig/"&gt;tig&lt;/a&gt; most of the time in the terminal, and &lt;a href="https://fork.dev/"&gt;Fork&lt;/a&gt; any time I run into tig's limitations. To get started I recommend &lt;a href="https://fork.dev/"&gt;Fork&lt;/a&gt;, or a similar GUI app, as it's a very complete Git tool. Both tools give great overviews of git history and staged and unstaged files. It's possible to stage entire files in one go, or deep dive and only add the &lt;em&gt;one specific line&lt;/em&gt; we want to stage and nothing else.&lt;/p&gt;

&lt;p&gt;There are &lt;a href="https://git-scm.com/downloads/guis"&gt;many other git GUIs&lt;/a&gt;, and no one tool is the best or only one you're allowed to use. Experiment, try them out, and use the tool that works best for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  An example commit flow
&lt;/h2&gt;

&lt;p&gt;When I am making a commit I often use tig in the terminal, but for convenience I'll use &lt;a href="https://fork.dev/"&gt;Fork&lt;/a&gt; in this example as it will look the same for everyone.&lt;/p&gt;

&lt;p&gt;First I open the app, then I'm presented with the git history. After opening the "Local Changes" view I get an overview of all uncommitted changes.&lt;/p&gt;

&lt;p&gt;In this example I want to stage the &lt;code&gt;env_helpers.rb&lt;/code&gt; file, but not all changes. There are changes in the same file for another feature I'm working on. If I stage the entire hunk I also stage the code I don't want to include. I could open the file in my editor again and remove the line temporarily, but then I should remember to restore it again later. (I'm going to forget that, aren't I?)&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/462944661" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is the process I go through in the video:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the left panel's "Unstaged Changes" box I look for the file I've just made changes to and want to commit.&lt;/li&gt;
&lt;li&gt;I open the file by clicking it and see the file changes in the right panel.&lt;/li&gt;
&lt;li&gt;There's a change on a line I do not want to commit, as indicated by the "TODO" comment.&lt;/li&gt;
&lt;li&gt;By selecting the line I do want to commit the Fork app gives me context specific actions to "Stage" the changes.&lt;/li&gt;
&lt;li&gt;I press the "Stage" button and only the selected change gets staged. The remaining unstaged file change is the line with the "TODO" comment I do not want to commit.&lt;/li&gt;
&lt;li&gt;I click on the file in the "Staged Changes" view in the left panel. Here I see the changes the one line change I just staged and nothing else. If these are all the changes I need, I can now commit them without also committing the unstaged changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this peek into how I review my changes before committing helps you make better commits. It's a process to keep being aware of. When I haven't kept a close eye on what I commit, I have included and pushed things I shouldn't have. So keep an eye on it and let's make better commits together!&lt;/p&gt;

&lt;p&gt;Review the changes you stage so you don't accidentally include any app secrets, debugging code, personal information, or anything else that shouldn't be committed.&lt;/p&gt;

&lt;p&gt;Try out a GUI or any of the other tools I've listed in this post and &lt;a href="https://twitter.com/tombruijn"&gt;let me know&lt;/a&gt; which is your favorite!&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>programming</category>
      <category>code</category>
    </item>
    <item>
      <title>Retry brittle tests until they fail</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Wed, 02 Sep 2020 13:27:32 +0000</pubDate>
      <link>https://dev.to/tombruijn/retry-brittle-tests-until-they-fail-3134</link>
      <guid>https://dev.to/tombruijn/retry-brittle-tests-until-they-fail-3134</guid>
      <description>&lt;p&gt;Brittle tests are tests that only fail &lt;em&gt;some of the time&lt;/em&gt;. Due to this it can be difficult to reproduce the scenario that's causing it to fail.&lt;/p&gt;

&lt;p&gt;These brittle tests can fail because of all sorts of things, some of which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Randomness in tests, or lack thereof. For example: the same numbers are generated twice, causing conflicts for object IDs in the database or memory.&lt;/li&gt;
&lt;li&gt;Test execution order. For example: tests that are run first are affecting the behavior of other tests. Test state leaks into other tests. For this scenario I love using &lt;a href="https://relishapp.com/rspec/rspec-core/docs/command-line/bisect"&gt;RSpec bisect&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;App bugs. Actual app specific bugs that only occur some of the time. What's causing it? Only way to find out is to get a failing test and start debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We want to fix those brittle tests, but the problem with debugging brittle tests is that they never fail when you want them to. A test can run without failure a 100 times, and only fail the 101th time. To manually retry it 101 times is very time consuming and not a lot of fun.&lt;/p&gt;

&lt;p&gt;What I found myself doing is squeezing a &lt;code&gt;while&lt;/code&gt;-statement around the command I wanted to keep retrying, but that got cumbersome and a typo was easily made. Instead, let's use a small executable for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retry executable
&lt;/h2&gt;

&lt;p&gt;When I'm not sure what the exact reason for the "brittleness" of a test is, I grab my "retry until fail" helper executable, &lt;code&gt;until-fail&lt;/code&gt; for short. This is a very small wrapper around a given command that keeps repeating until it encounters a failure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Retry a command until it fails

Usage:

  $ until-fail true
  # Will repeat forever

  $ until-fail false
  # Fails at the first iteration and breaks out of the retry loop

  $ until-fail ruby -e "rand(0..1) == 1 ? (puts 'failed'; exit(1)) : (puts 'success')"
  # Fails randomly and breaks out of the retry loop when it fails
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;until-fail&lt;/code&gt; executable repeats the given command, in our case a test, until it runs into the failing scenario that we want to investigate further. This allows us to debug the brittle test while it's in a broken scenario. With that new information we can hopefully fix that test.&lt;/p&gt;

&lt;p&gt;Combined with logging or print statements to provide more information about the context of the test failure, it should now be easier to debug the brittle test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="k"&gt;until&lt;/span&gt;&lt;span class="nt"&gt;-fail&lt;/span&gt; ruby tests/brittle_test.rb
Retry &lt;span class="c"&gt;#1&lt;/span&gt;
DEBUG: User#accepted_terms_and_conditions &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;Success!

Retry &lt;span class="c"&gt;#2&lt;/span&gt;
DEBUG: User#accepted_terms_and_conditions &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;Success!

...

Retry &lt;span class="c"&gt;#100&lt;/span&gt;
DEBUG: User#accepted_terms_and_conditions &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;Success!

Retry &lt;span class="c"&gt;#101&lt;/span&gt;
DEBUG: User#accepted_terms_and_conditions &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;false
&lt;/span&gt;Failure/Error: expect&lt;span class="o"&gt;(&lt;/span&gt;signed_up_user_names&lt;span class="o"&gt;)&lt;/span&gt;.to include&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Tom"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  expected signed up &lt;span class="nb"&gt;users &lt;/span&gt;to include &lt;span class="s2"&gt;"Tom"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where to find it
&lt;/h2&gt;

&lt;p&gt;The script is available &lt;a href="https://gist.github.com/tombruijn/0cde5de10e86d91717ed855623929b05"&gt;in this gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's a small Bash executable you can run in your shell, tested with Bash and ZSH.&lt;/p&gt;

&lt;p&gt;Download the file and run &lt;code&gt;chmod +x until-fail&lt;/code&gt; on it to make it executable. Move it to a location specified in your &lt;code&gt;$PATH&lt;/code&gt; so it can be run from any location by calling &lt;code&gt;until-fail&lt;/code&gt; and passing in the command to retry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="k"&gt;until&lt;/span&gt;&lt;span class="nt"&gt;-fail&lt;/span&gt; ruby some_file.rb
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="k"&gt;until&lt;/span&gt;&lt;span class="nt"&gt;-fail&lt;/span&gt; ruby tests/brittle_test.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See also the start this post for more information &lt;a href="https://tomdebruijn.com//posts/gems-on-the-command-line/#executables"&gt;how to create your own executables&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  In combination with pry
&lt;/h2&gt;

&lt;p&gt;I use this automatic retry method in combination with a well placed &lt;a href="https://github.com/pry/pry"&gt;pry&lt;/a&gt; statement in Ruby to open a console when the error occurs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="k"&gt;until&lt;/span&gt;&lt;span class="nt"&gt;-fail&lt;/span&gt; ruby tests/brittle_test.rb
...

Retry &lt;span class="c"&gt;#101&lt;/span&gt;
From: /path/to/project/tests/brittle_test.rb:11 :

     7: it &lt;span class="s2"&gt;"includes newly signed up user"&lt;/span&gt; &lt;span class="k"&gt;do
     &lt;/span&gt;8:   begin
     9:     expect&lt;span class="o"&gt;(&lt;/span&gt;signed_up_user_names&lt;span class="o"&gt;)&lt;/span&gt;.to include&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Tom"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    10:   rescue Exception &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; e
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 11:     binding.pry
    12:     raise e &lt;span class="c"&gt;# Reraise the failure so the retry script stops&lt;/span&gt;
    13:   end
    14: end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use &lt;code&gt;rescue Exception&lt;/code&gt;, because &lt;a href="https://tomdebruijn.com//posts/ruby-exceptions-primer/#failures-in-tests"&gt;RSpec raises an Exception on assertion failures&lt;/a&gt;. The rescue is only temporarily, we should remove it when the brittle test has been fixed.&lt;/p&gt;

&lt;p&gt;Now I can run the test command wrapped in the &lt;code&gt;until-fail&lt;/code&gt; helper, and walk away from the computer. When I come back some time later, hopefully a pry console is ready for me to start debugging the scenario that fails.&lt;/p&gt;




&lt;p&gt;I use this little &lt;code&gt;until-fail&lt;/code&gt; helper a lot while debugging brittle tests. It has certainly made it easier reproduce brittle tests locally. I've removed randomness in tests, cleaned up state between tests, and a variety of app specific scenarios that were the cause of the brittle test.&lt;/p&gt;

&lt;p&gt;Try it out and let me know if it has helped you!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>bash</category>
      <category>ruby</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Git is About Communication</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Thu, 16 Jul 2020 09:47:42 +0000</pubDate>
      <link>https://dev.to/appsignal/git-is-about-communication-2dl6</link>
      <guid>https://dev.to/appsignal/git-is-about-communication-2dl6</guid>
      <description>&lt;p&gt;An SCM such as Git is more than just a database for source code. It's not only the thing you need to interact with to get code to production, but also a log of changes on a project.&lt;/p&gt;

&lt;p&gt;It's not just the last couple of weeks of commits that are worth looking at. Any commit remains relevant weeks, months and years later.&lt;/p&gt;

&lt;p&gt;A commit serves multiple purposes. The first one is to explain a change during its review and the second is to explain a change to a future reader. It all revolves around communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication
&lt;/h2&gt;

&lt;p&gt;Git is about talking to your team. It's about talking to yourself, from the future. What about that colleague who hasn't even joined the team yet? Yes, them too.&lt;/p&gt;

&lt;p&gt;Git is a great resource to document why a change was made and the considerations that were part of the process of creating the commit. It's the documentation of how the project evolved.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Example: Using git blame in Practice
&lt;/h2&gt;

&lt;p&gt;Do you use git blame? Is it useful or is it a bunch of gibberish commits, including classics like: "WIP", "Fix bug", "update tests", "Move method", or my favorite: "..." (Yes, it's just three dots)?&lt;/p&gt;

&lt;p&gt;After some digging, you've found the change that introduced a bug, but you are no further in finding why the change was made in commit "WIP". You ask the person who authored it for more information, but they may not remember why the change from a year ago was necessary or they may no longer work at the company. So you're going to have to assume things about why a change was made and work off of that. That should not be necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Example: Pull Request Reviews
&lt;/h2&gt;

&lt;p&gt;When you or your team are reviewing a Pull Request, the same thing is happening, but you can ask why a change was made while it's still fresh in their memory. But you first &lt;em&gt;need to ask&lt;/em&gt;. To make a good review, the reviewer also needs to know if and which alternative solutions (if any) were considered and why. We need to make better commits to make that possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication in Commits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why "The why" is Important
&lt;/h3&gt;

&lt;p&gt;A commit with only a subject says very little. At best it tells you which change was made, which may be useful to tell what code was changed, but the reason why the change was made is missing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IqPm7fiV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2020-06/git-communication/commit_without_message_example.jpg" class="article-body-image-wrapper"&gt;&lt;img alt="Example of commit without a message" src="https://res.cloudinary.com/practicaldev/image/fetch/s--IqPm7fiV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2020-06/git-communication/commit_without_message_example.jpg"&gt;&lt;/a&gt;&lt;br&gt;&lt;p class="text-center"&gt;Example of a commit without a message&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/p&gt;

&lt;p&gt;Explaining why a change was made is a good moment to reflect on the process that got you there. Was the change made because it was the most logical choice, or were there alternative approaches, and why were these not chosen?&lt;/p&gt;

&lt;p&gt;If anyone else ever looks back on the commit, they can see if the restrictions a change was written under still apply or not, or how a certain bug slipped in under the assumptions a change was written.&lt;/p&gt;

&lt;p&gt;I use writing commit messages to rubber duck problems. When I'm stuck on a change, rather than grab my rubber ducky, I explain it in writing. This way, I also immediately have my commit message for my team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explaining the "why"
&lt;/h3&gt;

&lt;p&gt;To explain the "why" of why a commit was made, the commit message can explain the bug that's occurring that prompted a fix, along with its solution. This way, we have the reason for the commit as well as how the issue was fixed.&lt;/p&gt;

&lt;p&gt;For example, there is a method that needs to be called with an Integer value. In the production app, an invalid argument error is reported on the line the method is called. Upon closer inspection, it is found that the method is sometimes called with a String value.&lt;/p&gt;

&lt;p&gt;The quickest commit to write would be something along the lines of "Fix method call", but this commit without a message doesn't explain the actual problem.&lt;/p&gt;

&lt;p&gt;A commit should explain the situation that causes the error⁠—some user input isn't cast to an Integer⁠. And how it was fixed⁠—the controller action "update" will now cast the user input to an Integer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Subject&lt;/span&gt;
Fix Ticket#set_priority being called with Strings

&lt;span class="gh"&gt;# The Scenario&lt;/span&gt;
When Ticket#set_priority was called from the TicketsController the priority
value was sometimes a String type. This caused an &lt;span class="sb"&gt;`InvalidArgumentError`&lt;/span&gt;:

InvalidArgumentError: Invalid argument type given &lt;span class="sb"&gt;`String`&lt;/span&gt;, expected &lt;span class="sb"&gt;`Integer`&lt;/span&gt;
  1: from /app/lib/models/ticket.ext:23 in &lt;span class="sb"&gt;`set_priority`&lt;/span&gt;
  2: from /app/lib/controllers/tickets_controller.ext:45 in &lt;span class="sb"&gt;`update`&lt;/span&gt;

&lt;span class="gh"&gt;# How&lt;/span&gt;
The &lt;span class="sb"&gt;`user_params`&lt;/span&gt; method will now cast all &lt;span class="sb"&gt;`priority`&lt;/span&gt; params to an Integer
before sending it to the Ticket model.

&lt;span class="gh"&gt;# Alternatives&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Colleague&lt;/span&gt; &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; and I chose to cast it to an Integer in the &lt;span class="sb"&gt;`user_params`&lt;/span&gt;
method so that all other actions in the controller can also be able to use
this logic. This way, not all the methods need to implement their own casting,
making for a more fragile setup, something that's easy to miss when a new
action is added.
This allows us to clean up the &lt;span class="sb"&gt;`new`&lt;/span&gt; and &lt;span class="sb"&gt;`create`&lt;/span&gt; methods as well.

We didn't want to move the casting to the &lt;span class="sb"&gt;`set_priority`&lt;/span&gt; method because this
controller is the only place it can ever be called with a String.

&lt;span class="gh"&gt;# Additional sources&lt;/span&gt;
Fixes #1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Communication in Pull Requests
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Format
&lt;/h3&gt;

&lt;p&gt;When a Pull Request on GitHub is created with only one commit, it prefills the Pull Request title and description with the commit subject and message. This is not by accident. This way, the important information of the Pull Request is right there at the top. That's not to say that a good Pull Request only has one commit, oh no, but it does help a lot with creating smaller Pull Requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zHeQ_TXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2020-06/git-communication/pr_with_single_commit_example.jpg" class="article-body-image-wrapper"&gt;&lt;img alt="Example of Pull Request with a single commit" src="https://res.cloudinary.com/practicaldev/image/fetch/s--zHeQ_TXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2020-06/git-communication/pr_with_single_commit_example.jpg"&gt;&lt;/a&gt;&lt;br&gt;&lt;p class="text-center"&gt;Example of Pull Request with a single commit&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/p&gt;

&lt;p&gt;If a Pull Request has multiple commits, I advise you to use the same format. Repeating &lt;strong&gt;all&lt;/strong&gt; the commits in the Pull Request's description as separate headings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KKOpXmL2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2020-06/git-communication/pr_with_multiple_commits_example.jpg" class="article-body-image-wrapper"&gt;&lt;img alt="Example of Pull Request with multiple commits" src="https://res.cloudinary.com/practicaldev/image/fetch/s--KKOpXmL2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2020-06/git-communication/pr_with_multiple_commits_example.jpg"&gt;&lt;/a&gt;&lt;br&gt;&lt;p class="text-center"&gt;Example of Pull Request with multiple commits&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/p&gt;

&lt;p&gt;I use the important commit's subject as the Pull Request title or write a brand new one if it helps identify all the combined changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Content
&lt;/h3&gt;

&lt;p&gt;There's very little additional context a Pull Request needs after a good title and description. Commits should contain the important bits of a Pull Request. If more context needs to be added to the Pull Request body, it should have been part of one of the commits.&lt;/p&gt;

&lt;p&gt;This also prevents a lot of back and forth between author and reviewers to explain the changes in a Pull Request, speeding up the review time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep Pull Requests Small
&lt;/h3&gt;

&lt;p&gt;If a set of changes start to become large and difficult to review, send in smaller chunks as Pull Requests early to get feedback on the changes. This way you know you're on the right track.&lt;/p&gt;

&lt;p&gt;If you find yourself refactoring code while working on a change, send in a separate Pull Request for the refactor if possible. This way, the Pull Requests are easier to review because their size is smaller and focus only on one type of change. Your team can get started reviewing the refactor while you work on finishing the other changes.&lt;/p&gt;

&lt;p&gt;Nobody truly likes to review Pull Requests with 20 commits or 20,000 line changes. It's difficult to find the important changes between all the noise.&lt;/p&gt;

&lt;p&gt;Also, make sure every Pull Request can be merged independently, so it doesn't have to stay open until the entire change is done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Present a Tidy History
&lt;/h3&gt;

&lt;p&gt;A reviewer doesn't need to experience the exact same process you went through to get to the final changes. If you first went for approach A and halfway through, switched to approach B, do not include both A and B, but only the final result. But &lt;em&gt;do&lt;/em&gt; document the alternatives and reasons why approach B was chosen in the commit message.&lt;/p&gt;

&lt;p&gt;Rebase your commits to present a tidy history with just the necessary changes. Nobody needs to see when you merged the upstream develop branch back into your branch. Or when you signed off for the day and committed all your changes into "WIP" to 'back it up' on a remote server. This is noise that hides changes in undescriptive commits, and why they were made.&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;# History as it was logged during development&lt;/span&gt;

&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;WIP&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Add&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;edit&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Merge&lt;/span&gt; &lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tracking&lt;/span&gt; &lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="s1"&gt;'origin/develop'&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Refactor&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Fix&lt;/span&gt; &lt;span class="n"&gt;tests&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="c1"&gt;# Tidy history ready for review&lt;/span&gt;

&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Refactor&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Add&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;edit&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any additional commits as a result of reviews are of course fine, as they &lt;em&gt;communicate&lt;/em&gt; the changes that were made as part of the review. Allowing reviewers to see what changes were made based on their feedback. (So no "Processed feedback" or "Update path/to/file.ext" commits.)&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;Git is about communicating with your team. Document why you made a change in your git commits. Your team, your future self, and your future colleague will thank you.&lt;/p&gt;

&lt;p&gt;Make sure all the context needed is present in commits and Pull Requests in terms of why a change was made, how and what alternatives there were.&lt;/p&gt;

&lt;p&gt;Improve Pull Request review turn around time by keeping them small. And make them better by understanding why a change was necessary and review it with that thought in mind.&lt;/p&gt;

</description>
      <category>git</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>management</category>
    </item>
    <item>
      <title>#to_s or #to_str? Explicitly casting vs. implicitly coercing types in Ruby</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Tue, 25 Sep 2018 12:52:55 +0000</pubDate>
      <link>https://dev.to/appsignal/tos-or-tostr-explicitly-casting-vs-implicitly-coercing-types-in-ruby-3ob6</link>
      <guid>https://dev.to/appsignal/tos-or-tostr-explicitly-casting-vs-implicitly-coercing-types-in-ruby-3ob6</guid>
      <description>&lt;p&gt;Type coercion is the changing of an object's type into another type, together with its value. For example, changing an Integer into a String with &lt;code&gt;#to_s&lt;/code&gt; or a Float into an Integer with &lt;code&gt;#to_i&lt;/code&gt;. The perhaps lesser-known &lt;code&gt;#to_str&lt;/code&gt; and &lt;code&gt;#to_int&lt;/code&gt; methods some objects implement do the same at first glance, but there are some differences.&lt;/p&gt;

&lt;p&gt;In this edition of AppSignal academy, we'll dive into explicitly casting and implicitly coercing types in Ruby, while briefy touching on typecasting actors. We'll cover the differences between both methods, and discuss how they're used.&lt;/p&gt;

&lt;p&gt;Let's first look at how we usually coerce values to different types in Ruby with explicit casting helpers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicit Casting Helpers
&lt;/h2&gt;

&lt;p&gt;The most common casting helpers are &lt;code&gt;#to_s&lt;/code&gt;, &lt;code&gt;#to_i&lt;/code&gt;, &lt;code&gt;#to_a&lt;/code&gt; and &lt;code&gt;#to_h&lt;/code&gt;. These are explicit casting methods. They help us easily transform a value from one type to another.&lt;/p&gt;

&lt;p&gt;The explicit helpers come with a clear promise. Whenever &lt;code&gt;#to_s&lt;/code&gt; is called on an object, it'll &lt;em&gt;always&lt;/em&gt; return a string, even if the object doesn't really convert to a string well. It's like casting Michael Keaton as Batman. You'll get a batman, even if a comedy actor isn't especially suited for the role.&lt;/p&gt;

&lt;p&gt;Ruby offers these helper methods on almost any basic object in the Ruby standard library.&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;:foo&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; "foo"&lt;/span&gt;
&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 10&lt;/span&gt;
&lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These methods, especially &lt;code&gt;#to_s&lt;/code&gt;, are implemented on most basic types in Ruby. While the casting almost always returns a value, the result may not be what we expect.&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;"foo10"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;          &lt;span class="c1"&gt;# =&amp;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="nf"&gt;to_s&lt;/span&gt;        &lt;span class="c1"&gt;# =&amp;gt; "[1, 2, 3]"&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:bar&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; "{:foo=&amp;gt;:bar}"&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:bar&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; [[:foo, :bar]]&lt;/span&gt;
&lt;span class="no"&gt;Object&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; "Object"&lt;/span&gt;
&lt;span class="no"&gt;Object&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="nf"&gt;to_s&lt;/span&gt;       &lt;span class="c1"&gt;# =&amp;gt; "#&amp;lt;Object:0x00007f8e6d053a90&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling the &lt;code&gt;#to_s&lt;/code&gt;, &lt;code&gt;#to_i&lt;/code&gt;, &lt;code&gt;#to_a&lt;/code&gt; and &lt;code&gt;#to_h&lt;/code&gt; helpers forces any value to the selected type. They return a representation of the type it's coerced to regardless of what happens to the value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implicit Coercion Methods
&lt;/h2&gt;

&lt;p&gt;Calling type casting methods on values that do not act like the type we are casting to can cause errors or loss of data. Ruby also offers implicit coercion methods which only return a value when objects act like the type. This way we can be sure that the value acts like the type we want. These implicit coercion methods are &lt;code&gt;#to_str&lt;/code&gt;, &lt;code&gt;#to_int&lt;/code&gt;, &lt;code&gt;#to_ary&lt;/code&gt; and &lt;code&gt;#to_hash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Implicit coercion is like casting Leonard Nimoy as any role but Spock. They'll work if the character is close enough to Spock, but fail if they're not. The &lt;code&gt;#to_str&lt;/code&gt; helper &lt;em&gt;tries&lt;/em&gt; to convert to a string, but will raise a &lt;code&gt;NoMethodError&lt;/code&gt; if the object doesn't implement the method and can't be implicitly coerced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_int&lt;/span&gt;                           &lt;span class="c1"&gt;# =&amp;gt; 10&lt;/span&gt;
&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_int&lt;/span&gt;                         &lt;span class="c1"&gt;# =&amp;gt; 10&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"bigdecimal"&lt;/span&gt;
&lt;span class="no"&gt;BigDecimal&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="s2"&gt;"10.0000123"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_int&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 10&lt;/span&gt;

&lt;span class="c1"&gt;# Unsuccessful coercions&lt;/span&gt;
&lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_int&lt;/span&gt;             &lt;span class="c1"&gt;# =&amp;gt; NoMethodError&lt;/span&gt;
&lt;span class="s2"&gt;"foo10"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_int&lt;/span&gt;          &lt;span class="c1"&gt;# =&amp;gt; NoMethodError&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="nf"&gt;to_str&lt;/span&gt;        &lt;span class="c1"&gt;# =&amp;gt; NoMethodError&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;to_str&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; NoMethodError&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;to_ary&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; NoMethodError&lt;/span&gt;
&lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_str&lt;/span&gt;           &lt;span class="c1"&gt;# =&amp;gt; NoMethodError&lt;/span&gt;
&lt;span class="no"&gt;Object&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="nf"&gt;to_str&lt;/span&gt;       &lt;span class="c1"&gt;# =&amp;gt; NoMethodError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that Ruby is a bit more strict now in what it does and doesn't coerce to the requested types. If the coercion is not possible, the &lt;code&gt;#to_*&lt;/code&gt; method is not implemented on the object and calling it raises a &lt;code&gt;NoMethodError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When using implicit coercions, e.g. &lt;code&gt;#to_str&lt;/code&gt;, we ask the function to return a String object, only if the original type also acts like a String. For this reason, &lt;code&gt;#to_str&lt;/code&gt; is only implemented on String in the Ruby Standard Library.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Ruby Uses Implicit Coercion
&lt;/h3&gt;

&lt;p&gt;Other than being more precise in what we're asking for during a coercion, what else is implicit coercion useful for? Turns out Ruby uses implicit coercions itself in a fair bit of scenarios. For instance, when combining objects with &lt;code&gt;+&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"world!"&lt;/span&gt;
&lt;span class="s2"&gt;"Hello "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "Hello world!"&lt;/span&gt;

&lt;span class="c1"&gt;# Without #to_str&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Name&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="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="s2"&gt;"Hello "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;Name&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="s2"&gt;"world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; TypeError: no implicit conversion of Name into String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we see Ruby raise a &lt;code&gt;TypeError&lt;/code&gt; since it can't do an implicit conversion from the &lt;code&gt;Name&lt;/code&gt; type to a &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we implement &lt;code&gt;#to_str&lt;/code&gt; on the class, Ruby knows how to coerce the &lt;code&gt;Name&lt;/code&gt; type.&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;# With #to_str&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Name&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_str&lt;/span&gt;
    &lt;span class="vi"&gt;@name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="s2"&gt;"Hello "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;Name&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="s2"&gt;"world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "Hello world!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same works for Arrays and &lt;code&gt;#to_ary&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Options&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@internal&lt;/span&gt; &lt;span class="o"&gt;=&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;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@internal&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;value&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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Options&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;options&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:some_prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; TypeError: no implicit conversion of Options into Array&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Options&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_ary&lt;/span&gt;
    &lt;span class="vi"&gt;@internal&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="ss"&gt;:some_prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; [:some_prefix, :foo]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But &lt;code&gt;#to_ary&lt;/code&gt; is used in more scenarios. We can use it to destructure an Array into separate variables.&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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Options&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;options&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:first&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:second&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:third&lt;/span&gt;
&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;third&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;
&lt;span class="n"&gt;first&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; :first&lt;/span&gt;
&lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; :second&lt;/span&gt;
&lt;span class="n"&gt;third&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; :third&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also does conversion of the object into block 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="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; :first&lt;/span&gt;
  &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; :second&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are more scenarios where the implicit coercion methods are used, such as &lt;code&gt;#to_hash&lt;/code&gt; with &lt;code&gt;**&lt;/code&gt;. This coerces the value to a hash with &lt;code&gt;#to_hash&lt;/code&gt; before passing it to the &lt;code&gt;parse_options&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;class&lt;/span&gt; &lt;span class="nc"&gt;Options&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_hash&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a hash from the Options Array&lt;/span&gt;
    &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="vi"&gt;@internal&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Options&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;options&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:key&lt;/span&gt;
&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ss"&gt;:value&lt;/span&gt;
&lt;span class="n"&gt;parse_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; {:key=&amp;gt;:value}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enforcing Types
&lt;/h2&gt;

&lt;p&gt;Ruby also offers more resilient coercion methods when the type is of an unknown type and we want to make sure we get the correct type. There's one for every basic type (&lt;a href="http://ruby-doc.org/core-2.5.1/Kernel.html#method-i-String"&gt;&lt;code&gt;String(...)&lt;/code&gt;&lt;/a&gt;, &lt;a href="http://ruby-doc.org/core-2.5.1/Kernel.html#method-i-Integer"&gt;&lt;code&gt;Integer(...)&lt;/code&gt;&lt;/a&gt;, &lt;a href="http://ruby-doc.org/core-2.5.1/Kernel.html#method-i-Float"&gt;&lt;code&gt;Float(...)&lt;/code&gt;&lt;/a&gt;, &lt;a href="http://ruby-doc.org/core-2.5.1/Kernel.html#method-i-Array"&gt;&lt;code&gt;Array(...)&lt;/code&gt;&lt;/a&gt;, &lt;a href="http://ruby-doc.org/core-2.5.1/Kernel.html#method-i-Hash"&gt;&lt;code&gt;Hash(...)&lt;/code&gt;&lt;/a&gt;, etc.).&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;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# =&amp;gt; "main"&lt;/span&gt;
&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "Object"&lt;/span&gt;
&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123456&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# =&amp;gt; "123456"&lt;/span&gt;
&lt;span class="no"&gt;String&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="c1"&gt;# =&amp;gt; ""&lt;/span&gt;

&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;123.999&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; 123&lt;/span&gt;
&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"0x1b"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# =&amp;gt; 27&lt;/span&gt;
&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Time&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="c1"&gt;# =&amp;gt; 1204973019&lt;/span&gt;
&lt;span class="no"&gt;Integer&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="c1"&gt;# =&amp;gt; TypeError: can't convert nil into Integer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;String(...)&lt;/code&gt; method first tries to call &lt;code&gt;#to_str&lt;/code&gt; on the value, and when that fails, it calls its &lt;code&gt;#to_s&lt;/code&gt; method. Not all objects define a &lt;code&gt;#to_str&lt;/code&gt; method, therefore checking with both the implicit coercion (&lt;code&gt;#to_str&lt;/code&gt;) and explicit (&lt;code&gt;#to_s&lt;/code&gt;) casting methods increases the chances that the String conversion will work and you'll get the value you want. By first calling for implicit coercion we're more likely to get a result that has the same value but is of the coerced type, and not something like &lt;code&gt;"#&amp;lt;Object:0x00007f8e6d053a90&amp;gt;"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyString&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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&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;to_str&lt;/span&gt;
    &lt;span class="vi"&gt;@value&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;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyString&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="s2"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&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; "#&amp;lt;MyString:0x...&amp;gt;"&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_str&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; "hello world"&lt;/span&gt;
&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "hello world"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should only implement the implicit casting methods for objects that act like the to be coerced type, e.g. &lt;code&gt;#to_str&lt;/code&gt; for your own String class.&lt;/p&gt;

&lt;p&gt;Other than first trying implicit coercion, the &lt;code&gt;String(...)&lt;/code&gt; helper also checks the returned type. &lt;code&gt;#to_str&lt;/code&gt; is just a method which can return any type of value, even non-Strings. To ensure we get a value of the requested type &lt;code&gt;String(...)&lt;/code&gt; raises a &lt;code&gt;TypeError&lt;/code&gt; if the types don't match.&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;MyString&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_str&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="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyString&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="s2"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&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; "#&amp;lt;MyString:0x...&amp;gt;"&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_str&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "#&amp;lt;MyString:0x...&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can see that Ruby ignores the result of &lt;code&gt;#to_str&lt;/code&gt; because it returned &lt;code&gt;nil&lt;/code&gt;, which is not of the String-type. Instead, it falls back to the &lt;code&gt;#to_s&lt;/code&gt; result.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;#to_s&lt;/code&gt; also returns &lt;code&gt;nil&lt;/code&gt; and thus isn't of the correct type, &lt;code&gt;String(...)&lt;/code&gt; will raise a &lt;code&gt;TypeError&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyString&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_str&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;def&lt;/span&gt; &lt;span class="nf"&gt;to_s&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="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyString&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="s2"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&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; nil&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_str&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; TypeError: can't convert MyString to String (MyString#to_s gives NilClass)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While they may be more reliable in enforcing type coercion, note that the casting helper methods (&lt;code&gt;String(...)&lt;/code&gt;, &lt;code&gt;Integer(...)&lt;/code&gt;, etc.) are usually a bit slower as they need to perform more checks on the given value.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;When you want to make sure you're dealing with the right type of data for an object, type coercion is a useful process. In this post, we refreshed our knowledge of explicit casting helpers like &lt;code&gt;#to_s&lt;/code&gt;, &lt;code&gt;#to_i&lt;/code&gt;, &lt;code&gt;#to_a&lt;/code&gt; and &lt;code&gt;#to_h&lt;/code&gt;. We also looked at instances when implicit helpers like &lt;code&gt;#to_str&lt;/code&gt;, &lt;code&gt;#to_int&lt;/code&gt;, &lt;code&gt;#to_ary&lt;/code&gt; and &lt;code&gt;#to_hash&lt;/code&gt; are useful and how they're used by Ruby itself.&lt;/p&gt;

&lt;p&gt;We hope you found this type coercion overview useful and how you found the actor typecasting analogy. As always, let us know if there's a topic you'd like us to cover. If you have any questions or comments, don't hesitate to leave a comment.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>beginners</category>
      <category>programming</category>
      <category>learning</category>
    </item>
    <item>
      <title>Rails Collection Caching</title>
      <dc:creator>Tom de Bruijn</dc:creator>
      <pubDate>Tue, 14 Aug 2018 14:12:39 +0000</pubDate>
      <link>https://dev.to/appsignal/rails-collection-caching-1oed</link>
      <guid>https://dev.to/appsignal/rails-collection-caching-1oed</guid>
      <description>&lt;p&gt;We've previously looked at &lt;a href="https://blog.appsignal.com/2018/03/20/fragment-caching-in-rails.html"&gt;fragment caching in Rails&lt;/a&gt; on AppSignal Academy. This greatly improves the performance of views by caching smaller pieces of them. When caching partials, we have the added benefit of being able to reuse them elsewhere in our views at little cost.&lt;/p&gt;

&lt;p&gt;This works well for small collections, but problems quickly arise on larger collections. In this article, we'll take a look at how Rails collection caching works and how we can use it to speed up the rendering of a large collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering a Collection
&lt;/h2&gt;

&lt;p&gt;Let's start with a small controller that loads the last 100 posts for our blog's index page.&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;PostsController&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;index&lt;/span&gt;
    &lt;span class="vi"&gt;@posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:created_at&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:desc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&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;To render these posts in the view, we loop over the &lt;code&gt;@posts&lt;/code&gt; instance variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/views/posts/index.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Posts&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&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;post&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;author&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon requesting this page, we see the posts being fetched from the database and the view being rendered. With only 32 milliseconds spent in the view layer, this page is pretty fast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.5ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
  Rendered posts/index.html.erb within layouts/application (19.4ms)
Completed 200 OK in 37ms (Views: 32.4ms | ActiveRecord: 2.7ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rendering a Collection with Partials
&lt;/h2&gt;

&lt;p&gt;Next, we want to use the &lt;code&gt;post&lt;/code&gt; element in another view, so we move the post HTML to a partial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/views/posts/index.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Posts&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&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;post&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- app/views/posts/_post.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;author&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.2ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
...
  Rendered posts/_post.html.erb (0.1ms)
  Rendered posts/_post.html.erb (0.1ms)
  Rendered posts/index.html.erb within layouts/application (205.4ms)
Completed 200 OK in 217ms (Views: 213.8ms | ActiveRecord: 1.7ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With 213 milliseconds spent on the view layer, you can see that the render time has increased substantially. This is because a new file (the partial) needs to be loaded, compiled and rendered for every post. Let's briefly look at how we can improve the render time with fragment caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fragment Caching
&lt;/h2&gt;

&lt;p&gt;As described in the &lt;a href="https://blog.appsignal.com/2018/03/20/fragment-caching-in-rails.html"&gt;fragment caching&lt;/a&gt; article, we'll use the &lt;code&gt;cache&lt;/code&gt; helper in the view around the &lt;code&gt;render&lt;/code&gt; call. In this way, we'll cache the rendering of the partial for every post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/views/posts/index.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Posts&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&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;post&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index_with_partial_caching.html.erb within layouts/application
  Post Load (1.4ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
...
Read fragment views/posts/index.1ms)
  Rendered posts/_post.html.erb (0.1ms)
Write fragment views/posts/index.1ms)
Read fragment views/posts/index.5ms)
  Rendered posts/_post.html.erb (0.1ms)
Write fragment views/posts/index.1ms)
  Rendered posts/index.html.erb within layouts/application (274.5ms)
Completed 200 OK in 286ms (Views: 281.4ms | ActiveRecord: 2.4ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first request won't be that much faster, because it still needs to render every partial the first time around and store it in the cache store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (2.2ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
...
Read fragment views/posts/index.1ms)
Read fragment views/posts/index.1ms)
  Rendered posts/index.html.erb within layouts/application (63.8ms)
Completed 200 OK in 78ms (Views: 75.5ms | ActiveRecord: 2.2ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In subsequent requests, we see that the time spent in the view is considerably lower - from 286 milliseconds down to 78 milliseconds. Yet, it's still a lot slower than what we got with our original code - it's almost twice as slow.&lt;/p&gt;

&lt;p&gt;Note: If you're not seeing the "Read/Write fragment" lines in your logs, be sure to enable fragment cache logging in your development environment, which is set to &lt;code&gt;false&lt;/code&gt; by default on Rails 5.1 and above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# config/environments/development.rb
config.action_controller.enable_fragment_cache_logging = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Collection Caching
&lt;/h2&gt;

&lt;p&gt;In Rails 5, a lot of work was done to make collection caching faster. To leverage these improvements, we'll need to change our view code. Instead of calling the &lt;code&gt;cache&lt;/code&gt; helper ourselves, we can ask Rails to render an entire collection and cache it at the same time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app/views/posts/index.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Posts&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;partial: :post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;collection: &lt;/span&gt;&lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;cached: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;render @collection, cached: true&lt;/code&gt; shorthand won't work for this caching speed improvement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.4ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
  Rendered collection of posts/_post.html.erb [0 / 100 cache hits] (28.2ms)
  Rendered posts/index.html.erb within layouts/application (46.6ms)
Completed 200 OK in 64ms (Views: 59.9ms | ActiveRecord: 2.0ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the first request, we can already see a large improvement in time spent on the view layer. This is because Rails now prepares in advance, the partial being used for the entire collection, rather than for each post separately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.3ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
  Rendered collection of posts/_post.html.erb [100 / 100 cache hits] (19.2ms)
  Rendered posts/index.html.erb within layouts/application (26.5ms)
Completed 200 OK in 37ms (Views: 35.7ms | ActiveRecord: 1.3ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In subsequent requests, we see even more improvement - from 64 milliseconds down to about 35 milliseconds. A big speed improvement for the entire collection is made here by Rails optimization for collections. Instead of checking the availability of a cache for every partial, Rails checks all cache keys of the collection at the same time, saving time querying the &lt;a href="https://blog.appsignal.com/2018/04/17/rails-built-in-cache-stores.html"&gt;cache store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An added benefit of this caching helper is the summarized logging of the collection. In the first request, none of the cache keys were found &lt;code&gt;[0 / 100 cache hits]&lt;/code&gt;, but in the second request, they were all found &lt;code&gt;[100 / 100 cache hits]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After updating some of the objects in the database, we can even see how many keys were stale.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rendered collection of posts/_post.html.erb [88 / 100 cache hits] (13.4ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's much speed improvement to gain with this optimized collection rendering and caching. An even bigger difference will be made when rendering larger collections. Unless you need customized views for your collection, this optimized strategy is the way to go for your Rails apps. At AppSignal, we managed to significantly speed up one of our admin views that was rendering thousands of records, in this way.&lt;/p&gt;

&lt;p&gt;Have any questions about caching collections in Rails? Please don’t hesitate to leave a comment! If you have any comments regarding the article or if you have any topics that you'd like us to cover, then please get in touch with us.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>caching</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
