<?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: Matias Salles</title>
    <description>The latest articles on DEV Community by Matias Salles (@matiassalles99).</description>
    <link>https://dev.to/matiassalles99</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%2F3825853%2F8c8a484e-e6f5-436b-b077-cce47204b5be.jpeg</url>
      <title>DEV Community: Matias Salles</title>
      <link>https://dev.to/matiassalles99</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matiassalles99"/>
    <language>en</language>
    <item>
      <title>Building a NES Emulator from Scratch: The Book (Crystal)</title>
      <dc:creator>Matias Salles</dc:creator>
      <pubDate>Sun, 22 Mar 2026 17:23:41 +0000</pubDate>
      <link>https://dev.to/matiassalles99/building-a-nes-emulator-from-scratch-the-book-crystal-3i4o</link>
      <guid>https://dev.to/matiassalles99/building-a-nes-emulator-from-scratch-the-book-crystal-3i4o</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/matiassalles99/crystal-the-language-i-didnt-know-i-needed-4bi1"&gt;last post&lt;/a&gt; I mentioned I'd spent a few months writing a book about building a NES emulator from scratch. Well, it's done. And I want to tell you about it, because I think the journey from "I wonder how emulators work" to "I wrote a 280-page book about it" is kind of ridiculous and worth sharing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we got here
&lt;/h2&gt;

&lt;p&gt;It started, as most bad decisions do, at 2 AM. I was playing Mario Bros in a browser emulator, died in world 2-3, and instead of going to sleep like a normal person, I started wondering how the emulator worked. A few weeks later I had a working emulator in Crystal running at 60 FPS. A few months after that, I had a book.&lt;/p&gt;

&lt;p&gt;The thing is, while building the emulator I kept thinking: "I wish someone had explained this to me step by step." The NES Wiki is incredible but dense. YouTube tutorials assume you already know C and have opinions about memory allocation strategies. I wanted something that started from zero and built up piece by piece, with code first and theory after.&lt;/p&gt;

&lt;p&gt;So I wrote that thing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkx2pz3r85mgy2kjcomq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkx2pz3r85mgy2kjcomq.gif" alt="fine I'll do it myself" width="299" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the book
&lt;/h2&gt;

&lt;p&gt;You start with a CPU that can't do anything. Literally nothing. Then you teach it to load a number into a register. Then to add. Then to jump. By the end you have all 151 instructions of the 6502 processor implemented, a PPU that renders pixels, an APU that generates audio, and you're playing Super Mario Bros.&lt;/p&gt;

&lt;p&gt;Here's the full roadmap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chapters 1-2:&lt;/strong&gt; NES architecture overview + Crystal setup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 3 (7 sub-chapters):&lt;/strong&gt; The entire 6502 CPU, all 151 opcodes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 4:&lt;/strong&gt; Cartridge parsing, iNES format, Mapper 0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 5 (6 sub-chapters):&lt;/strong&gt; PPU, SDL2 GUI, background rendering, sprites, scroll&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 6:&lt;/strong&gt; Plugging in real games and watching them run&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chapter 7:&lt;/strong&gt; APU, generating audio with square, triangle and noise waves&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appendix:&lt;/strong&gt; Mapper 1 (MMC1) for games like Zelda and Mega Man 2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing is written in Crystal, which if you know Ruby you basically already know. No C, no emulation libraries. Just you, a text editor, and 20,000 virtual transistors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let me show you what I mean
&lt;/h2&gt;

&lt;p&gt;The best way to explain the book's approach is to show you some actual code from it. Let's look at how the CPU works.&lt;/p&gt;

&lt;p&gt;The CPU has registers (tiny pieces of memory inside the chip), a program counter that tracks where we are in the code, and a &lt;code&gt;step&lt;/code&gt; method that fetches the next opcode and executes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# src/nes/cpu.cr&lt;/span&gt;

&lt;span class="n"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;UInt8&lt;/span&gt;   &lt;span class="c1"&gt;# Accumulator&lt;/span&gt;
&lt;span class="n"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;UInt8&lt;/span&gt;   &lt;span class="c1"&gt;# X register&lt;/span&gt;
&lt;span class="n"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;UInt8&lt;/span&gt;   &lt;span class="c1"&gt;# Y register&lt;/span&gt;
&lt;span class="n"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;UInt8&lt;/span&gt;   &lt;span class="c1"&gt;# Stack Pointer&lt;/span&gt;
&lt;span class="n"&gt;property&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;UInt16&lt;/span&gt;  &lt;span class="c1"&gt;# Program Counter&lt;/span&gt;
&lt;span class="n"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;UInt8&lt;/span&gt;   &lt;span class="c1"&gt;# Flags (Zero, Negative, Carry, etc.)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;step&lt;/span&gt;
  &lt;span class="n"&gt;opcode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_byte&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;opcode&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;CODE_LDA_IMMEDIATE&lt;/span&gt;   &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;op_lda_immediate&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;CODE_LDA_ZERO_PAGE&lt;/span&gt;   &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;op_lda_zero_page&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;CODE_LDA_ABSOLUTE&lt;/span&gt;    &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;op_lda_absolute&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;CODE_LDA_ABSOLUTE_X&lt;/span&gt;  &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;op_lda_absolute_x&lt;/span&gt;
  &lt;span class="c1"&gt;# ... STA, LDX, LDY, ADC, SBC, JMP, branches ...&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;CODE_INX&lt;/span&gt;             &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;op_inx&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;CODE_NOP&lt;/span&gt;             &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;op_nop&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;UnknownOpcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opcode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="no"&gt;CYCLES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;opcode&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;That's the whole CPU. Fetch a byte, match it against 151 opcodes, execute the right method, return how many cycles it took. The giant &lt;code&gt;case&lt;/code&gt; statement looks intimidating at first, but each instruction is just a few lines.&lt;/p&gt;

&lt;p&gt;Let's zoom into one. Every NES instruction has an &lt;strong&gt;opcode&lt;/strong&gt;, a number that tells the CPU what to do. When the CPU reads &lt;code&gt;0xA9&lt;/code&gt; from memory, it knows it has to run LDA (Load Accumulator) in immediate mode:&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;# src/nes/cpu/instructions/lda.cr&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lda&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;@a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

  &lt;span class="n"&gt;set_z_flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;set_n_flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@a&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;op_lda_immediate&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;fetch_byte&lt;/span&gt;
  &lt;span class="n"&gt;lda&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read a byte, put it in register A, update the flags. That's it. The &lt;code&gt;lda&lt;/code&gt; method is reusable across all 8 addressing modes, each one just resolves the address differently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;op_lda_zero_page&lt;/span&gt;
  &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address_zero_page&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;read_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;lda&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;def&lt;/span&gt; &lt;span class="nf"&gt;op_lda_absolute&lt;/span&gt;
  &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address_absolute&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;read_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;lda&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="c1"&gt;# ... and so on for all 8 modes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the pattern? Once you implement one instruction family, the rest follow the same structure. The book shows you a few in detail, you implement 10-15 yourself to really internalize how the CPU works, and then you grab the rest from the repo. No one needs to hand-type 151 opcodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that blew my mind: the PPU
&lt;/h2&gt;

&lt;p&gt;The CPU is satisfying to build, but the PPU is where things get wild. The NES draws an entire screen with 2KB of RAM. Two kilobytes. Your average email is bigger than that.&lt;/p&gt;

&lt;p&gt;The PPU (Picture Processing Unit) is a separate chip that runs 3 times faster than the CPU and has its own memory. It draws the screen scanline by scanline, 256x240 pixels, 60 times per second. The book walks you through it step by step: first a black screen, then the background, then sprites, then scroll. Each chapter adds one layer and you can &lt;em&gt;see&lt;/em&gt; the progress on screen.&lt;/p&gt;

&lt;p&gt;When Mario's title screen showed up for the first time, I just sat there staring at it for a good minute. And then I pressed Start and nothing happened because of a missing feature called sprite 0 hit (in the book I'll tell you all about it). Classic.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The emulation loop
&lt;/h2&gt;

