<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="https://bytes.akshaybirajdar.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://bytes.akshaybirajdar.com/" rel="alternate" type="text/html" /><updated>2025-03-15T23:06:03+05:30</updated><id>https://bytes.akshaybirajdar.com/feed.xml</id><title type="html">Bytes</title><subtitle>Byte size blogs to share my experiences.</subtitle><entry><title type="html">Using Procs as Filters for RSpec Metadata</title><link href="https://bytes.akshaybirajdar.com/ruby/2024/10/02/rspec_metadata.html" rel="alternate" type="text/html" title="Using Procs as Filters for RSpec Metadata" /><published>2024-10-02T17:33:06+05:30</published><updated>2024-10-02T17:33:06+05:30</updated><id>https://bytes.akshaybirajdar.com/ruby/2024/10/02/rspec_metadata</id><content type="html" xml:base="https://bytes.akshaybirajdar.com/ruby/2024/10/02/rspec_metadata.html"><![CDATA[<p>Ever wondered why we have to add RSpec Helpers multiple times for each spec type? There must be a more idiomatic way to do this.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">RSpec</span><span class="p">.</span><span class="nf">configure</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">include</span> <span class="no">RequestSpecHelper</span><span class="p">,</span> <span class="ss">type: :controller</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">include</span> <span class="no">RequestSpecHelper</span><span class="p">,</span> <span class="ss">type: :service</span>
<span class="k">end</span>
</code></pre></div></div>

<p>I suspected others might have the same question, so I put on my detective hat and jumped into RSpec core <a href="https://github.com/rspec/rspec-core">repository</a> issues. Behold, there was already an issue descrbing exactly this. <a href="https://github.com/rspec/rspec-core/issues/2890">“#2890 Allow array as value for type key in Configuration#include”</a>.</p>

<p>Here, Phil <a href="https://github.com/pirj">@pirj</a> explained in this <a href="https://github.com/rspec/rspec-core/issues/2890#issuecomment-825886660">comment</a> that introducing special handling for <code class="language-plaintext highlighter-rouge">type</code>, especially for <code class="language-plaintext highlighter-rouge">config.include</code>, risks breaking existing code that relies on standard behavior. And desired behaviour can easily be acheived with current rspec metadata options, which accepts <code class="language-plaintext highlighter-rouge">Proc</code> as a value.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">RSpec</span><span class="p">.</span><span class="nf">configure</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">include</span> <span class="no">RequestSpecHelper</span><span class="p">,</span> <span class="ss">type: </span><span class="o">-&gt;</span><span class="p">(</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="ss">:request</span><span class="p">,</span> <span class="ss">:component</span><span class="p">].</span><span class="nf">include?</span><span class="p">(</span><span class="n">type</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre></div></div>

<h3 id="small-contributions-towards-docs">Small contributions towards docs</h3>

<p>After learning this, I decided to contribute back by creating a follow-up PR that adds an example of using Procs with <code class="language-plaintext highlighter-rouge">config.include</code>. You can check it out here: <a href="https://github.com/rspec/rspec-core/pull/3112">PR #3112</a>.</p>

<p>A special shoutout to RSpec maintainer <a href="https://github.com/JonRowe">@JonRowe</a> for the quick review and merge. It’s always great to see maintainers so responsive to contributions! 🎉</p>

<h3 id="learnings">Learnings</h3>

<p>This whole experience was a valuable learning opportunity, seeing how maintainers balance shiny new features and refactors with backward compatibility. More importantly, it shows that just using Ruby can take us a long way.</p>]]></content><author><name></name></author><category term="ruby" /><summary type="html"><![CDATA[Ever wondered why we have to add RSpec Helpers multiple times for each spec type? There must be a more idiomatic way to do this.]]></summary></entry><entry><title type="html">Reverse Find in Ruby</title><link href="https://bytes.akshaybirajdar.com/ruby/2024/04/28/reverse_find.html" rel="alternate" type="text/html" title="Reverse Find in Ruby" /><published>2024-04-28T16:15:06+05:30</published><updated>2024-04-28T16:15:06+05:30</updated><id>https://bytes.akshaybirajdar.com/ruby/2024/04/28/reverse_find</id><content type="html" xml:base="https://bytes.akshaybirajdar.com/ruby/2024/04/28/reverse_find.html"><![CDATA[<p>One of the things that sets Ruby apart from other programming languages is its impressive set of built-in features.
One of my favourite method is <a href="https://ruby-doc.org/3.3.0/Enumerable.html#method-i-detect"><code class="language-plaintext highlighter-rouge">Enumerable#detect</code></a>.
It returns the first element for which the block yields a truthy value and stops searching upon the first hit.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s2">"prime"</span>
<span class="n">arr</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">10</span><span class="p">).</span><span class="nf">to_a</span>
<span class="n">arr</span><span class="p">.</span><span class="nf">detect</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Prime</span><span class="p">.</span><span class="nf">prime?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">}</span> <span class="c1">#=&gt; 2</span>
</code></pre></div></div>

<p>Okay, let’s spice it up! How do we find last matching element? A possible solution could be to filter the whole array using <a href="https://ruby-doc.org/3.3.0/Enumerable.html#method-i-select"><code class="language-plaintext highlighter-rouge">Enumerable#filter</code></a>, and use the last match.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s2">"prime"</span>
<span class="n">arr</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">10</span><span class="p">).</span><span class="nf">to_a</span>
<span class="n">arr</span><span class="p">.</span><span class="nf">filter</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Prime</span><span class="p">.</span><span class="nf">prime?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">}.</span><span class="nf">last</span> <span class="c1">#=&gt; 7</span>
</code></pre></div></div>

