{
  "version": "https://jsonfeed.org/version/1",
  "title": "Weird on enumerator.dev",
  "icon": "<no value>",
  "home_page_url": "https://enumerator.dev/",
  "feed_url": "https://enumerator.dev/feed.json",
  "items": [
      {
        "id": "https://enumerator.dev/weird-method-signatures-in-ruby-with-keyword-arguments/",
        "title": "Weird Method Signatures in Ruby with Keyword Arguments",
        "content_html": "<p>In a recent project, I was working with a method call from a library that used some meta-programming to define a <code>get</code> method. I wasn&rsquo;t certain what the correct signature was, so I thought I&rsquo;d try some things out.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success, got at 200!</span>\n</span></span></code></pre></div><p>I knew that the method accepted a request <code>body</code> but I wasn&rsquo;t sure how to pass the body. So I tried this next call.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: wrong number of arguments (given 2, expected 1)</span>\n</span></span></code></pre></div><p>Okay, this tells me something, but I&rsquo;m a bit confused. How did it expect one argument when I know a successful call can have more than one argument?</p>\n<p>So I tried this, something you might recognize from a Ruby 2 project (more on that later):</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span> <span class=\"p\">})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: wrong number of arguments (given 2, expected 1)</span>\n</span></span></code></pre></div><p>The same error! What does that tell us? It wasn&rsquo;t immediately obvious to me so I tried the next iteration:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success, got at 200!</span>\n</span></span></code></pre></div><h2 id=\"lets-break-down-whats-happening-here\">Let&rsquo;s break down what&rsquo;s happening here</h2>\n<ol>\n<li>We&rsquo;re using a variable called <code>api_client</code> in this example. Pretend this is a wrapper that can make HTTP calls to a remote service.</li>\n<li>We&rsquo;re calling the <code>get</code> method which presumably uses HTTP <code>GET</code> to fetch data.</li>\n<li>The <code>get</code> method accepts a positional argument, a string, that represents the URL path we&rsquo;re fetching.</li>\n</ol>\n<p>All good so far, right? The next step is where things get weird.</p>\n<p>What is the next argument? I didn&rsquo;t know until I tried all the options. It turns out <code>body:</code> is a keyword argument, or kwarg, and it has a default. So the method signature must look something like this.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># Perform get request</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>So what&rsquo;s with this error? <code>ArgumentError: wrong number of arguments (given 2, expected 1)</code> The method only requires one positional argument to work. So even though it can accept three arguments, it is only expecting one. The result is a message that is a bit misleading because you can correctly call the method with one, two, or three arguments, but the second and third need to be keywords.</p>\n<h3 id=\"lets-make-things-weird\">Let&rsquo;s Make Things Weird</h3>\n<p>In Ruby land, especially applications that existed before Ruby 2, it is reasonable to see a method signature like this.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">options</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:body</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># Perform get request</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>Calling this method can look the same as a call with kwargs because the curly braces around a hash in Ruby are optional. That&rsquo;s why I tried wrapping the second argument in a hash. I wanted to know if we were dealing with an options hash or a keyword.</p>\n<p>As a consumer of an interface like this, it can take a bit of poking around to know if you&rsquo;re dealing with an options hash or keywords.</p>\n<h3 id=\"lets-make-things-better\">Let&rsquo;s Make Things Better</h3>\n<p>Kwargs are great for helping developers understand a method signature, but if they&rsquo;re not used carefully they result in confusing error messages.</p>\n<p>To make this method call better, I&rsquo;d suggest defining it entirely with kwargs and doing away with the positional argument.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># Perform GET</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>Let&rsquo;s see what usage looks like on this. Let&rsquo;s do something wild and call the method with no arguments.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: missing keyword: :path</span>\n</span></span></code></pre></div><p>Oh! That&rsquo;s helpful. I need to give it a <code>path</code>.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success!</span>\n</span></span></code></pre></div><p>What about some obviously wrong method calls?</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># SyntaxError: unexpected &#39;)&#39;, expecting =&gt;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># get(path: &#39;my/path&#39;, &#39;body&#39;)</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span> <span class=\"p\">})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># SyntaxError: unexpected &#39;)&#39;, expecting =&gt;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># get(path: &#39;my/path&#39;, { body: &#39;body&#39; })</span>\n</span></span></code></pre></div><p>SyntaxError! Neat! Because Ruby knows this method needs keywords, it doesn&rsquo;t know how to parse these two calls. This prevents you from even calling the method at all.</p>\n<p>Let&rsquo;s make a typo:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">bdy</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: unknown keyword: :bdy</span>\n</span></span></code></pre></div><p>That&rsquo;s helpful too! It puts the typo right in front of my eyes.</p>\n<p>And finally, let&rsquo;s use all keywords:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span> <span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success!</span>\n</span></span></code></pre></div><h2 id=\"but-why-is-it-this-way-a-history-of-keyword-arguments-in-ruby\">But Why is it This Way? A History of Keyword Arguments in Ruby</h2>\n<p>Before keyword arguments existed in Ruby, the method signature would have had an options hash, as I noted above.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">options</span> <span class=\"o\">=</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:body</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># insert remaining http client code here</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>We had a few options for how we called the method, depending on our syntax preferences. Most commonly, you&rsquo;d see something like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span></code></pre></div><p>But if you prefer to be explicit about what you are passing to a method you might wrap the hash in curly braces:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{}</span> <span class=\"p\">})</span>\n</span></span></code></pre></div><h3 id=\"enter-keyword-arguments\">Enter Keyword Arguments</h3>\n<p>Keyword arguments were introduced in Ruby 2.0. Ruby 2!!!! &ldquo;Isn&rsquo;t that like eons ago?&rdquo; you say. Yes, it is eons ago, but code practices change very slowly. So the two examples above were very common in Ruby 2.</p>\n<p>In fact, in early versions of Ruby 2 you could define a method using kwargs and call the method with a hash. Ruby would see the hash and automatically convert it to kwargs.</p>\n<p>So that meant a method like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:,</span> <span class=\"ss\">headers</span><span class=\"p\">:)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>Could be called like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">,</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{</span> <span class=\"ss\">auth</span><span class=\"p\">:</span> <span class=\"s1\">&#39;auth&#39;</span> <span class=\"p\">})</span>\n</span></span></code></pre></div><p>Or like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">,</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{</span> <span class=\"ss\">auth</span><span class=\"p\">:</span> <span class=\"s1\">&#39;auth&#39;</span> <span class=\"p\">}</span> <span class=\"p\">})</span>\n</span></span></code></pre></div><p>Ruby would figure out that the second argument, the hash, is the keyword argument. To the developer using the <code>get</code> method, there is no difference between using kwargs or an options hash, provided the use the right keywords.</p>\n<p>Additionally, developers often chose to use a hash as the last positional argument for flexibility. Imagine an options hash with five or more options. Using kwargs the method signature would make the method unreadable!</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:,</span> <span class=\"ss\">headers</span><span class=\"p\">:,</span> <span class=\"k\">retry</span><span class=\"p\">:,</span> <span class=\"ss\">retry_delay</span><span class=\"p\">:,</span> <span class=\"ss\">admin</span><span class=\"p\">:,</span> <span class=\"ss\">on_error</span><span class=\"p\">:</span> <span class=\"o\">...</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p><em>A contrived example of a long kwargs list</em></p>\n<p>With kwargs users need to know the kwargs and the method signature is locked into the kwargs that the developer chose. But with an options hash, there is some flexibility to add or remove options if things change.</p>\n<p><a href=\"https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/\">But in Ruby 3 all that changed and Ruby stopped automatically converting positional hashes to keyword arguments.</a></p>\n<p>Today we get a slightly ambiguous message when we use signatures that mix positional and keyword arguments, but in Ruby 2, a positional argument could be converted to a keyword argument unexpectedly. An excerpt from the post above shows how keyword arguments were confusing:</p>\n<blockquote>\n<p>Automatic conversion does not work well when a method accepts optional positional arguments and keyword arguments. Some people expect the last Hash object to be treated as a positional argument, and others expect it to be converted to keyword arguments.</p>\n</blockquote>\n<p>Let&rsquo;s rewrite the <code>get</code> method to demonstrate how this can be confusing. (Note: this is my rewording of the example that the authors of the Ruby blog post wrote).</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Using Ruby 2.6</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"nb\">p</span> <span class=\"o\">[</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">({})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; [{}, {}, {}]</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get_with_default</span><span class=\"p\">(</span><span class=\"n\">path</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;home&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"nb\">p</span> <span class=\"o\">[</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get_with_default</span><span class=\"p\">({})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"o\">[</span><span class=\"s2\">&#34;home&#34;</span><span class=\"p\">,</span> <span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><p><code>get_with_default</code> has an unexpected behaviour here. Since we&rsquo;re only passing one argument, the method should see that as the first positional argument. But because we&rsquo;re passing it a hash, it parses this hash as the keyword arguments. Let&rsquo;s try to put something in that hash to test this out.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Again, we&#39;re in Ruby 2.6 here!</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get_with_default</span><span class=\"p\">({</span><span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"o\">[</span><span class=\"s2\">&#34;home&#34;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">,</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><p>There is a reason for this, but the behaviour is not intuitive. Since the first argument has a default, we don&rsquo;t need to pass it, so when Ruby 2.6 sees a hash it automatically parses the hash as keyword arguments.</p>\n<p>In the Ruby blog post about separating positional and keyword arguments, they suggest a workaround one might think is clever but produces unexpected results as well.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Still Ruby 2.6 here</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">({},</span> <span class=\"o\">**</span><span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">expected</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">actual</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"s1\">&#39;home&#39;</span><span class=\"p\">,</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><p>The <code>**{}</code> here is telling Ruby, &ldquo;I&rsquo;m passing you a hash and I&rsquo;d like you to treat it as keyword arguments.&rdquo; However, Ruby just ignores it because the parser sees the first hash and uses that as the kwargs!</p>\n<p>To quote the Ruby post you need to call <code>get({}, {})</code> to get this to work, &ldquo;which is very weird.&rdquo;</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Still Ruby 2.6 here</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">({},</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">expected</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">actual</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><h2 id=\"enter-ruby-3\">Enter Ruby 3</h2>\n<p>And finally! Here we are at Ruby 3 where you can&rsquo;t mix hashes with kwargs&hellip;err, wait..but you can still mix positional arguments with kwargs!</p>\n<h1 id=\"summing-up\">Summing Up</h1>\n<p>Ruby method signatures can be kinda funky, especially when they&rsquo;re peppered with the history of the language itself.</p>\n<p>My take here is that we should always write the most human-intelligible code possible. If you have a simple method call where the arguments are straightforward, positional arguments are fine.</p>\n<p>However, it helps to name things, so go with keyword arguments all the way. Mixing the two can get a bit messy.</p>\n",
        "date_published": "2024-01-10T00:00:00+00:00",
        "url": "https://enumerator.dev/weird-method-signatures-in-ruby-with-keyword-arguments/",
        "tags": ["weird","ruby","coding-style"]
      }
  ]
}