&lt;p&gt;Maybe my favorite part of the whole emulator is how simple the core loop is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;step&lt;/span&gt;
  &lt;span class="n"&gt;cycles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles&lt;/span&gt; &lt;span class="o"&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;times&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vi"&gt;@ppu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="vi"&gt;@apu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cycles&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines. The CPU executes one instruction and tells you how many cycles it took. The PPU runs 3 times as fast (that's the real hardware ratio). The APU keeps up. That's the entire emulation loop. Everything else is just implementing the details behind each &lt;code&gt;.step&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Play it right now
&lt;/h2&gt;

&lt;p&gt;I compiled the emulator to WebAssembly so you can play it in your browser. No downloads, no setup. Just pick a game and go:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://emulator.matiassalles99.codes" rel="noopener noreferrer"&gt;emulator.matiassalles99.codes&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fair warning: you might lose an hour. I sure did while "testing" it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Get the book
&lt;/h2&gt;

&lt;p&gt;The book is available in both English and Spanish on Leanpub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🇬🇧 &lt;strong&gt;English:&lt;/strong&gt; &lt;a href="https://leanpub.com/nes-emulator-en" rel="noopener noreferrer"&gt;Building Your First Emulator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🇪🇸 &lt;strong&gt;Español:&lt;/strong&gt; &lt;a href="https://leanpub.com/nes-emulator-sp" rel="noopener noreferrer"&gt;Construí tu Primer Emulador&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both versions include a &lt;strong&gt;free sample&lt;/strong&gt; that covers the introduction, NES architecture, setup, and the first coding chapter where you build the CPU skeleton and implement your first two instructions. That's enough to know if the book is for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you know Ruby, Python, or any similar language, you can follow along. Crystal reads almost exactly like Ruby, and the book doesn't assume any knowledge of emulation or retro hardware.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Who is this for?
&lt;/h2&gt;

&lt;p&gt;Honestly? Any programmer who's ever been curious about what happens below the abstraction layers we work on every day. You don't need to know anything about emulation, hardware, or assembly.&lt;/p&gt;

&lt;p&gt;But it's especially for people like me: web developers who spend all day in Rails or React and sometimes wonder what a CPU actually &lt;em&gt;does&lt;/em&gt; when it runs our code. If you're curious about that side of things, I also &lt;a href="https://dev.to/matiassalles99/building-a-4-bit-cpu-with-integrated-circuits-and-breadboards-24ek"&gt;built a 4-bit CPU on breadboards&lt;/a&gt; a while back.&lt;/p&gt;

&lt;p&gt;It's also not a reference manual. It's informal, opinionated, and occasionally self-deprecating. I wrote it the way I'd explain things to a friend over coffee (or beer, depending on the chapter).&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I have a few more side projects lined up that I'll be building in Crystal. The language has been a revelation for anything that needs real performance but where I don't want to leave Ruby's syntax behind. I'll keep writing about them here.&lt;/p&gt;

&lt;p&gt;If you end up building the emulator, playing the web version, or reading the book, I'd love to hear about it. Drop me a message, open an issue, whatever works.&lt;/p&gt;

&lt;p&gt;Now if you'll excuse me, I need to go beat world 2-3.&lt;/p&gt;

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

</description>
      <category>coding</category>
      <category>emulation</category>
    </item>
    <item>
      <title>Crystal: The Language I Didn't Know I Needed</title>
      <dc:creator>Matias Salles</dc:creator>
      <pubDate>Sun, 01 Mar 2026 17:23:41 +0000</pubDate>
      <link>https://dev.to/matiassalles99/crystal-the-language-i-didnt-know-i-needed-4bi1</link>
      <guid>https://dev.to/matiassalles99/crystal-the-language-i-didnt-know-i-needed-4bi1</guid>
      <description>&lt;p&gt;How I discovered Crystal while building a NES emulator in Ruby, and why this compiled language with Ruby-like syntax became my go-to for performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F569s7pqmsusi2m5b3g6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F569s7pqmsusi2m5b3g6o.png" alt="Crystal the Programming Language Logo" width="672" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few months ago I was searching "Mario Bros NES online" at 2 AM. Pure nostalgia. As a kid I used to play that game at my grandparents' house because they had nothing else installed on their PC. I knew all the warps, the infinite lives trick in 3-1, the whole deal.&lt;/p&gt;

&lt;p&gt;I found an emulator, played for 15 minutes, died in world 2-3 as always, and closed the tab. But something stuck with me: how hard is it to code one of these?&lt;/p&gt;

&lt;p&gt;I'd always been fascinated by the idea of virtual machines, how you can emulate a bunch of machines inside your own hardware. I didn't think it was black magic, but I'd never actually looked at emulator code before. What does it even mean, in code terms, to emulate a console? A lot of assembly? I had no idea.&lt;/p&gt;

&lt;p&gt;So after playing I went down a rabbit hole: YouTube tutorials about the NES, reading the &lt;a href="https://www.nesdev.org/wiki/Nesdev_Wiki" rel="noopener noreferrer"&gt;NES Wiki&lt;/a&gt;, trying to understand the architecture. And then I started coding the CPU, since that's what I felt I understood best from my brief research. It helped that I'd &lt;a href="https://dev.to%20post_url%202024-06-18-4bit-cpu%20"&gt;built half of a 4-bit CPU using breadboards&lt;/a&gt; back in college, so I had a rough idea of what a CPU involves: registers, ALU, flags, the whole thing.&lt;/p&gt;

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

&lt;p&gt;I haven't touched C or C++ since college, and the YouTube guys building NES emulators are like 100 times smarter than me when it comes to emulation. So I went with Ruby, the language I use every day and know inside out. My goal was to &lt;em&gt;understand how emulation works&lt;/em&gt;, not to fight with pointers I haven't thought about in years.&lt;/p&gt;

&lt;p&gt;So I started, and as soon as I had 10 instructions implemented I was hooked. There's something about emulation that feels like you're touching hardware without actually touching it. Plus, testing individual instructions by writing tiny 5-instruction assembly programs is a refreshing break from web dev.&lt;/p&gt;

&lt;p&gt;After a few days I finished the CPU and moved on to the PPU (Picture Processing Unit). Once that was done (took me about 2 weeks, and that was during the holiday break), I ran Mario, hit Enter to start the game and ... 🥁🥁🥁&lt;/p&gt;

&lt;p&gt;Nothing.&lt;/p&gt;

&lt;p&gt;It was stuck on the loading screen.&lt;/p&gt;

&lt;p&gt;I Spent another 2 days debugging until I gave up and went to cook something. When I came back, there it was. World 1-1 had somehow loaded while I was gone and Mario was just standing there. I pressed the arrow key and...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6vjsys48fmrignofgx3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6vjsys48fmrignofgx3.gif" alt="NES emulator running Super Mario Bros at 0.5 FPS in Ruby — Mario standing in World 1-1" width="622" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0.5 FPS.&lt;/strong&gt; Half a frame per second. Mario was practically a slideshow. That also explained why world 1-1 had taken about 10 minutes to load.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Search for a Faster Language
&lt;/h2&gt;