<p>However, this approach means traversing the entire array just to get that final match and discarding rest of the matches.</p>

<h3>Ruby to Rescue</h3>

<p>Ruby provides another awesome method <a href="https://ruby-doc.org/3.3.0/Enumerable.html#method-i-reverse_each"><code class="language-plaintext highlighter-rouge">Enumerable#reverse_each</code></a>, it allows to gracefully traverse an array in reverse order without mutating the original array.</p>

<p>Combining it with <code class="language-plaintext highlighter-rouge">Array#detect</code>, we now have an optimized solution where we can find the last matching element without traversing the full array, making it doubly awesome.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s2">"prime"</span>
<span class="n">arr</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">10</span><span class="p">).</span><span class="nf">to_a</span>
<span class="n">arr</span><span class="p">.</span><span class="nf">reverse_each</span><span class="p">.</span><span class="nf">detect</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Prime</span><span class="p">.</span><span class="nf">prime?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">}</span>
</code></pre></div></div>

<h3>Wait! Ruby is actually more awesome!!</h3>

<p>Ruby provides a method that exactly matches our use case: <a href="https://ruby-doc.org/3.3.0/Array.html#method-i-rindex"><code class="language-plaintext highlighter-rouge">Array#rindex</code></a>.
This method returns the index of the last element for which the block returns a truthy value.</p>

<p>While similar to <code class="language-plaintext highlighter-rouge">Enumerable#detect</code>, there is a slight difference between the two: <code class="language-plaintext highlighter-rouge">Enumerable#detect</code> returns the matched element itself, whereas <code class="language-plaintext highlighter-rouge">Array#rindex</code> returns the index of that element.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s2">"prime"</span>
<span class="n">arr</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">10</span><span class="p">).</span><span class="nf">to_a</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">arr</span><span class="p">.</span><span class="nf">rindex</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Prime</span><span class="p">.</span><span class="nf">prime?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">}</span>
<span class="n">arr</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="c1">#=&gt; 7</span>
</code></pre></div></div>

<h3>Benchmark It!!</h3>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># frozen_string_literal: true</span>

<span class="nb">require</span> <span class="s2">"bundler/inline"</span>

<span class="n">gemfile</span> <span class="kp">true</span> <span class="k">do</span>
  <span class="n">source</span> <span class="s2">"https://rubygems.org"</span>

  <span class="n">gem</span> <span class="s2">"benchmark-ips"</span>
  <span class="n">gem</span> <span class="s2">"prime"</span>
<span class="k">end</span>

<span class="nb">require</span> <span class="s2">"benchmark/ips"</span>
<span class="nb">require</span> <span class="s2">"prime"</span>

<span class="no">ARR</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">100_000</span><span class="p">).</span><span class="nf">to_a</span>

<span class="no">Benchmark</span><span class="p">.</span><span class="nf">ips</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
  <span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"reverse_each.detect"</span><span class="p">)</span> <span class="p">{</span> <span class="no">ARR</span><span class="p">.</span><span class="nf">reverse_each</span><span class="p">.</span><span class="nf">detect</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Prime</span><span class="p">.</span><span class="nf">prime?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span>
  <span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"filter.last"</span><span class="p">)</span> <span class="p">{</span> <span class="no">ARR</span><span class="p">.</span><span class="nf">filter</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Prime</span><span class="p">.</span><span class="nf">prime?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">}.</span><span class="nf">last</span> <span class="p">}</span>
  <span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"rindex"</span><span class="p">)</span> <span class="p">{</span> <span class="no">ARR</span><span class="p">[</span><span class="no">ARR</span><span class="p">.</span><span class="nf">rindex</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="no">Prime</span><span class="p">.</span><span class="nf">prime?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">}]</span> <span class="p">}</span>

  <span class="n">x</span><span class="p">.</span><span class="nf">compare!</span>
<span class="k">end</span>

<span class="c1"># ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +YJIT [arm64-darwin22]</span>
<span class="c1"># Warming up --------------------------------------</span>
<span class="c1">#  reverse_each.detect     7.306k i/100ms</span>
<span class="c1">#          filter.last     1.000 i/100ms</span>
<span class="c1">#               rindex     7.623k i/100ms</span>
<span class="c1"># Calculating -------------------------------------</span>
<span class="c1">#  reverse_each.detect     73.400k (± 1.2%) i/s -    372.606k in   5.077127s</span>
<span class="c1">#          filter.last      8.764 (± 0.0%) i/s -     44.000 in   5.025497s</span>
<span class="c1">#               rindex     76.693k (± 1.0%) i/s -    388.773k in   5.069692s</span>

<span class="c1"># Comparison:</span>
<span class="c1">#               rindex:    76693.4 i/s</span>
<span class="c1">#  reverse_each.detect:    73400.3 i/s - 1.04x  slower</span>
<span class="c1">#          filter.last:        8.8 i/s - 8750.82x  slower</span>
</code></pre></div></div>

<p>The results are in, and it looks like <code class="language-plaintext highlighter-rouge">Array#rindex</code> is the clear winner! While <code class="language-plaintext highlighter-rouge">reverse_each.detect</code> puts up a valiant effort, it falls just short of the mark. And as for <code class="language-plaintext highlighter-rouge">filter.last</code>, well, let’s just say it’s taking the scenic route… at a snail’s pace.</p>]]></content><author><name></name></author><category term="ruby" /><summary type="html"><![CDATA[One of the things that sets Ruby apart from other programming languages is its impressive set of built-in features. One of my favourite method is Enumerable#detect. It returns the first element for which the block yields a truthy value and stops searching upon the first hit.]]></summary></entry></feed>