<?xml version="1.0" encoding="utf-8"?>
    <feed xmlns="http://www.w3.org/2005/Atom">
     <title>BigBinary Blog</title>
     <link href="https://www.bigbinary.com/feed.xml" rel="self"/>
     <link href="https://www.bigbinary.com/"/>
     <updated>2026-03-06T01:48:01+00:00</updated>
     <id>https://www.bigbinary.com/</id>
     <entry>
       <title><![CDATA[Ruby 2.7 adds Beginless Range]]></title>
       <author><name>Ashwath Biradar</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-7-adds-beginless-range"/>
      <updated>2020-08-25T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-7-adds-beginless-range</id>
      <content type="html"><![CDATA[<p>Ruby 2.7 added support for<a href="https://ruby-doc.org/core-2.7.0/Range.html#class-Range-label-Beginless-2FEndless+Ranges">Beginless Range</a>which makes the start of range an optional parameter.</p><p><code>(..100)</code> is a Beginless Range and it is equivalent to <code>(nil..100)</code>.</p><p>Let's see how Beginless Range could be used.</p><pre><code class="language-ruby">&gt; array = (1..10).to_a# Select first 6 elements&gt; array[..5]=&gt; [1, 2, 3, 4, 5, 6]# Select first 5 elements&gt; array[...5]=&gt; [1, 2, 3, 4, 5]# grep (INFINITY..5) in (1..5)&gt; (1..10).grep(..5)=&gt; [1, 2, 3, 4, 5]# (..100) is equivalent to (nil..100)&gt; (..100) == (nil..100)=&gt; true</code></pre><p>Here is another example where in the <code>case</code> statement the condition can be readas <code>below the specified level</code>.</p><pre><code class="language-ruby">case temperaturewhen ..-15  puts &quot;Deep Freeze&quot;when -15..8  puts &quot;Refrigerator&quot;when 8..15  puts &quot;Cold&quot;when 15..25  puts &quot;Room Temperature&quot;when (25..)   # Kindly notice the brackets here  puts &quot;Hot&quot;end</code></pre><p>It can also be used for defining constants for ranges.</p><pre><code class="language-ruby">TEMPERATURE = {  ..-15  =&gt; :deep_freeze,  -15..8 =&gt; :refrigerator,  8..15  =&gt; :cold,  15..25 =&gt; :room_temperature,  25..   =&gt; :hotend</code></pre><p>Using Beginless Range in DSL makes it easier to write conditions and it looksmore natural.</p><pre><code class="language-ruby"># In RailsUser.where(created_at: (..DateTime.now))# User Load (2.2ms)  SELECT &quot;users&quot;.* FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;created_at&quot; &lt;= $1 LIMIT $2  [[&quot;created_at&quot;, &quot;2020-08-05 15:00:19.111217&quot;], [&quot;LIMIT&quot;, 11]]# In RubySpecruby_version(..'1.9') do# Tests for old Rubyend</code></pre><p>Here is the relevant<a href="https://github.com/ruby/ruby/commit/95f7992b89efd35de6b28ac095c4d3477019c583">commit</a>and <a href="https://bugs.ruby-lang.org/issues/14799">discussion</a> regarding this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.7 adds Enumerable#filter_map]]></title>
       <author><name>Ashik Salman</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-7-adds-enumerable-filter-map"/>
      <updated>2020-05-08T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-7-adds-enumerable-filter-map</id>
      <content type="html"><![CDATA[<p>Ruby 2.7 adds<a href="https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-filter_map">Enumerable#filter_map</a>which is a combination of filter + map as the name indicates. The 'filter_map'method filters and map the enumerable elements within a single iteration.</p><p>Before Ruby 2.7, we could have achieved the same with 2 iterations using<code>select</code> &amp; <code>map</code> combination or <code>map</code> &amp; <code>compact</code> combination.</p><pre><code class="language-ruby">irb&gt; numbers = [3, 6, 7, 9, 5, 4]# we can use select &amp; map to find square of odd numbersirb&gt; numbers.select { |x| x.odd? }.map { |x| x**2 }=&gt; [9, 49, 81, 25]# or we can use map &amp; compact to find square of odd numbersirb&gt; numbers.map { |x| x**2 if x.odd? }.compact=&gt; [9, 49, 81, 25]</code></pre><h4>Ruby 2.7</h4><p>Ruby 2.7 adds <code>Enumerable#filter_map</code> which can be used to filter &amp; map theelements in a single iteration and which is more faster when compared to otheroptions described above.</p><pre><code class="language-ruby">irb&gt; numbers = [3, 6, 7, 9, 5, 4]irb&gt; numbers.filter_map { |x| x**2 if x.odd? }=&gt; [9, 49, 81, 25]</code></pre><p>The original discussion had started<a href="https://bugs.ruby-lang.org/issues/5663">8 years back</a>. Here is the latest<a href="https://bugs.ruby-lang.org/issues/15323">thread</a> and<a href="https://github.com/ruby/ruby/pull/2017/commits/38e04e15bf1d4e67c52630fa3fca1d4a056ea768">github commit</a>for reference.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.7 deprecates conversion of keyword arguments]]></title>
       <author><name>Taha Husain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-7-deprecates-conversion-of-keyword-arguments"/>
      <updated>2020-04-14T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-7-deprecates-conversion-of-keyword-arguments</id>
      <content type="html"><![CDATA[<p>A notable change has been announced for Ruby 3 for which deprecation warning hasbeen added in Ruby 2.7. Ruby 2.7 deprecated automatic conversion of keywordarguments and positional arguments. This conversion will be completely removedin Ruby 3.</p><p><a href="https://github.com/ruby/ruby/blob/4643bf5d55af6f79266dd67b69bb6eb4ff82029a/doc/NEWS-2.7.0#the-spec-of-keyword-arguments-is-changed-towards-30-">Ruby 2.7 NEWS</a>has listed the spec of keyword arguments for Ruby 3.0. We will take the examplesmentioned there and for each scenario we will look into how we can fix them inthe existing codebase.</p><h4>Scenario 1</h4><p><em>When method definition accepts keyword arguments as the last argument.</em></p><pre><code class="language-ruby">def sum(a: 0, b: 0)  a + bend</code></pre><p>Passing exact keyword arguments in a method call is acceptable, but inapplications we usually pass a hash to a method call.</p><pre><code class="language-ruby">sum(a: 2, b: 4) # OKsum({ a: 2, b: 4 }) # Warned</code></pre><p>In this case, we can add a double splat operator to the hash to avoiddeprecation warning.</p><pre><code class="language-ruby">sum(**{ a: 2, b: 4 }) # OK</code></pre><h4>Scenario 2</h4><p><em>When method call passes keyword arguments but does not pass enough requiredpositional arguments.</em></p><p>If the number of positional arguments doesn't match with method definition, thenkeyword arguments passed in method call will be considered as the lastpositional argument to the method.</p><pre><code class="language-ruby">def sum(num, x: 0)  num.values.sum + xend</code></pre><pre><code class="language-ruby">sum(a: 2, b: 4) # Warnedsum(a: 2, b: 4, x: 6) # Warned</code></pre><p>To avoid deprecation warning and for code to be compatible with Ruby 3, weshould pass hash instead of keyword arguments in method call.</p><pre><code class="language-ruby">sum({ a: 2, b: 4 }) # OKsum({ a: 2, b: 4}, x: 6) # OK</code></pre><h4>Scenario 3</h4><p><em>When a method accepts a hash and keyword arguments but method call passes onlyhash or keyword arguments.</em></p><p>If a method arguments are a mix of symbol keys and non-symbol keys, and themethod definition accepts either one of them then Ruby splits the keywordarguments but also raises a warning.</p><pre><code class="language-ruby">def sum(num={}, x: 0)  num.values.sum + xend</code></pre><pre><code class="language-ruby">sum(&quot;x&quot; =&gt; 2, x: 4) # Warnedsum(x: 2, &quot;x&quot; =&gt; 4) # Warned</code></pre><p>To fix this warning, we should pass hash separately as defined in the methoddefinition.</p><pre><code class="language-ruby">sum({ &quot;x&quot; =&gt; 4 }, x: 2) # OK</code></pre><h4>Scenario 4</h4><p><em>When an empty hash with double splat operator is passed to a method thatdoesn't accept keyword arguments.</em></p><p>Passing keyword arguments using double splat operator to a method that doesn'taccept keyword argument will send empty hash similar to earlier version of Rubybut will raise a warning.</p><pre><code class="language-ruby">def sum(num)  num.values.sumend</code></pre><pre><code class="language-ruby">numbers = {}sum(**numbers) # Warned</code></pre><p>To avoid this warning, we should change method call to pass hash instead ofusing double splat operator.</p><pre><code class="language-ruby">numbers = {}sum(numbers) # OK</code></pre><hr><h3>Added support for non-symbol keys</h3><p>In Ruby 2.6.0, support for non-symbol keys in method call was removed. It isadded back in Ruby 2.7. When method accepts arbitrary keyword arguments usingdouble splat operator then non-symbol keys can also be passed.</p><pre><code class="language-ruby">def sum(**num)  num.values.sumend</code></pre><h5>ruby 2.6.5</h5><pre><code class="language-ruby">sum(&quot;x&quot; =&gt; 4, &quot;y&quot; =&gt; 3)=&gt; ArgumentError (wrong number of arguments (given 1, expected 0))sum(x: 4, y: 3)=&gt; 7</code></pre><h5>ruby 2.7.0</h5><pre><code class="language-ruby">sum(&quot;x&quot; =&gt; 4, &quot;y&quot; =&gt; 3)=&gt; 7sum(x: 4, y: 3)=&gt; 7</code></pre><hr><h3>Added support for <code>**nil</code></h3><p>Ruby 2.7 added support for <code>**nil</code> to explicitly mention if a method doesn'taccept any keyword arguments in method call.</p><pre><code class="language-ruby">def sum(a, b, **nil)  a + bendsum(2, 3, x: 4)=&gt; ArgumentError (no keywords accepted)</code></pre><hr><p>To suppress above deprecation warnings we can use<a href="https://github.com/ruby/ruby/blob/4643bf5d55af6f79266dd67b69bb6eb4ff82029a/doc/NEWS-2.7.0#warning-option-"><code>-W:no-deprecated option</code></a>.</p><p>In conclusion, Ruby 2.7 has worked big steps towards changing specification ofkeyword arguments which will be completely changed in Ruby 3.</p><p>For more information on discussion, code changes and official documentation,please head to <a href="https://bugs.ruby-lang.org/issues/14183">Feature #14183</a>discussion, <a href="https://github.com/ruby/ruby/pull/2395">pull request</a> and<a href="https://github.com/ruby/ruby/blob/4643bf5d55af6f79266dd67b69bb6eb4ff82029a/doc/NEWS-2.7.0#the-spec-of-keyword-arguments-is-changed-towards-30-">NEWS release</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.7 adds Enumerator::Lazy#eager]]></title>
       <author><name>Ashik Salman</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-7-adds-enumerator-lazy-eager"/>
      <updated>2020-03-18T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-7-adds-enumerator-lazy-eager</id>
      <content type="html"><![CDATA[<p>Ruby 2.0 introduced<a href="https://ruby-doc.org/core-2.7.0/Enumerator/Lazy.html"><code>Enumerator::Lazy</code></a>, aspecial type of enumerator which helps us in processing chains of operations ona collection without actually executing it instantly.</p><p>By applying<a href="https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-lazy"><code>Enumerable#lazy</code></a>method on any enumerable object, we can convert that object into<code>Enumerator::Lazy</code> object. The chains of actions on this lazy enumerator will beevaluated only when it is needed. It helps us in processing operations on largecollections, files and infinite sequences seamlessly.</p><pre><code class="language-ruby"># This line of code will hang and you will have to quit the console by Ctrl+C.irb&gt; list = (1..Float::INFINITY).select { |i| i%3 == 0 }.reject(&amp;:even?)# Just adding `lazy`, the above line of code now executes properly# and returns result without going to infinite loop. Here the chains of# operations are performed as and when it is needed.irb&gt; lazy_list = (1..Float::INFINITY).lazy.select { |i| i%3 == 0 }.reject(&amp;:even?)=&gt; #&lt;Enumerator::Lazy: ...&gt;irb&gt; lazy_list.first(5)=&gt; [3, 9, 15, 21, 27]</code></pre><p>When we chain more operations on <code>Enumerable#lazy</code> object, it again returns lazyobject without executing it. So, when we pass lazy objects to any method whichexpects a normal enumerable object as an argument, we have to force evaluationon lazy object by calling<a href="https://ruby-doc.org/core-2.7.0/Enumerator/Lazy.html#method-i-to_a"><code>to_a</code></a>method or it's alias<a href="https://ruby-doc.org/core-2.7.0/Enumerator/Lazy.html#method-i-force"><code>force</code></a>.</p><pre><code class="language-ruby"># Define a lazy enumerator object.irb&gt; list = (1..30).lazy.select { |i| i%3 == 0 }.reject(&amp;:even?)=&gt; #&lt;Enumerator::Lazy: #&lt;Enumerator::Lazy: ... 1..30&gt;:select&gt;:reject&gt;# The chains of operations will return again a lazy enumerator.irb&gt; result = list.select { |x| x if x &lt;= 15 }=&gt; #&lt;Enumerator::Lazy: #&lt;Enumerator::Lazy: ... 1..30&gt;:select&gt;:reject&gt;:map&gt;# It returns error when we call usual array methods on result.irb&gt; result.sampleirb&gt; NoMethodError (undefined method `sample'irb&gt; for #&lt;Enumerator::Lazy:0x00007faab182a5d8&gt;)irb&gt; result.lengthirb&gt; NoMethodError (undefined method `length'irb&gt; for #&lt;Enumerator::Lazy:0x00007faab182a5d8&gt;)# We can call the normal array methods on lazy object after forcing# its actual execution with methods as mentioned above.irb&gt; result.force.sample=&gt; 9irb&gt; result.to_a.length=&gt; 3</code></pre><p>The<a href="https://ruby-doc.org/core-2.7.0/Enumerator/Lazy.html#method-i-eager"><code>Enumerable#eager</code></a>method returns a normal enumerator from a lazy enumerator, so that lazyenumerator object can be passed to any methods which expects a normal enumerableobject as an argument. Also, we can call other usual array methods on thecollection to get desired results.</p><pre><code class="language-ruby"># By adding eager on lazy object, the chains of operations would return# actual result here. If lazy object is passed to any method, the# processed result will be received as an argument.irb&gt; eager_list = (1..30).lazy.select { |i| i%3 == 0 }.reject(&amp;:even?).eager=&gt; #&lt;Enumerator: #&lt;Enumerator::Lazy: ... 1..30&gt;:select&gt;:reject&gt;:each&gt;irb&gt; result = eager_list.select { |x| x if x &lt;= 15 }irb&gt; result.sample=&gt; 9irb&gt; result.length=&gt; 3</code></pre><p>The same way, we can use <code>eager</code> method when we pass lazy enumerator as anargument to any method which expects a normal enumerator.</p><pre><code class="language-ruby">irb&gt; list = (1..10).lazy.select { |i| i%3 == 0 }.reject(&amp;:even?)irb&gt; def display(enum)irb&gt;   enum.map { |x| p x }irb&gt; endirb&gt;  display(list)=&gt; #&lt;Enumerator::Lazy: #&lt;Enumerator::Lazy: ... 1..30&gt;:select&gt;:reject&gt;:map&gt;irb&gt; eager_list = (1..10).lazy.select { |i| i%3 == 0 }.reject(&amp;:even?).eagerirb&gt; display(eager_list)=&gt; 3=&gt; 9</code></pre><p>Here's the relevant<a href="https://github.com/ruby/ruby/commit/1d4bd229b898671328c2a942b04f08065c640c28">commit</a>and <a href="https://bugs.ruby-lang.org/issues/15901">feature discussion</a> for thischange.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.7 adds numbered parameters as default block parameters]]></title>
       <author><name>Taha Husain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-7-introduces-numbered-parameters-as-default-block-parameters"/>
      <updated>2020-03-03T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-7-introduces-numbered-parameters-as-default-block-parameters</id>
      <content type="html"><![CDATA[<p>At some point, all of us have used names like <code>a</code>, <code>n</code>, <code>i</code> etc for blockparameters. Below are few examples where numbered parameters can come in handy.</p><pre><code class="language-ruby">&gt; (1..10).each { |n| p n * 3 }&gt; { a: [1, 2, 3], b: [2, 4, 6], c: [3, 6, 9] }.each { |_k, v| p v }&gt; [10, 100, 1000].each_with_index { |n, i| p n, i }</code></pre><p>Ruby 2.7 introduces a new way to access block parameters. Ruby 2.7 onwards, ifblock parameters are obvious and we wish to not use absurd names like <code>n</code> or <code>i</code>etc, we can use numbered parameters which are available inside a block bydefault.</p><p>We can use **1_ for first parameter, **2_ for second parameter and so on.</p><p>Here's how Ruby 2.7 provides numbered parameters inside a block. Below shown arethe examples from above, only this time using numbered parameters.</p><pre><code class="language-ruby">&gt; (1..10).each { p _1 * 3 }&gt; { a: [1, 2, 3], b: [2, 4, 6], c: [3, 6, 9] }.each { p _2 }&gt; [10, 100, 1000].each_with_index { p _1, _2 }</code></pre><p>Like mentioned in<a href="https://github.com/ruby/ruby/blob/7f6bd6bb1c2220d2d7c17b77abf52fb4af548001/doc/NEWS-2.7.0#numbered-parameters">News-2.7.0 docs</a>,Ruby now raises a warning if we try to define local variable in the format <code>_1</code>.Local variable will have precedence over numbered parameter inside the block.</p><pre><code class="language-ruby">&gt; _1 = 0&gt; =&gt; warning: `_1' is reserved for numbered parameter; consider another name&gt; [10].each { p _1 }&gt; =&gt; 0</code></pre><p>Numbered parameters are not accessible inside the block if we define ordinaryparameters. If we try to access <code>_1</code> when ordinary parameters are defined, thenruby raises <code>SyntaxError</code> like shown below.</p><pre><code class="language-ruby">&gt; [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;].each_with_index { |alphabet, index| p _1, _2}=&gt; SyntaxError ((irb):1: ordinary parameter is defined)</code></pre><p>This feature was suggested 9 years back and came back in discussion last year.After many suggestions community agreed to use <code>_1</code> syntax.</p><p>Head to following links to read the discussion behind numbered parameters,<a href="https://bugs.ruby-lang.org/issues/4475">Feature #4475</a> and<a href="https://bugs.ruby-lang.org/issues/15723">Discussion #15723</a>.</p><p>Here's relevant<a href="https://github.com/ruby/ruby/commit/12acc751e3e7fd6f8aec33abf661724ad76c862a">commit</a>for this feature.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.7 adds Enumerable#tally]]></title>
       <author><name>Akhil Gautam</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-7-adds-enumerable-tally"/>
      <updated>2020-02-18T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-7-adds-enumerable-tally</id>
      <content type="html"><![CDATA[<p>Let's say that we have to find the frequency of each element of an array.</p><p>Before Ruby 2.7, we could have achieved it using <code>group_by</code> or <code>inject</code>.</p><pre><code class="language-ruby">irb&gt; scores = [100, 35, 70, 100, 70, 30, 35, 100, 45, 30]# we can use group_by to group the scoresirb&gt; scores.group_by { |v| v }.map { |k, v| [k, v.size] }.to_h=&gt; {100=&gt;3, 35=&gt;2, 70=&gt;2, 30=&gt;2, 45=&gt;1}# or we can use inject to group the scoresirb&gt; scores.inject(Hash.new(0)) {|hash, score| hash[score] += 1; hash }=&gt; {100=&gt;3, 35=&gt;2, 70=&gt;2, 30=&gt;2, 45=&gt;1}</code></pre><h4>Ruby 2.7</h4><p>Ruby 2.7 adds <code>Enumerable#tally</code> which can be used to find the frequency.<code>Tally</code> makes the code more readable and intuitive. It returns a hash where keysare the unique elements and values are its corresponding frequency.</p><pre><code class="language-ruby">irb&gt; scores = [100, 35, 70, 100, 70, 30, 35, 100, 45, 30]irb&gt; scores.tally=&gt; {100=&gt;3, 35=&gt;2, 70=&gt;2, 30=&gt;2, 45=&gt;1}</code></pre><p>Check out the<a href="https://github.com/ruby/ruby/commit/673dc51c251588be3c9f4b5b5486cd80d46dfeee">github commit</a>for more details on this.</p>]]></content>
    </entry>
     </feed>