&lt;p&gt;So I started looking at alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go?&lt;/strong&gt; Cool, but pretty different from what I'm used to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust?&lt;/strong&gt; Same deal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C?&lt;/strong&gt; The obvious candidate, but that's exactly what I was trying to avoid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I kept asking ChatGPT for suggestions. At one point it mentioned Crystal, but I brushed it off because I confused it with Carbon (Google's supposed C++ replacement, remember that?).&lt;/p&gt;

&lt;p&gt;After asking like 700 times, even the AI got tired of throwing random languages at me and circled back to Crystal, this time really hammering the point that it was &lt;strong&gt;very similar to Ruby&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So I looked it up and...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bam #1:&lt;/strong&gt; It was made in Argentina 🇦🇷. Hold on, what?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bam #2:&lt;/strong&gt; The syntax was basically Ruby!&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;# This is valid Crystal AND valid Ruby&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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="k"&gt;end&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bam #3:&lt;/strong&gt; I rewrote everything I had in Crystal, ran the emulator, and it was doing &lt;strong&gt;120 FPS&lt;/strong&gt;. Mario went from slideshow to creatine. Same code, 240 times faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvfm2qdmb0avamfkch4u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvfm2qdmb0avamfkch4u.gif" alt="Flexing muscles — celebrating Crystal's 240x speed improvement over Ruby" width="388" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I capped it at 60 FPS and it ran perfectly.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What's Crystal?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;Crystal&lt;/a&gt; is a compiled, statically typed language with Ruby's syntax. It compiles to native code through LLVM, so you get C-like speeds. Quick rundown:&lt;/p&gt;

&lt;h3&gt;
  
  
  Static typing with inference
&lt;/h3&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; add type annotations, but Crystal infers most of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Matias"&lt;/span&gt;
&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;

&lt;span class="c1"&gt;# But you can be explicit when you want&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&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="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;
  &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler catches type errors before your code runs. No more &lt;code&gt;NoMethodError&lt;/code&gt; at 3 AM in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compiled to a single binary
&lt;/h3&gt;

&lt;p&gt;No runtime, no &lt;code&gt;bundle exec&lt;/code&gt;, no interpreter. You build it and ship it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crystal build app.cr &lt;span class="nt"&gt;--release&lt;/span&gt;
./app  &lt;span class="c"&gt;# done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  C interop out of the box
&lt;/h3&gt;

&lt;p&gt;You can call C libraries directly, which is great for things like SDL2 (graphics), audio libraries, or anything with a C API. I used this a lot for the emulator's GUI and audio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Macros instead of runtime metaprogramming
&lt;/h3&gt;

&lt;p&gt;Ruby has &lt;code&gt;define_method&lt;/code&gt;, &lt;code&gt;method_missing&lt;/code&gt;, all those runtime tricks we love. Crystal swaps most of that for compile-time macros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;define_getter&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="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;def&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="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="err"&gt;@&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="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;User&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="nf"&gt;ine_getter&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="nf"&gt;ine_getter&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different flavor, same idea. Zero runtime overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's great
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero learning curve if you know Ruby.&lt;/strong&gt; I was productive on day one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's fast.&lt;/strong&gt; My emulator renders frames, processes audio, and emulates a full 6502 CPU at 60 FPS without breaking a sweat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error messages are helpful.&lt;/strong&gt; The compiler tells you exactly what's wrong and where.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What could be better
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compile times&lt;/strong&gt; can be slow for larger projects. You miss Ruby's instant feedback sometimes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller ecosystem.&lt;/strong&gt; No Crystal equivalent for every Ruby gem. You'll sometimes write your own stuff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows support&lt;/strong&gt; is still catching up. Works great on macOS and Linux though.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;After finishing the emulator I spent a few months writing a book about building one from scratch, so anyone can get a taste of what emulation is about and step away from the web dev grind for a bit. If I could do it, you can too. I'll write about that in another post.&lt;/p&gt;

&lt;p&gt;Crystal is a language I plan to keep using for low-level side projects I have coming up, and I'd genuinely recommend it to any Ruby dev who wants to do something closer to the metal, whether that's emulation, audio, graphics, or anything where you need real performance and direct hardware access but don't want to leave Ruby's syntax behind.&lt;/p&gt;

&lt;p&gt;Shoutout to the folks at &lt;a href="https://manas.tech/" rel="noopener noreferrer"&gt;Manas&lt;/a&gt; for creating such a cool language, and saving me from having to rewrite everything in C!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can check out Crystal at &lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;crystal-lang.org&lt;/a&gt; and their &lt;a href="https://crystal-lang.org/reference/getting_started/" rel="noopener noreferrer"&gt;getting started guide&lt;/a&gt;. The language reference is excellent.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programminglanguages</category>
      <category>emulation</category>
    </item>
    <item>
      <title>Save Money on Heroku: Share One Database Across Multiple Apps</title>
      <dc:creator>Matias Salles</dc:creator>
      <pubDate>Thu, 07 Aug 2025 17:23:41 +0000</pubDate>
      <link>https://dev.to/matiassalles99/save-money-on-heroku-share-one-database-across-multiple-apps-486l</link>
      <guid>https://dev.to/matiassalles99/save-money-on-heroku-share-one-database-across-multiple-apps-486l</guid>
      <description>&lt;p&gt;Save money on Heroku by sharing one Postgres database across multiple apps. Step-by-step guide using schema_search_path for Rails developers.&lt;/p&gt;

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

&lt;p&gt;Hey!&lt;br&gt;
This one's going to be a short one, but hopefully useful to some of you out there.&lt;/p&gt;

&lt;p&gt;It’s been a while since Heroku announced the end of free dynos and database plans, but it’s still one of the best price/value platforms for deploying proof of concepts, staging environments, and personal projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wait… how?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They introduced a new Eco Dyno plan, a personal subscription for $7/month that gives you 1,000 hours to use across all your Heroku apps. Pretty neat!&lt;/p&gt;

&lt;p&gt;But what about the database?&lt;/p&gt;

&lt;p&gt;The cheapest plan for Heroku Postgres is $5/month, which doesn’t sound like much… until you have 10 staging apps running. That’s:&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;$5&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; 10 apps + &lt;span class="nv"&gt;$7&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;dyno&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$57&lt;/span&gt;/month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For apps you barely use and only access once every few weeks or months? Yeah, not ideal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if you could reuse a single DB across all your apps?
&lt;/h2&gt;

&lt;p&gt;This simple trick lets you run as many Heroku apps as you want for just $12/month, and it’s been super helpful for me.&lt;/p&gt;

&lt;p&gt;I run several proof of concepts, staging environments for projects I built for friends, &lt;a href="https://www.burnandstretch.studio/" rel="noopener noreferrer"&gt;my wife’s sports studio&lt;/a&gt; staging website, and even an old college final project that my friend and I still maintain to test small changes the company we built it for occasionally requests.&lt;/p&gt;

&lt;p&gt;Let’s walk through how to do this. I’ll show the example using Ruby on Rails, but the same idea applies to other frameworks too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-step: Share a single Heroku Postgres across apps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use schema_search_path in your database.yml
&lt;/h3&gt;

&lt;p&gt;In your Rails app, set the schema_search_path in config/database.yml like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_URL"] %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;schema_search_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_SCHEMA"] || "public" %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Rails to use a specific schema for this app, falling back to "public" if nothing is set.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update your Heroku app’s environment variables
&lt;/h3&gt;

&lt;p&gt;After deploying your app to Heroku, it may automatically provision a new database. Let it finish, then delete it.&lt;/p&gt;

&lt;p&gt;Now go to the app where your main Heroku Postgres addon lives, and copy its DATABASE_URL.&lt;/p&gt;

&lt;p&gt;Paste that into the DATABASE_URL of your other apps.&lt;/p&gt;

&lt;p&gt;Then, add a new environment variable:&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;DATABASE_SCHEMA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_schema_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I usually just set it to the app’s name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tntxe159yhttbw3kdic.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tntxe159yhttbw3kdic.gif" alt="Almost there — excited reaction as we're close to finishing the database setup" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Manually create the schema in the shared database
&lt;/h3&gt;

&lt;p&gt;Your deploy will likely fail at first, that’s expected! The schema doesn’t exist yet.&lt;/p&gt;

&lt;p&gt;Open the Heroku Postgres addon in the dashboard, grab the credentials, and connect using a tool like TablePlus or PgAdmin.&lt;/p&gt;

&lt;p&gt;From there, just create a new schema with the same name you used in &lt;code&gt;DATABASE_SCHEMA&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Release and deploy!
&lt;/h3&gt;

&lt;p&gt;Once the schema is in place, trigger a new release, and you’re done 🎉&lt;/p&gt;

&lt;p&gt;You just saved yourself $5/month, and the next time you do this, it'll be $10/month, then $15/month, and so on 💸&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚠️ Gotchas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If Heroku rotates the &lt;code&gt;DATABASE_URL&lt;/code&gt; for maintenance, you’ll need to update it in the other apps that don't have the addon directly attached.&lt;/li&gt;
&lt;li&gt;Aside from that, you're good!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🪄 Alternatives: Kamal and self-hosting
&lt;/h2&gt;

&lt;p&gt;If you're a Rails developer, you’ve probably heard about Kamal, it's been out for a few months now, and it’s awesome. It makes it really easy to deploy apps to virtual machines on AWS, Hetzner, DigitalOcean, etc.&lt;/p&gt;

&lt;p&gt;If you're not using AWS's 1-year free tier, you're probably looking at $8–12 per app/month, and that’s if you set up the DB as a Docker container yourself.&lt;/p&gt;

&lt;p&gt;If you use managed services like RDS, that might cost an extra ~$16/month, even if you reuse the same DB across apps 😬&lt;/p&gt;

&lt;p&gt;But here's something cool I might write about soon: You can use Kamal to deploy multiple apps on the same server, reducing costs even further.&lt;/p&gt;




&lt;p&gt;Thanks for reading! 😄&lt;/p&gt;

&lt;p&gt;Let me know if you end up using this trick — or if you’ve got others to share.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tebqy4aygbskd504c94.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tebqy4aygbskd504c94.gif" alt="Thank you wave — thanks for reading this Heroku tips post" width="478" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>devops</category>
    </item>
    <item>
      <title>Building a 4-bit CPU with integrated circuits and breadboards</title>
      <dc:creator>Matias Salles</dc:creator>
      <pubDate>Tue, 18 Jun 2024 17:23:41 +0000</pubDate>
      <link>https://dev.to/matiassalles99/building-a-4-bit-cpu-with-integrated-circuits-and-breadboards-24ek</link>
      <guid>https://dev.to/matiassalles99/building-a-4-bit-cpu-with-integrated-circuits-and-breadboards-24ek</guid>
      <description>&lt;p&gt;How I built a 4-bit CPU from scratch with integrated circuits and breadboards, covering the clock, ALU, registers, and RAM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g3d5xk44fzlm2beeebx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g3d5xk44fzlm2beeebx.jpg" alt="4 bit CPU Preview" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few weeks ago, while packing for a move, I stumbled upon an old 4-bit CPU that a friend and I built during our first year of college. For our "Computer System Architecture" class, they didn't give us specific instructions—just that it had to relate to the course topics. My friend and I were fascinated by the inner workings of a CPU and eager to understand how it actually functions. We were learning about Boolean logic, the architecture of a 4x3 RAM chip, and the simplified instruction set of an Intel Pentium chip, but none of this really explained how transistors and logic gates come together to create such a complex piece of engineering like a CPU.&lt;/p&gt;

&lt;p&gt;Around that time, electronics engineer and YouTuber Ben Eater posted his first couple of videos on building an 8-bit CPU with integrated circuits and breadboards. The initial videos only covered building a proper clock, but that was enough to hook us. We decided to build our own CPU for the assignment, even though we knew Ben Eater's series wouldn't be finished before our deadline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://matiassalles99.codes/posts/4bit-cpu/" rel="noopener noreferrer"&gt;Watch the demo video →&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the CPU
&lt;/h2&gt;

&lt;p&gt;We started by ordering a bunch of integrated circuits from &lt;a href="https://www.ti.com/" rel="noopener noreferrer"&gt;Texas Instruments&lt;/a&gt;, since we couldn't find any in Uruguay. These circuits were supposed to help us build the clock. To our surprise, the integrated circuits didn't fit in the breadboard—they were five times smaller than the ones we needed (yeah, and five times smaller than what they showed in the pictures 😐). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4542f97piflm6yybhs0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4542f97piflm6yybhs0.gif" alt="Frustrated reaction when the integrated circuits were too small for the breadboard" width="480" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After visiting every electronics shop in Uruguay, we finally found a small, old shop that sold the type of chips we needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clock
&lt;/h3&gt;

&lt;p&gt;You might think it would have been smooth sailing from there, but unsurprisingly, they didn't have the exact models we needed. 🤦‍♂️ The interesting part is, this actually led to our first big lesson: you don't need to copy every step and use the exact materials; you can use what you have and think your way through it. The integrated circuits we bought served the same purpose, but since they were a different model, each pin had a different function. This forced us to read through each chip's documentation instead of blindly following Ben's videos (which we did try at first).&lt;/p&gt;

&lt;p&gt;A couple of days in, and we had our clock working! I'm not going to dive into the implementation details for the clock because, first of all, I don't remember everything about it 😂, and more importantly, knowing the internals doesn't contribute much to fully understanding how a CPU works. As long as you know that the clock provides regular energy pulses to the rest of the CPU every few milliseconds (each pulse being a clock cycle), and that an operation is executed in each cycle, you should be fine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We'll dive into the "operations" that the CPU executes later in the post. Meanwhile if you're curious about the internals of a CPU clock, you can watch &lt;a href="https://www.youtube.com/watch?v=SmQ5K7UQPMM&amp;amp;list=PLowKtXNTBypGqImE405J2565dvjafglHU&amp;amp;index=5" rel="noopener noreferrer"&gt;this video&lt;/a&gt; from Ben Eater.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ALU, Registers and a simple BUS
&lt;/h3&gt;

&lt;p&gt;After building the clock, we moved on to the ALU and the registers. The ALU (Arithmetic Logic Unit) is the part of the CPU that performs arithmetic and logical operations, while the registers are memory units that store the data the ALU operates on.&lt;/p&gt;

&lt;p&gt;This is where we decided to make our CPU a 4-bit CPU. The old store had limited chip options, and we couldn't afford to order new ones from Texas Instruments without knowing if they would be suitable. We could have chained 4-bit registers and ALUs to create an 8-bit CPU, but we opted to keep things simple and start small, knowing we could always expand later.&lt;/p&gt;

&lt;p&gt;Here are some key insights we gained while building the ALU and the registers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Register Control:&lt;/strong&gt; You can control when to load data into a register by changing the voltage of a pin. This was our first glimpse into how you can actively manage the flow of data in a CPU, demonstrating that loading data from the BUS isn't just some magical, automatic process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ALU Operations:&lt;/strong&gt; For the ALU, you can dictate the operation it performs by altering the voltage of a specific pin. Our simple 4-bit ALU could only handle addition and subtraction, controlled by the voltage at a single pin. If it supported more operations, additional pins would be involved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BUS Functionality:&lt;/strong&gt; Data can also be output from the registers and ALU to the BUS. Here, we realized that the BUS acts like the CPU's highway, connecting various components that can read from and output data to it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After assembling the ALU and the registers, we set them up so that the ALU would output results to the BUS, and register A would read the data from it, enabling us to perform multiplication tables!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://matiassalles99.codes/posts/4bit-cpu/" rel="noopener noreferrer"&gt;Watch the demo video →&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  RAM
&lt;/h3&gt;

&lt;p&gt;The last component we managed to assemble, which isn’t featured in the video, was the RAM. It comprised several small RAM chips, each capable of holding 4 bits of data. We manually loaded data into these chips using DIP switches.&lt;/p&gt;

&lt;p&gt;While the RAM itself might not seem particularly exciting, it’s important to understand its function in a CPU system. RAM is used to store the results of operations performed by the ALU as well as the instructions that the CPU executes. This makes it a critical component, serving as the storage and retrieval point for both data and operational commands.&lt;/p&gt;

&lt;h3&gt;
  
  
  CU, where the magic happens
&lt;/h3&gt;

&lt;p&gt;The last piece of the puzzle was the CU (Control Unit). Although we attempted to build it, we ran out of time and didn’t have a detailed guide or tutorial to follow, as Ben's series was only beginning to explore the ALU when we reached this stage.&lt;/p&gt;

&lt;p&gt;The CU is where terms like "Instructions," "Machine Code," and "Assembly" transition from abstract concepts into practical components of computing. Recall our earlier discussion about the Registers, ALU, and BUS? The CU is responsible for controlling the voltage of specific pins to manage the loading and outputting of data to and from the BUS. This central role in coordinating how the CPU processes instructions makes the CU a fundamental element where much of the computational 'magic' occurs.&lt;/p&gt;

&lt;h4&gt;
  
  
  But how does it do it?
&lt;/h4&gt;

&lt;p&gt;The CU connects to every "control" pin, thus controlling the operations of the ALU, including whether registers should load data from the BUS. This is where you define your CPU’s instruction set. For example, "0001" might be set to instruct the CPU to "load data from the BUS into Register A," triggering the appropriate voltage change in the register’s control pin to perform the operation. Similarly, "0010" or another binary code could be assigned for different instructions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This variability is why there are many different Assembly languages, as their instruction sets are defined arbitrarily based on each CPU’s architecture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By encoding your instruction set in an EEPROM, the CU is programmed to deliver specific control signals to other components based on the instruction codes it receives ("0000", "0001", etc.). This is crucial for directing the precise behavior of the CPU during each operation.&lt;/p&gt;

&lt;p&gt;Now, the CU receives instructions from the same BUS that supplies data to other components. In a 4-bit CPU, the limited number of bits presents a challenge: ideally, you use all bits for data or instructions at different times, rather than permanently dividing the bus. Implementing a strict division (2 bits for data, 2 for instructions) severely restricts operational flexibility, limiting you to just 4 distinct operations.&lt;/p&gt;

&lt;p&gt;At this point, we decided to conclude our project. While most of our peers had only built simple systems using Arduinos and sensors, we believed our project would earn a good grade. More importantly, we had gained a deep understanding of how a CPU works, satisfying our curiosity.&lt;/p&gt;

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

&lt;p&gt;If you're an electronics engineer, you might find this post a bit basic or lacking in detail—and that's exactly the intention. As software engineers, we rarely get a firsthand look at the hardware we work on. Peeling back some of the "magic" behind a CPU is a fantastic way to spark curiosity and encourage others to explore this fascinating subject further.&lt;/p&gt;

&lt;p&gt;I definitely recommend watching Ben Eater's complete series. After our assignment was done, I watched it to see how he addressed the issues with the CU that we couldn't figure out. Let me tell you, he is a genius. If you're interested, you can check out his series &lt;a href="https://www.youtube.com/watch?v=HyznrdDSSGM&amp;amp;list=PLowKtXNTBypGqImE405J2565dvjafglHU" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>electronics</category>
    </item>
    <item>
      <title>Active Record's Magic 🪄: How Rails Defines Getters and Setters from Your Schema</title>
      <dc:creator>Matias Salles</dc:creator>
      <pubDate>Fri, 10 May 2024 17:23:41 +0000</pubDate>
      <link>https://dev.to/matiassalles99/active-records-magic-how-rails-defines-getters-and-setters-from-your-schema-1ggk</link>
      <guid>https://dev.to/matiassalles99/active-records-magic-how-rails-defines-getters-and-setters-from-your-schema-1ggk</guid>
      <description>&lt;p&gt;A deep dive into how ActiveRecord defines getter and setter methods from your database schema using Ruby metaprogramming and the AttributeMethods module.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c06xn4eyk3d29exfewp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c06xn4eyk3d29exfewp.jpg" alt="Active Record Logo" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever wondered how ActiveRecord, the ORM behind Ruby on Rails, functions? ORMs are crucial tools that simplify database interactions in web applications, yet many developers use them without understanding their inner workings.&lt;/p&gt;

&lt;p&gt;Why is that? Well, as long as it works and gets the job done there is no good reason to dive into such a complex piece of software, ...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9aff3e0b85aj3cbl0f1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9aff3e0b85aj3cbl0f1.gif" alt="Person shrugging and saying 'am I right?' — illustrating the attitude of not questioning tools that just work" width="480" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even though I agree on that one, curiosity gets the best of us, and I always used to wonder: How does ActiveRecord manage to define getter/setter methods based on our DB Schema?&lt;/p&gt;

&lt;p&gt;This might seem like a basic question, but it's fundamental to how we use ActiveRecord daily. This "harmless" question is a good one to start understanding how ActiveRecord internals work, and how some of those Ruby metaprogramming features we talked about in the &lt;a href="https://dev.to%20post_url%202024-04-20-dsl-with-ruby%20"&gt;previous post&lt;/a&gt; come in handy here too 💪.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏊‍♂️ into ActiveRecord::Base
&lt;/h2&gt;

&lt;p&gt;You may have observed that &lt;code&gt;models/application_record.rb&lt;/code&gt; typically contains minimal code and inherits from the &lt;code&gt;ActiveRecord::Base&lt;/code&gt; class. Inside &lt;code&gt;ActiveRecord::Base&lt;/code&gt; you'll see a lot of &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;extend&lt;/code&gt; calls on different modules that play a role in how ActiveRecord works:&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;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Naming&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Benchmarkable&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DescendantsTracker&lt;/span&gt;

    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ConnectionHandling&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;QueryCache&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Querying&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Translation&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;DynamicMatchers&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;DelegatedType&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Explain&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Delegation&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DelegateCache&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Aggregations&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;

    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Core&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Persistence&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ReadonlyAttributes&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ModelSchema&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Inheritance&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Scoping&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Sanitization&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;AttributeAssignment&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Conversion&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Integration&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Validations&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;CounterCache&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Attributes&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Locking&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Optimistic&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Locking&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Pessimistic&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Encryption&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EncryptableRecord&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Callbacks&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Timestamp&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Associations&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;SecurePassword&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;AutosaveAssociation&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;NestedAttributes&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Transactions&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TouchLater&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;NoTouching&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Reflection&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Serialization&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Store&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;SecureToken&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TokenFor&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;SignedId&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Suppressor&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Normalization&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Marshalling&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Methods&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a lot of modules 😱! We'll only dive into a couple of them though; after skimming through the code, I found that the getter/setter method definitions based on our DB Schema take place in the &lt;code&gt;ModelSchema&lt;/code&gt; and &lt;code&gt;AttributeMethods&lt;/code&gt; modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  AttributeMethods Module
&lt;/h3&gt;

&lt;p&gt;Let's first dive into the &lt;code&gt;AttributeMethods&lt;/code&gt; module and suppose we already know what the columns in our DB tables are. The first couple of things that caught my eye when digging into this module were the following:&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;ActiveRecord&lt;/span&gt;  
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AttributeMethods&lt;/span&gt;

    &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;initialize_generated_modules&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Read&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Write&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;BeforeTypeCast&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Query&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;PrimaryKey&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TimeZoneConversion&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Dirty&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Serialization&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;GeneratedAttributeMethods&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="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mutex_m&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;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;initialize_generated_modules&lt;/span&gt;
        &lt;span class="vi"&gt;@generated_attribute_methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;const_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:GeneratedAttributeMethods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GeneratedAttributeMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;private_constant&lt;/span&gt; &lt;span class="ss"&gt;:GeneratedAttributeMethods&lt;/span&gt;
        &lt;span class="vi"&gt;@attribute_methods_generated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
        &lt;span class="vi"&gt;@alias_attributes_mass_generated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
        &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="vi"&gt;@generated_attribute_methods&lt;/span&gt;

        &lt;span class="k"&gt;super&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;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;First of all, this module heavily relies on &lt;code&gt;ActiveModel::AttributeMethods&lt;/code&gt;, which gives us methods that you might be familiar with, such as: &lt;code&gt;attribute_method_prefix&lt;/code&gt;, &lt;code&gt;alias_attribute&lt;/code&gt;, and more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's important to remember that the ActiveModel's API was extracted from the ActiveRecord component to allow us to create POROs with "model-like" behavior (validations, type casting, etc.).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then, you can see a bunch of sub-modules included that self-describe their purpose, such as &lt;code&gt;Read&lt;/code&gt; (for reader/getter methods), &lt;code&gt;Write&lt;/code&gt; (for writer/setter methods), &lt;code&gt;PrimaryKey&lt;/code&gt;, &lt;code&gt;Dirty&lt;/code&gt; (for tracking changes), etc.&lt;/p&gt;

&lt;p&gt;And finally, you can see a method &lt;code&gt;initialize_generated_modules&lt;/code&gt; that gets called as soon as the module is included, where it sets up an empty &lt;code&gt;GeneratedAttributeMethods&lt;/code&gt; module into the &lt;code&gt;@generated_attribute_methods&lt;/code&gt; variable. Inside this &lt;code&gt;GeneratedAttributeMethods&lt;/code&gt; module is where all of the getter/setter methods will be defined, and then included in your class.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This pattern of defining an empty module, then dynamically adding methods to it and finally including it is a common approach you'll see in most of Ruby on Rails codebase.&lt;/p&gt;
&lt;/blockquote&gt;







&lt;blockquote&gt;
&lt;p&gt;When reading any Ruby open-source code, looking at the "ClassMethods" module within the module you're looking at might be helpful, since usually the "API" or "DSL" methods live in there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  But how does it work!?
&lt;/h3&gt;

&lt;p&gt;Now that we know the basic structure, let's dive into the actual code that defines the getter/setter methods based on our DB Schema.&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;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt;
      &lt;span class="c1"&gt;# Generates all the attribute related methods for columns in the database&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;define_attribute_methods&lt;/span&gt;
        &lt;span class="c1"&gt;#...&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="c1"&gt;#...&lt;/span&gt;

      &lt;span class="c1"&gt;# Returns an array of column names as strings if it's not an abstract class and&lt;/span&gt;
      &lt;span class="c1"&gt;# table exists. Otherwise it returns an empty array.&lt;/span&gt;
      &lt;span class="c1"&gt;# Person.attribute_names&lt;/span&gt;
      &lt;span class="c1"&gt;# eg: =&amp;gt; ["id", "created_at", "updated_at", "name", "age"]&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attribute_names&lt;/span&gt;
        &lt;span class="vi"&gt;@attribute_names&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;abstract_class?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;table_exists?&lt;/span&gt;
          &lt;span class="n"&gt;attribute_types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
          &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The super call ends up invoking the &lt;code&gt;define_attribute_methods&lt;/code&gt; method that lives within &lt;code&gt;ActiveModel::AttributeMethods&lt;/code&gt;, let's take a look at it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveModel&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="ss"&gt;:attribute_method_patterns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;instance_writer: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="no"&gt;ClassMethods&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AttributeMethodPattern&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="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;#...&lt;/span&gt;

    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&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;define_attribute_methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attr_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;#...&lt;/span&gt;
        &lt;span class="n"&gt;attr_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&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;attr_name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;define_attribute_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_name&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;define_attribute_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;attribute_method_patterns&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;pattern&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;method_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;generate_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"define_method_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;proxy_target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

          &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generate_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;owner: &lt;/span&gt;&lt;span class="n"&gt;owner&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="c1"&gt;#...&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what's happening here? The &lt;code&gt;ActiveModel::AttributeMethods&lt;/code&gt; uses the &lt;code&gt;class_attribute helper&lt;/code&gt; inside the &lt;code&gt;included do&lt;/code&gt; block which we saw in the &lt;a href="https://dev.to%20post_url%202024-04-20-dsl-with-ruby%20"&gt;previous post&lt;/a&gt;, it defines a class attribute where we'll save the "attribute method patterns", we'll come to this later. &lt;/p&gt;

&lt;p&gt;Then, we can find the method we were looking for: &lt;code&gt;define_attribute_methods&lt;/code&gt; which goes through each attribute name and calls &lt;code&gt;define_attribute_method&lt;/code&gt; for each one of them. &lt;/p&gt;

&lt;p&gt;This last method goes through each pattern available in the class attribute defined above and dynamically decides what method to call. This "dynamically deciding" will make sense when looking at the &lt;code&gt;AttributeMethodPattern&lt;/code&gt; and how it is used:&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;AttributeMethodPattern&lt;/span&gt; &lt;span class="c1"&gt;# :nodoc:&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:suffix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:proxy_target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:parameters&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="ss"&gt;prefix: &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;suffix: &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;parameters: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;
    &lt;span class="vi"&gt;@suffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;suffix&lt;/span&gt;
    &lt;span class="vi"&gt;@proxy_target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@prefix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@suffix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="vi"&gt;@method_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%s&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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;method_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@method_name&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;attr_name&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;If we only take into account the default AttributeMethodPattern that was added inside &lt;code&gt;ActiveModel::AttributeMethods&lt;/code&gt; with no prefix or suffix, when calling &lt;code&gt;generate_method = "define_method_#{pattern.proxy_target}"&lt;/code&gt; it will return &lt;code&gt;"define_method_attribute"&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;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveModel&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="ss"&gt;:attribute_method_patterns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;instance_writer: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="no"&gt;ClassMethods&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AttributeMethodPattern&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="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="c1"&gt;#...&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;define_attribute_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;attribute_method_patterns&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;pattern&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;method_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;generate_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"define_method_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;proxy_target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
          &lt;span class="c1"&gt;# ============================================================&lt;/span&gt;
          &lt;span class="c1"&gt;# ==== generate_method will be "define_method_attribute" =====&lt;/span&gt;
          &lt;span class="c1"&gt;# ============================================================&lt;/span&gt;

          &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generate_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr_name&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;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;So when we use &lt;code&gt;send&lt;/code&gt; to call that method, who will answer to &lt;code&gt;define_method_attribute(attr_name)&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The answer is...... 🥁🥁🥁🥁 The &lt;code&gt;ActiveRecord::AttributeMethods::Read&lt;/code&gt; module that we mentioned 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;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="c1"&gt;# = Active Record Attribute Methods \Read&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Read&lt;/span&gt;
      &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;

      &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt; &lt;span class="c1"&gt;# :nodoc:&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;define_method_attribute&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;owner&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
          &lt;span class="s2"&gt;"def &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;
          &lt;span class="s2"&gt;"  _read_attribute(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) { |n| missing_attribute(n, caller) }"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;
          &lt;span class="s2"&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="c1"&gt;#...&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_read_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_name&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;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there we have getter/reader methods defined for each attribute! But what about the setter/writer methods 🤔? It's as simple as adding a new attribute_method_pattern 😃! Let's look at the &lt;code&gt;ActiveRecord::AttributeMethods::Write&lt;/code&gt; 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;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Write&lt;/span&gt;
      &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;

      &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;attribute_method_suffix&lt;/span&gt; &lt;span class="s2"&gt;"="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;parameters: &lt;/span&gt;&lt;span class="s2"&gt;"value"&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="kp"&gt;private&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;define_method_attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="s2"&gt;"def &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;(value)"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;
          &lt;span class="s2"&gt;"  _write_attribute(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, value)"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;
          &lt;span class="s2"&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;def&lt;/span&gt; &lt;span class="nf"&gt;_write_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr_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="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;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;By adding a new attribute_method_pattern with a suffix of &lt;code&gt;=&lt;/code&gt; &lt;code&gt;ActiveModel::AttributeMethods&lt;/code&gt; will call &lt;code&gt;define_method_attribute=&lt;/code&gt; when iterating over that specific method pattern!&lt;/p&gt;

&lt;p&gt;I encourage you to look at the other sub-modules inside &lt;code&gt;ActiveRecord::AttributeMethods&lt;/code&gt; since you'll see they follow the same pattern:&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;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;AttributeMethods&lt;/span&gt;
    &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;initialize_generated_modules&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Read&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Write&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;BeforeTypeCast&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Query&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;PrimaryKey&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TimeZoneConversion&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Dirty&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Serialization&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;h3&gt;
  
  
  When do the getter/setter attribute definitions take place?
&lt;/h3&gt;

&lt;p&gt;If you paid close attention, you may have noticed that we never showed who calls the initial &lt;code&gt;define_attribute_methods&lt;/code&gt; method that starts the whole process.&lt;/p&gt;

&lt;p&gt;Here's where Railties comes into play, Railties "ties" all of the Rails components together, and it's responsible for orchestrating the "initialization" of a Rails application.&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;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Railtie&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;Railtie&lt;/span&gt; 
    &lt;span class="n"&gt;initializer&lt;/span&gt; &lt;span class="s2"&gt;"active_record.define_attribute_methods"&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;app&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;after_initialize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="c1"&gt;#...&lt;/span&gt;

        &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:active_record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="n"&gt;descendants&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;model&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define_attribute_methods&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;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it! We have now defined all of the getter and setter attributes for our models 💪!&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick 🏊‍♂️ into ActiveRecord::ModelSchema
&lt;/h2&gt;

&lt;p&gt;So far we supposed we already knew all of the columns in our DB tables, but we'll quickly unravel how this happens under the hood. Let's take a quick look at the &lt;code&gt;load_schema!&lt;/code&gt; method inside &lt;code&gt;ActiveRecord::ModelSchema&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;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ModelSchema&lt;/span&gt;
    &lt;span class="c1"&gt;#...&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;load_schema!&lt;/span&gt;
        &lt;span class="n"&gt;columns_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schema_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;columns_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&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="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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's pretty clear that based on a db connection and a table name it will fetch all of the columns in it. At first, I thought loading the schema would involve reading the famous &lt;code&gt;db/schema.rb&lt;/code&gt; file, but it turns out the schema is loaded by querying the DB itself! For instance, this is how that query looks like for MySQL:&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;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ConnectionAdapters&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractMysqlAdapter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;AbstractAdapter&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;column_definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;execute_and_free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SHOW FULL FIELDS FROM &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;quote_table_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"SCHEMA"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;each_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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="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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;And that brings us full circle! We've explored how ActiveRecord defines getter and setter methods aligned with our database schema and how it dynamically loads this schema.&lt;/p&gt;

&lt;p&gt;Ruby on Rails codebase is an awesome place to learn more about Ruby metaprogramming features and how to use it to your advantage; I hope this post has given you a glimpse of that! 🎉&lt;/p&gt;

</description>
      <category>rails</category>
    </item>
    <item>
      <title>How to Create a DSL (Domain-Specific Language) in Ruby</title>
      <dc:creator>Matias Salles</dc:creator>
      <pubDate>Sat, 20 Apr 2024 17:23:41 +0000</pubDate>
      <link>https://dev.to/matiassalles99/how-to-create-a-dsl-domain-specific-language-in-ruby-2k7g</link>
      <guid>https://dev.to/matiassalles99/how-to-create-a-dsl-domain-specific-language-in-ruby-2k7g</guid>
      <description>&lt;p&gt;Learn how to create a Domain-Specific Language (DSL) in Ruby using metaprogramming, define_method, class_eval, and ActiveSupport::Concern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkd1cyj992qjqbxh68wk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkd1cyj992qjqbxh68wk.jpeg" alt="Create a DSL Language Preview" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After completing the first version of a website for a friend, I dedicated some time to extract an API client I had developed for connecting with dlocalGo's API. dlocalGo is a payment processor built by dlocal, a company like Stripe, but that operates mainly in South America and other emerging markets.&lt;/p&gt;

&lt;p&gt;Since this was my first time creating an open-source gem and I wasn't on a rush to publish it, I took the liberty to play around with some Ruby metaprogramming features while at it. After playing around for a while, I realized that creating my own mini-DSL to easily add support for new endpoints with little-to-no code was easier than I initially expected.&lt;/p&gt;

&lt;p&gt;I leveraged Ruby's metaprogramming capability, particularly the define_method, which allows for dynamic definition of new methods. Down the road, I also ended up digging into other Ruby features such as &lt;code&gt;class_eval&lt;/code&gt;, &lt;code&gt;instance_eval&lt;/code&gt;, multiline strings with &lt;code&gt;&amp;lt;&amp;lt;-&lt;/code&gt;, Module's lifecycle and more. This also encouraged me to dig into some of ActiveSupport's APIs and discovered some awesome helper methods like &lt;code&gt;class_attribute&lt;/code&gt; and how &lt;code&gt;ActiveSupport::Concern&lt;/code&gt; actually works&lt;/p&gt;

&lt;h2&gt;
  
  
  v0.1
&lt;/h2&gt;

&lt;p&gt;When starting the website we only needed to support one-off payments and refunds, so I created a simple class with a method per endpoint:&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;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Client&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;create_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
      &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/v1/payments"&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;get_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/v1/payments/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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;create_refund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
      &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/v1/refunds"&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach soon proved inadequate as we needed to incorporate subscriptions and recurring payments. By following the same approach we would've ended up with 20 different repetitive methods and a bloated class with 600+ lines of code. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8zkmmozp4e6dmrqpzdh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8zkmmozp4e6dmrqpzdh.gif" alt="Sherlock Holmes looking unimpressed, representing the frustration of bloated repetitive code" width="480" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On our way to v1.0 🏎️
&lt;/h2&gt;

&lt;p&gt;The main idea was to create a class method that when being called would generate a method for a specific endpoint based on its URI, HTTP method and response model. It should look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;

    &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="ss"&gt;:create_payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;uri: &lt;/span&gt;&lt;span class="s2"&gt;"/v1/payments"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;verb: :post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dto_class: &lt;/span&gt;&lt;span class="no"&gt;Responses&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Payments&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;/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;# Usage&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DlocalGo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_payment&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;param1: &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;param2: &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;# response is a Responses::Payment object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This is where &lt;code&gt;define_method&lt;/code&gt; comes in handy.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I already had experience combining class methods and &lt;code&gt;define_method&lt;/code&gt;, but it was always inside Ruby on Rails and using concerns (&lt;code&gt;ActiveSupport::Concern&lt;/code&gt;). So when I first tried the following approach in the &lt;code&gt;"dlocal_go"&lt;/code&gt; gem I realized &lt;code&gt;"class_methods do ... end"&lt;/code&gt; and &lt;code&gt;"included do ... end"&lt;/code&gt; don't 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="c1"&gt;# This approach doesn't work with plain Ruby&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;EndpointGenerator&lt;/span&gt;
  &lt;span class="n"&gt;class_methods&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;verb&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;dto_class&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
      &lt;span class="n"&gt;define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="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;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;Encountering "method_missing" errors led me to discover that these methods were part of &lt;code&gt;ActiveSupport::Concern&lt;/code&gt;. This prompted me to consult the ActiveSupport documentation and delve into the source code for &lt;code&gt;included&lt;/code&gt; and &lt;code&gt;class_methods&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's easy to see in their documentation that &lt;code&gt;class_methods&lt;/code&gt; defines class methods from a given block (&lt;a href="https://api.rubyonrails.org/v7.1.3.2/classes/ActiveSupport/Concern.html#method-i-class_methods" rel="noopener noreferrer"&gt;see docs&lt;/a&gt;), but how does it work behind the scenes?&lt;/p&gt;

&lt;p&gt;You can navigate to the gem's source code by using &lt;code&gt;gem unpack&lt;/code&gt;, &lt;code&gt;gem open&lt;/code&gt; or installing extensions in your favorite IDE (although it might not be necessary if you use something like RubyMine). Here you'll find the definition to &lt;code&gt;class_methods&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;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveSupport&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Concern&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;append_features&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="c1"&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="nb"&gt;const_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ClassMethods&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;const_defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ClassMethods&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;class_methods&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;class_methods_module_definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;const_defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ClassMethods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
        &lt;span class="nb"&gt;const_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ClassMethods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;const_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ClassMethods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;module_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;class_methods_module_definition&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It checks if there's a constant named &lt;code&gt;ClassMethods&lt;/code&gt; defined, if so it keeps it, otherwise it creates a new empty &lt;code&gt;ClassMethods&lt;/code&gt; module, then evaluates the block we passed inside the &lt;code&gt;ClassMethods&lt;/code&gt; module. Finally &lt;code&gt;ActiveSupport::Concern&lt;/code&gt; has its own implementation of the &lt;code&gt;append_features&lt;/code&gt; method, a method that gets called when a module is included (&lt;a href="https://apidock.com/ruby/Module/append_features" rel="noopener noreferrer"&gt;see docs&lt;/a&gt;). Here, it "extends" base (the class where you included the Module) with all of methods inside the &lt;code&gt;ClassMethods&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;This all makes sense especially when we look how a typical module looks with plain ruby:&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;M&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="c1"&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;blockquote&gt;
&lt;p&gt;The method &lt;code&gt;included&lt;/code&gt; is similar to &lt;code&gt;append_features&lt;/code&gt; (&lt;a href="https://apidock.com/ruby/Module/included" rel="noopener noreferrer"&gt;see docs&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's clear that &lt;code&gt;ActiveSupport::Concern&lt;/code&gt; gives us a nicer and cleaner API to achieve the same goal. So after getting a better grasp of how modules and their lifecycle works, we can create the first version of our &lt;code&gt;EndpointGenerator&lt;/code&gt; 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;module&lt;/span&gt; &lt;span class="nn"&gt;EndpointGenerator&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="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&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;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;endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;verb&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;dto_class&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
      &lt;span class="n"&gt;define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="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;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Parsing the response
&lt;/h3&gt;

&lt;p&gt;🎉 Now we can take a closer look at parsing a succesful response, the first version of the response objects (v0.1) looked more or less like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Responses&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt;
      &lt;span class="no"&gt;RESPONSE_ATTRIBUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%i[id amount etc..]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;

      &lt;span class="nb"&gt;attr_reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;RESPONSE_ATTRIBUTES&lt;/span&gt;&lt;span class="p"&gt;)&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;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="no"&gt;RESPONSE_ATTRIBUTES&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;attribute&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="nb"&gt;instance_variable_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&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;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;If a response object had an association it would look something 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="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s2"&gt;"subscription_plan"&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Responses&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt;
      &lt;span class="no"&gt;RESPONSE_ATTRIBUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%i[id country etc...]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;

      &lt;span class="nb"&gt;attr_reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;RESPONSE_ATTRIBUTES&lt;/span&gt;&lt;span class="p"&gt;)&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;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RESPONSE_ATTRIBUTES&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;attribute&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="nb"&gt;instance_variable_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="vi"&gt;@plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SubscriptionPlan&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="no"&gt;OpenStruct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"plan"&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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There was clear repetition in all of the response objects, so I thought it would be great if by just defining the attributes and associations with a clean API similar to &lt;code&gt;ActiveRecord&lt;/code&gt;'s one, all of them could be populated automatically. Something that would look similar to 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="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s2"&gt;"subscription_plan"&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s2"&gt;"client"&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Responses&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Base&lt;/span&gt;
      &lt;span class="n"&gt;has_attributes&lt;/span&gt; &lt;span class="sx"&gt;%i[id country etc..]&lt;/span&gt;

      &lt;span class="n"&gt;has_association&lt;/span&gt; &lt;span class="ss"&gt;:plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SubscriptionPlan&lt;/span&gt;
      &lt;span class="n"&gt;has_association&lt;/span&gt; &lt;span class="ss"&gt;:client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Client&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;To achieve this, we needed a way to "save" all of the associations data (attribute name and its corresponding response class) somewhere when &lt;code&gt;has_association&lt;/code&gt; was called.&lt;/p&gt;

&lt;p&gt;There was a specific method &lt;code&gt;ActiveSupport::Support&lt;/code&gt; gives us that I saw all around Rails codebase: &lt;code&gt;class_attribute&lt;/code&gt;. It declares a class-level attribute and creates the getter/read and setter/write methods for us. With that in mind, I created a &lt;code&gt;Responses::Base&lt;/code&gt; class, which all Response objects will inherit from, and created a new &lt;code&gt;ReponseParser&lt;/code&gt; module, in which I planned to include all of the "magic" 🪄&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s2"&gt;"response_parser"&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Responses&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ResponseParser&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;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;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Responses&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ResponseParser&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;class_eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="ss"&gt;:response_attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:response_associations&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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Not sure what &lt;code&gt;class_eval&lt;/code&gt; does? &lt;a href="https://web.stanford.edu/~ouster/cgi-bin/cs142-winter15/classEval.php" rel="noopener noreferrer"&gt;Here's&lt;/a&gt; a short and interesting article from Stanford that explains &lt;code&gt;class_eval&lt;/code&gt; and &lt;code&gt;instance_eval&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we need to add the &lt;code&gt;ClassMethod&lt;/code&gt; module with the methods that will define our second mini-DSL (&lt;code&gt;has_attributes&lt;/code&gt; and &lt;code&gt;has_association&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;module&lt;/span&gt; &lt;span class="nn"&gt;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Responses&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ResponseParser&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;class_eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="ss"&gt;:response_attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:response_associations&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="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&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;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;has_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&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;response_attributes&lt;/span&gt; &lt;span class="o"&gt;||=&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;response_attributes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;

          &lt;span class="nb"&gt;class_eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;attr_reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&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;has_association&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;klass&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;response_associations&lt;/span&gt; &lt;span class="o"&gt;||=&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;response_associations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;klass&lt;/span&gt;

          &lt;span class="nb"&gt;class_eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="n"&gt;attribute&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;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now save all the information needed to parse the response inside the &lt;code&gt;response_attributes&lt;/code&gt; and &lt;code&gt;response_associations&lt;/code&gt; class attributes. The only missing piece is to override the initialize method, so we can call a new method that will iterate on the &lt;code&gt;response_attributes&lt;/code&gt; and &lt;code&gt;response_associations&lt;/code&gt; and populate each one of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DlocalGo&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Responses&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ResponseParser&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;class_eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;class_attribute&lt;/span&gt; &lt;span class="ss"&gt;:response_attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:response_associations&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="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&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;class_eval&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;CODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__LINE__&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;
          def initialize(response)
            assign_attributes(response)
            assign_associations(response)
          end
&lt;/span&gt;&lt;span class="no"&gt;        CODE&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;has_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&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;has_association&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;klass&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="kp"&gt;private&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;assign_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&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;assign_associations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&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;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might be wondering what does &lt;code&gt;&amp;lt;&amp;lt;-&lt;/code&gt; stand for 🤔. It's just a multiline string delimited by the &lt;code&gt;CODE&lt;/code&gt; keyword. &lt;code&gt;__FILE__&lt;/code&gt; and &lt;code&gt;__LINE__ + 1&lt;/code&gt; are there for debugging purposes, you can read more about it in Ruby's official documentation. &lt;/p&gt;

&lt;p&gt;You'll see this approach in various places inside the Ruby on Rails codebase, &lt;code&gt;class_eval&lt;/code&gt; not only works with blocks but also with strings, so instead of defining a method inside of a method (doing &lt;code&gt;def initialize&lt;/code&gt; inside &lt;code&gt;self.included(base)&lt;/code&gt;), we use class_eval and use a string instead of a block.&lt;/p&gt;

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

&lt;p&gt;That's a wrap! We've explored an extensive range of topics, from &lt;code&gt;ActiveSupport::Concern&lt;/code&gt; internals to the lifecycle of modules, along with &lt;code&gt;define_method&lt;/code&gt;, &lt;code&gt;class_eval&lt;/code&gt;, and multiline strings. We've also looked at helper methods like &lt;code&gt;class_attribute&lt;/code&gt; 😄.&lt;/p&gt;

&lt;p&gt;So what might be next?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Since we ended up including ActiveSupport as a dependency in order to use the &lt;code&gt;class_attribute&lt;/code&gt; method, we might as well refactor these modules into cocerns 😅.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maybe creating another gem similar to &lt;code&gt;ActiveResource&lt;/code&gt;, that would allow you to turn any Ruby class into a HTTP client by just adding &lt;code&gt;endpoint&lt;/code&gt; calls like we do inside &lt;code&gt;DlocalGo::Client&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I also plan to create a small rails engine in the future were you'll be able to get a simple dlocalGo dashboard with all the payments, subscriptions, and transactions just by mounting it inside your Ruby on Rails app.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't know what a rails engine is? That might be a whole new blog post, meanwhile, I encourage you to read the official &lt;a href="https://guides.rubyonrails.org/engines.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt; that explains it amazingly&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ruby</category>
    </item>
  </channel>
</rss>
