<?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-06T02:59:54+00:00</updated>
     <id>https://www.bigbinary.com/</id>
     <entry>
       <title><![CDATA[Debugging a Stack Overflow in Rails 7.2.1.1]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/debugging-stack-overflow-in-rails"/>
      <updated>2025-11-25T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/debugging-stack-overflow-in-rails</id>
      <content type="html"><![CDATA[<p>A few weeks ago, after upgrading <a href="https://www.neeto.com/neetocal">NeetoCal</a> fromRails 7.1.5.2 to Rails 7.2.1.1, we started seeing mysterious crashes inproduction with the error message <code>SystemStackError: stack level too deep</code>.</p><h2>Identifying the problem</h2><p>The crash happened inside <code>Slots::SyncAllCalendarsService</code>, a service that syncsmultiple calendars concurrently using the <code>Async</code> gem. What made it particularlypuzzling was that switching from <code>Async::Barrier</code> to <code>Thread.new</code> made the errordisappear. This led us down a rabbit hole thinking it was an Async-specificissue.</p><p>The stack trace pointed to a strange location:</p><pre><code>activerecord (7.2.1.1) lib/arel/visitors/to_sql.rb:898:in `each'  from lib/arel/visitors/to_sql.rb:898:in `each_with_index'  from lib/arel/visitors/to_sql.rb:898:in `inject_join'  from lib/arel/visitors/to_sql.rb:627:in `visit_Arel_Nodes_Or'  ... 1132 levels...</code></pre><p>Over a thousand levels deep into <code>visit_Arel_Nodes_Or</code>. That's unusual. Whywould visiting OR nodes in a SQL query cause such deep recursion?</p><p>The stack trace mentioned <code>Slots::SyncAllCalendarsService</code>, but that serviceitself had nothing obviously wrong. It was just iterating through calendars andsyncing them. We traced deeper into the code and found the actual culprit inNeeto's <code>Integrations::Icloud::SyncEventsService</code>:</p><pre><code class="language-ruby">def abandoned_events  pairs = event_params.map { |e| [e[:url], e[:recurrence_id]] }  @_abandoned_events = calendar.events    .where(&quot;start_time BETWEEN ? AND ?&quot;, start_time, end_time)    .where.not([:url, :recurrence_id] =&gt; pairs)end</code></pre><p>This code finds &quot;abandoned&quot; events by excluding events that match specific URLand recurrence ID combinations. In production, <code>pairs</code> contained 233 entries.Nothing immediately suspicious, right?</p><p>To understand what was happening, we needed to see what Rails was actually doingwith this query. The <code>where.not([:url, :recurrence_id] =&gt; pairs)</code> syntax isRails' composite key feature. With 233 pairs, Rails generates SQL like this:</p><pre><code class="language-sql">WHERE NOT (  (url = 'url1' AND recurrence_id = 'rec1') OR  (url = 'url2' AND recurrence_id = 'rec2') OR  (url = 'url3' AND recurrence_id = 'rec3') OR  -- ... 230 more OR clauses)</code></pre><p>233 OR clauses. That's a lot, but databases can handle it. The problem wasn'tthe SQL itself - it was how Rails built the internal representation of thatquery.</p><h2>Going into Rails Internals</h2><p>To really understand what changed, we used <code>bundle open activerecord</code> to look atthe Rails source code. We compared the same code in Rails 7.1.5.2 and 7.2.1.1.</p><h3>What We Found in Rails 7.1.5.2</h3><p>In Rails 7.1.5.2, the code that visits OR nodes looked like this:</p><pre><code class="language-ruby">def visit_Arel_Nodes_Or(o, collector)  stack = [o.right, o.left]  while o = stack.pop    if o.is_a?(Arel::Nodes::Or)      stack.push o.right, o.left    else      visit o, collector      collector &lt;&lt; &quot; OR &quot; unless stack.empty?    end  end  collectorend</code></pre><p>This is an iterative approach using a manual stack. No matter how deeply nestedthe OR conditions are, this code only uses a single stack frame for the<code>visit_Arel_Nodes_Or</code> method. It's stack-safe.</p><h3>What Changed in Rails 7.2.1.1</h3><p>In Rails 7.2.1.1, the same method became much simpler:</p><pre><code class="language-ruby">def visit_Arel_Nodes_Or(o, collector)  inject_join o.children, collector, &quot; OR &quot;end</code></pre><p>Where <code>inject_join</code> does:</p><pre><code class="language-ruby">def inject_join(list, collector, join_str)  list.each_with_index do |x, i|    collector &lt;&lt; join_str unless i == 0    collector = visit(x, collector)  # Recursive call  end  collectorend</code></pre><p>This is a recursive approach. If an OR node contains another OR node, it calls<code>visit</code>, which calls <code>visit_Arel_Nodes_Or</code>, which calls <code>inject_join</code> again. Therecursion depth grows with the nesting depth of the OR tree.</p><h2>The Tree Structure Problem</h2><p>But why is the OR tree so deeply nested? We found the answer in Active Record's<code>PredicateBuilder#grouping_queries</code>:</p><pre><code class="language-ruby">def grouping_queries(queries)  if queries.one?    queries.first  else    queries.map! { |query| query.reduce(&amp;:and) }    queries = queries.reduce { |result, query| Arel::Nodes::Or.new([result, query]) }    Arel::Nodes::Grouping.new(queries)  endend</code></pre><p>That <code>reduce</code> call is the key. It builds a left-deep nested tree:</p><pre><code>Level 1:  Query1 OR Query2 = OR_Node_1Level 2:  OR_Node_1 OR Query3 = OR_Node_2Level 3:  OR_Node_2 OR Query4 = OR_Node_3...Level 232: OR_Node_231 OR Query233 = OR_Node_232</code></pre><p>With 233 pairs, this creates 232 levels of nesting. Each level addsapproximately 5 stack frames when Rails traverses it recursively. That's 1,160stack frames just for the query building.</p><h2>The Async Connection</h2><p>Why did <code>Thread.new</code> work but <code>Async::Barrier</code> didn't?</p><p>We wrote a test script to measure the actual stack depth limits in differentcontexts:</p><pre><code class="language-ruby">def test_recursion_depth(context_name)  depth = 0  recurse = lambda do |n|    depth = n    recurse.call(n + 1)  end  begin    recurse.call(0)  rescue SystemStackError    return depth  endendthread_depth = nilThread.new do  thread_depth = test_recursion_depth(&quot;thread&quot;)end.joinputs &quot;Thread recursion limit: ~#{thread_depth} calls&quot;async_depth = nilAsync do  async_depth = test_recursion_depth(&quot;async&quot;)endputs &quot;Async fiber recursion limit: ~#{async_depth} calls&quot;</code></pre><p>When we ran this, the results were revealing:</p><pre><code>Thread recursion limit:      ~11910 callsAsync fiber recursion limit: ~1482 calls</code></pre><p>Threads have roughly 8x more stack space than Async fibers. This is becausethreads use larger stacks (1MB-8MB) while fibers are designed to be lightweightwith smaller stacks (512KB-1MB). This difference in stack allocation is whythreads can handle deeper recursion before hitting the overflow limit.</p><p>With 233 pairs requiring ~1,160 stack frames, we were right at the edge of theAsync fiber limit. But we were still well within the thread limit, which is whyswitching to <code>Thread.new</code> seemed to fix it.</p><p>When we tested with 500 pairs (which some of our larger calendars had), even<code>Thread.new</code> failed with a stack overflow. So it wasn't really a fix, it justpushed the problem further down the road.</p><h2>The GitHub Trail</h2><p>After we understood the problem, we searched the Rails repository and found theexact history:</p><ol><li><p><strong>April 4, 2024 - <a href="https://github.com/rails/rails/pull/51492">PR #51492</a></strong>:This PR changed OR nodes from <strong>binary</strong> to <strong>n-ary</strong> to handle multiplechildren in a single node.</p></li><li><p><strong>September 24, 2024 -<a href="https://github.com/rails/rails/issues/53031">Issue #53031</a></strong>: Someonereported the exact issue we were seeing. Queries with 800+ OR conditions thatworked in Rails 7.1 now crashed in Rails 7.2.</p></li><li><p><strong>September 25, 2024 -<a href="https://github.com/rails/rails/pull/53032">PR #53032</a></strong>:<a href="https://github.com/fatkodima">fatkodima</a> fixed it with a one-line change in<code>PredicateBuilder#grouping_queries</code>:</p></li></ol><p><strong>Before:</strong></p><pre><code class="language-ruby">queries = queries.reduce { |result, query| Arel::Nodes::Or.new([result, query]) }</code></pre><p><strong>After:</strong></p><pre><code class="language-ruby">queries = Arel::Nodes::Or.new(queries)</code></pre><p>The difference is profound. The old code using <code>reduce</code> created a deeply nestedstructure like Russian nesting dolls:</p><pre><code>Or([Or([Or([Query1, Query2]), Query3]), Query4])  # 232 levels with 233 pairs</code></pre><p>The new code creates a flat structure:</p><pre><code>Or([Query1, Query2, Query3, Query4, ...Query233])  # Just 1 level</code></pre><p>With a flat structure, the recursive visitor only traverses one level instead of232, eliminating the stack overflow. The fix is available in Rails 7.2.2+.</p><h2>Our Solution</h2><p>We're currently on Rails 7.2.1.1 and upgrading immediately would requireextensive testing. So we implemented a workaround in our code:</p><pre><code class="language-ruby">def abandoned_events  return @_abandoned_events if defined?(@_abandoned_events)  pairs = event_params.map { |e| [e[:url], e[:recurrence_id]] }  return if pairs.empty?  events_in_time_range = calendar.events    .where(&quot;start_time BETWEEN ? AND ?&quot;, start_time, end_time)  # Get candidate events using simple IN clauses  urls = pairs.map(&amp;:first).uniq  recurrence_ids = pairs.map(&amp;:last).uniq  candidate_events = events_in_time_range    .where(url: urls)    .where(recurrence_id: recurrence_ids)  # Filter to exact pairs in memory  pairs_set = pairs.to_set  ids_to_exclude = candidate_events.select { |event|    pairs_set.include?([event.url, event.recurrence_id])  }.map(&amp;:id)  @_abandoned_events = if ids_to_exclude.empty?    events_in_time_range  else    events_in_time_range.where.not(id: ids_to_exclude)  endend</code></pre><p>This approach:</p><ul><li>Uses simple IN clauses instead of complex OR conditions</li><li>Filters the exact pairs in memory (fast with a Set)</li><li>Excludes by ID, which is a flat list</li><li>Never builds deeply nested Arel nodes</li></ul><p>The trade-off is we run 2 queries instead of 1, but the queries are simpler andmore efficient. The in-memory filtering is negligible since we're alreadyconstrained by time range.</p><h2>Measuring and Verifying</h2><p>To prove our hypothesis, we wrote verification scripts that patched Railsinternals to measure what was actually happening.</p><h3>Counting Arel Visitor Calls</h3><p>We created a script that patched <code>visit_Arel_Nodes_Or</code> to count how many timesit was called and how deep the recursion went:</p><pre><code class="language-ruby">module Arel  module Visitors    class ToSql      alias_method :original_visit_Arel_Nodes_Or, :visit_Arel_Nodes_Or      def visit_Arel_Nodes_Or(o, collector)        @or_call_count ||= 0        @or_call_count += 1        @max_depth ||= 0        @current_depth ||= 0        @current_depth += 1        @max_depth = [@max_depth, @current_depth].max        result = original_visit_Arel_Nodes_Or(o, collector)        @current_depth -= 1        result      end    end  endend</code></pre><p>Results with 50 test pairs:</p><ul><li><strong>Rails 7.1.5.2</strong>: <code>visit_Arel_Nodes_Or</code> was called 1 time and max recursiondepth was 0.</li><li><strong>Rails 7.2.1.1</strong>: <code>visit_Arel_Nodes_Or</code> was called 49 times and max recursiondepth was 100.</li></ul><p>With 233 pairs in production:</p><ul><li><strong>Rails 7.1.5.2</strong>: Still called 1 time, depth 0 (iterative approach)</li><li><strong>Rails 7.2.1.1</strong>: Called 232 times, depth ~466 (exceeds Async fiber limit)</li></ul><h3>Testing the Actual Breaking Points</h3><p>We ran the problematic query with different pair counts to find exactly where itbreaks:</p><pre><code class="language-ruby"># Test with AsyncAsync do  pairs = calendar.events.limit(count).pluck(:url, :recurrence_id)  calendar.events.where.not([:url, :recurrence_id] =&gt; pairs).countend.wait# Test with ThreadThread.new do  pairs = calendar.events.limit(count).pluck(:url, :recurrence_id)  calendar.events.where.not([:url, :recurrence_id] =&gt; pairs).countend.join</code></pre><p>Results:</p><ul><li><strong>Async Fiber</strong>: Breaks at approximately 233 pairs</li><li><strong>Thread.new</strong>: Breaks at approximately 500 pairs</li></ul><p>This confirmed that Thread.new wasn't a real solution - it just had moreheadroom before hitting the same problem.</p><p>For now, we're sticking with our workaround. It works reliably, performs well,and doesn't require upgrading Rails immediately. When we do upgrade to Rails7.2.2+, we can revert to the original clean syntax, knowing that the Rails teamhas fixed the underlying issue.</p><p>If you're on Rails 7.2.0 through 7.2.1.x and use composite key queries withlarge datasets, watch out for this issue. The fix is in Rails 7.2.2+, or you canwork around it like we did.</p><h2>References</h2><ul><li><a href="https://github.com/rails/rails/pull/51492">PR #51492 - Bug introduced</a></li><li><a href="https://github.com/rails/rails/issues/53031">Issue #53031 - Bug reported</a></li><li><a href="https://github.com/rails/rails/pull/53032">PR #53032 - Bug fixed</a></li></ul>]]></content>
    </entry><entry>
       <title><![CDATA[Active Record adds support for deprecating associations]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/active-record-deprecated-associations"/>
      <updated>2025-07-03T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/active-record-deprecated-associations</id>
      <content type="html"><![CDATA[<p>In Rails8, we can now mark ActiveRecord associations as deprecated. This makesit easy to phase out old associations from our codebase, while still keepingthem around to safely remove their usage. Whenever a deprecated association isused, whether by calling the association, executing a query that references it,or triggering a sideeffect like <code>:dependent</code> or <code>:touch</code>, Rails will alert usaccording to our chosen reporting mode.</p><h3>Marking an association as deprecated</h3><p>Simply pass the <code>deprecated: true</code> option when declaring an association.</p><pre><code class="language-ruby">class User &lt; ApplicationRecord  has_many :meetings, deprecated: trueend</code></pre><p>Now, every time the meeting association is invoked, well get a deprecationwarning in our logs.</p><pre><code class="language-bash">&gt; user.meetingsThe association User#meetings is deprecated, the method meetings was invoked ((calendar):4:in '&lt;main&gt;')&gt; User.includes(:meetings).where(id: 1)The association User#meetings is deprecated, referenced in query to preload records ()&gt; User.joins(:meetings).where(id: 1)The association User#meetings is deprecated, referenced in query to join its table ()</code></pre><h3>Working with different association types</h3><p>We can deprecate any association type.</p><pre><code class="language-ruby">class Order &lt; ApplicationRecord  # has_many  has_many :line_items, deprecated: true  # belongs_to  belongs_to :customer, deprecated: true  # has_one  has_one :profile, deprecated: true  # has_many through  has_many :archived_comments, through: :comments, deprecated: trueend</code></pre><h3>Reporting modes and backtrace support</h3><p>This feature supports three deprecation modes:</p><ul><li><code>:warn</code> (default) Logs a warning to our ActiveRecord logger.</li><li><code>:raise</code> Raises an exception when the deprecated association is used.</li><li><code>:notify</code> Emits an Active Support notification event with the key<code>deprecated_association.active_record</code>. This can be used to send notificationsto external services like Honeybadger etc. We can check the details about itspayload<a href="https://edgeguides.rubyonrails.org/active_support_instrumentation.html#deprecated-association-active-record">here</a>.</li></ul><p>Backtraces are disabled by default. If <code>:backtrace</code> is true, <code>:warn</code> mode willinclude a clean backtrace in the message, and <code>:notify</code> mode will have a<code>backtrace</code> key in the payload. Exceptions raised via <code>:raise</code> mode will alwayshave a clean stack trace.</p><p>We can change the global default mode in an initializer.</p><pre><code class="language-ruby"># config/initializers/deprecated_associations.rbActiveRecord.deprecated_associations_options = {  mode: :warn,      # :warn | :raise | :notify  backtrace: true   # whether to include a cleaned backtrace}</code></pre><p>It can also be set at an environment level.</p><pre><code class="language-ruby"># config/environments/development.rbRails.application.configure do  config.active_record.deprecated_associations_options = { mode: :raise, backtrace: true }end# config/environments/production.rbRails.application.configure do  config.active_record.deprecated_associations_options = { mode: :warn, backtrace: true }end</code></pre><h3>Why deprecate rather than remove?</h3><p>In large applications, its often hard to guarantee complete test coverage. Someassociation usages may only surface in production.</p><p>Deprecating an association first, lets us:</p><ul><li>Identify every code path (tests, console, background jobs) that relies on it.</li><li>Gradually refactor those references before removal.</li><li>Ensure confidence that deleting the association wont break anythingunexpectedly.</li></ul><p>This new feature in Rails provides a clean and intuitive way to phase out ourassociations with deprecation warnings, making it easier to maintain andrefactor large codebases.</p><p><em>This feature <a href="https://github.com/rails/rails/pull/55285">was merged</a> recently,and will be released in the next Rails minor/patch version.</em></p>]]></content>
    </entry><entry>
       <title><![CDATA[Active Job Continuations]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/active-jobs-continuations"/>
      <updated>2025-06-09T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/active-jobs-continuations</id>
      <content type="html"><![CDATA[<p>Active Job Continuations was recently merged into Rails. We recommend that you gothrough the description in the<a href="https://github.com/rails/rails/issues/55127">pull request</a> since they are sowell written.</p><p>If you prefer watching a video to learn about Active Job Continuations, then wemade a video for you.</p><p>&lt;iframewidth=&quot;560&quot;height=&quot;315&quot;src=&quot;https://www.youtube.com/embed/r4uuQh1Zog0&quot;title=&quot;YouTube video player&quot;frameborder=&quot;0&quot;allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;allowfullscreen</p><blockquote><p>&lt;/iframe&gt;</p></blockquote><p>In short, this feature allows you to configure your jobs in such a manner thatthe job can be interrupted and next time when the job starts, it'll start from aparticular point so that the work done so far is not totally wasted.</p><p>This work is highly inspired by Shopify's<a href="https://github.com/Shopify/job-iteration">job-iteration</a> gem.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Understanding Queueing Theory]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/understanding-queueing-theory"/>
      <updated>2025-06-03T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/understanding-queueing-theory</id>
      <content type="html"><![CDATA[<p><em>This is Part 6 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>.</em></p><hr><h2>Queueing Systems</h2><p>In web applications, not every task needs to be processed immediately. When youupload a large video file, send a bulk email campaign, or generate a complexreport, these time-consuming operations are often handled in the background.This is where queueing systems like <a href="https://sidekiq.org/">Sidekiq</a> or<a href="https://github.com/rails/solid_queue">Solid Queue</a> comes into play.</p><p>Queueing theory helps us understand how these systems behave under differentconditions - from quiet periods to peak load times.</p><p>Let's understand the fundamentals of queueing theory.</p><h2>Basic Terminology in Queueing Theory</h2><ol><li><p><strong>Unit of Work</strong>: This is the individual item needing service - a job.</p></li><li><p><strong>Server</strong>: This is one &quot;unit of parallel processing capacity.&quot; In queuingtheory, this doesn't necessarily mean a physical server. It refers to theability to process one unit of work at a time. For JRuby or TruffleRuby, eachthread can be considered a separate &quot;server&quot; since they can execute inparallel. For CRuby/MRI, because of the GVL, the concept of a &quot;server&quot; isdifferent. We'll discuss it later.</p></li><li><p><strong>Queue Discipline</strong>: This is the rule determining which unit of work isselected next from the queue. For Sidekiq and Solid Queue, it is FCFS(FirstCome First Serve). If there are multiple queues, which job is selecteddepends on the priority of the queue.</p></li><li><p><strong>Service Time</strong>: The actual time it takes to process a unit of work (howlong a job takes to execute).</p></li><li><p><strong>Latency/Wait Time</strong>: How long jobs spend waiting in the queue before beingprocessed.</p></li><li><p><strong>Total Time</strong>: The sum of service time and wait time. It's the completeduration from when a job is enqueued until it finishes executing.</p></li></ol><h2>Little's law</h2><p>Little's law is a theorem in queuing theory that states that the average numberof jobs in a system is equal to the average arrival rate of new jobs multipliedby the average time a job spends in the system.</p><pre><code class="language-ruby">L = W</code></pre><p>L = Average number of jobs in the system <br> = Average arrival rate of new jobs <br>W = Average time a job spends in the system</p><p>For example, if jobs arrive at a rate of 10 per minute (), and each job takes30 seconds (W) to complete:</p><p>Average number of jobs in system = 10 jobs/minute * 0.5 minutes = 5 jobs</p><p>This helps us understand the current state of our system and that there are 5jobs in the system on average at any given moment.</p><p><code>L</code> is also called <strong>offered traffic</strong>.</p><p>Note: Little's Law assumes the arrival rate is consistent over time.</p><h3>Managing Utilization</h3><p>Utilization measures how busy our processing capacity is.</p><p>Mathematically, it is the ratio of how much processing capacity we're using tothe processing capacity we have.</p><pre><code class="language-ruby">utilization = (average number of jobs in the system/capacity to handle jobs) * 100</code></pre><p>In other words, it could be written as follows.</p><pre><code class="language-ruby">utilization = (offered_traffic / parallelism) * 100</code></pre><p>For example, if we are using Sidekiq to manage our background jobs then in asingle-threaded case, parallelism is equal to the number of Sidekiq processes.</p><p>Let's look at a practical case with numbers:</p><ul><li>We have 30 jobs arriving every minute</li><li>It takes 0.5 minutes to process a job</li><li>We have 20 Sidekiq processes</li></ul><p>In this case, the utilization will be:</p><pre><code class="language-ruby">utilization = ((30 jobs/minute * 0.5 minutes) / 20 processes) * 100 = 75%</code></pre><h3>High utilization is bad for performance</h3><p>Let's assume we maintain 100% utilization in our system. It means that if, onaverage, we get 30 jobs per minute, then we have just enough capacity to handle30 jobs per minute.</p><p>One day, we started getting 45 jobs per minute. Since utilization is at 100%,there is no extra room to accommodate the additional load. This leads to higherlatency.</p><p>Hence, having a high utilization rate may result in low performance, as it canlead to higher latency for specific jobs.</p><h3>The knee curve</h3><p>Mathematically, it would seem that only when the utilization rate hits 100%should the latency spike up. However, in the real world, it has been found thatlatency begins to increase dramatically when utilization reaches around 70-75%.</p><p>If we draw a graph between utilization and performance then the graph would looksomething like this.</p><p><img src="/blog_images/2025/understanding-queueing-theory/knee-curve.png" alt="The knee curve"></p><p>The point at which the curve bends sharply upwards is called &quot;Knee&quot; in theperformance curve. At this point, the exponential effects predicted by queueingtheory become pronounced, causing the queue latency to climb up quickly.</p><p>Running any system consistently above 70-75% utilization significantly increasesthe risk of spiking the latency, as jobs spend more and more time waiting.</p><p>This would directly impact the customer experience, as it could result in delaysin sending emails or making calls to Twilio to send SMS messages, etc.</p><p>Tracking this latency will be covered in the upcoming blogs. The tracking ofmetrics depends on the queueing backend used (Sidekiq or Solid Queue).</p><h2>Concurrency and theoretical parallelism</h2><p>In Sidekiq, a process is the primary unit of parallelism. However, concurrency(threads per process) significantly impacts a process's effective throughput.Because of GVL we need to take into account how long the job is waiting for I/O.</p><p>The more time a job spends waiting on external resources (like databases orAPIs) rather than executing Ruby code, the more other threads within the sameprocess can run Ruby code while the first thread waits.</p><p>We learned about Amdahl's law in<a href="/blog/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency">Part 3</a>of this series.</p><p><img src="/blog_images/2025/understanding-queueing-theory/amdahls-law.png" alt="Amdahl's law"></p><p>Where:</p><p><code>p</code> is the portion that can be parallelized (the I/O percentage)</p><p><code>n</code> is the number of threads (concurrency)</p><p>Speedup is equivalent to theoretical parallelism in this context. In queueingtheory, parallelism refers to how many units of work can be processedsimultaneously. When we calculate speedup using Amdahl's Law, we're essentiallydetermining how much faster a multi-threaded system can handle work compared toa single-threaded system.</p><p>Let's assume that a system has an I/O of 50% and a concurrency of 10. ThenSpeedup will be:</p><pre><code class="language-ruby">Speedup = 1 / ((1 - 0.5) + 0.5 / 10) = 1 / 0.55 = 1.82  2</code></pre><p>This means one Sidekiq process with 10 threads will handle jobs twice as fast asSidekiq with a single process with a single thread.</p><p>Let's recap what we are saying here. We are assuming that the system has I/O of50%. System is using a single Sidekiq process with 10 threads(concurrency). Thenbecause of 10 threads the system has a speed gain of 2x compared to systemhaving just a single thread. In other words, just because we have 10 threadsrunning we are not going to gain 10X performance improvement. What those 10threads is getting us is what is called &quot;theoretical parallelism&quot;.</p><p>Similarly, for other values of I/O and Concurrency, we can get the theoreticalparallelism.</p><table><thead><tr><th>I/O</th><th>Concurrency</th><th>Theoretical parallelism</th></tr></thead><tbody><tr><td>5%</td><td>1</td><td>1</td></tr><tr><td>25%</td><td>5</td><td>1.25</td></tr><tr><td>50%</td><td>10</td><td>2</td></tr><tr><td>75%</td><td>16</td><td>3</td></tr><tr><td>90%</td><td>32</td><td>8</td></tr><tr><td>95%</td><td>64</td><td>16</td></tr></tbody></table><p>Let's go over one more time. In the last example, what we are stating is that ifa system has 95% I/O and if the system has 64 threads running, then that willgive 16x performance improvement over the same system running on a singlethread.</p><p>Here is the graph for this data.</p><p><img src="/blog_images/2025/understanding-queueing-theory/concurrency-vs-effective-parallelism.png" alt="Theoretical Parallelism"></p><p>As shown in the graph, a Sidekiq process with 16 threads handling jobs that are75% I/O-bound achieves a theoretical parallelism of approximately 3. In otherwords, 3x performance improvement is there over a single-threaded system.</p><h2>Calculating the number of processes required</h2><p>At the beginning of this article, we discussed &quot;Little's law&quot; and we discussedthat <code>L</code> is also called &quot;offered traffic,&quot; which depicts the &quot;average number ofjobs in the system&quot;.</p><p>If &quot;offered traffic&quot; is 5, then it means we have 5 units of work arriving onaverage that requires processing simultaneously.</p><p>We just learned that if the utilization is greater than 75% then it can causeproblems as there is a risk of latency to spike.</p><p>For queues with low latency requirements(eg. <code>urgent</code>), we need to target alower utilization rate. Let's say we want utilization to be around 50% to be onthe safe side.</p><p>Now we know the utilization rate that we need to target and we know the &quot;offeredtraffic&quot;. So now we can calculate the &quot;parallelism&quot;.</p><pre><code class="language-ruby">utilization = offered_traffic / parallelism=&gt; 0.50 = 5 / parallelism=&gt; parallelism = 5 / 0.50 = 10</code></pre><p>This means we need a theoretical parallelism of 10 to ensure that theutilization is 50% at max.</p><p>Let's assume the jobs in this queue have an average of <code>50%</code> I/O. Based on theabove mentioned graph, we can see that if the concurrency is 10 then we getparallelism of 2. However, increasing the concurrency doesn't increase theparallelism. It means if we want 10 parallelism, then we can't just switch toconcurrency of 50. Even the concurrency of 50 (or 50 threads) will only yield aparallelism of 2.</p><p>So we have no choice but to add more processes. Since one process with 10concurrency is yielding a parallelism of 2 we need to add 5 processes to get 10parallelism.</p><p><em>To get the I/O wait percentage, we can make use of perfm.<a href="https://github.com/bigbinary/perfm?tab=readme-ov-file#sidekiq-gvl-instrumentation">Here</a>is the documentation on how it can be done.</em></p><pre><code class="language-ruby">Total number of Sidekiq processes required = 10 / 2 = 5</code></pre><p>Here we're talking about Sidekiq free version, where we'll only be able to run asingle process per dyno. If we're using Sidekiq Pro, we can run multipleprocesses per dyno via Sidekiq Swarm.</p><p>We can provision 5 dynos for the urgent queue. But we should always have a queuetime based autoscaler like Judoscale enabled to handle spikes.</p><h2>Sources of Saturation</h2><p>We discussed earlier that, in the context of queueing theory, the saturationpoint is typically reached at around 70-75% utilization. This is from the pointof view of further gains by adding more threads.</p><p>However saturation can occur in other parts of the system.</p><h3>CPU</h3><p>The servers running your Sidekiq processes have finite CPU and memory. While CPUusage is a metric we can track for Sidekiq, it's generally not the only one weneed to focus on for scaling decisions.</p><p>CPU utilization can be misleading. If our jobs spend most of their time doingI/O (like making API calls or database queries), in which case CPU usage will bevery low, even when our Sidekiq system is at capacity.</p><h3>Memory</h3><p>Memory utilization impacts performance very differently from CPU utilization.Memory utilization generally exhibits minimal changes in latency or throughputfrom 0% to 100% utilization. However, after 100% utilization, things will startto deteriorate significantly. The system will start using the swap memory, whichcan be very slow and thereby increase the job service times.</p><h3>Redis</h3><p>Another place where saturation can occur is in our datastore i.e Redis in caseof Sidekiq. We have to make sure that we provision a separate Redis instance forSidekiq and also make sure to set the eviction policy to <code>noeviction</code>. Thisensures that Redis will reject new data when the memory limit is reached,resulting in an explicit failure rather than silently dropping important jobs.</p><p><em>This was Part 6 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>. If any part of theblog is not clear to you then please write to us at<a href="https://www.linkedin.com/company/bigbinary">LinkedIn</a>,<a href="https://twitter.com/bigbinary">Twitter</a> or<a href="https://bigbinary.com/contact">BigBinary website</a>.</em></p>]]></content>
    </entry><entry>
       <title><![CDATA[Understanding Active Record Connection Pooling]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/understanding-active-record-connection-pooling"/>
      <updated>2025-05-13T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/understanding-active-record-connection-pooling</id>
      <content type="html"><![CDATA[<p><em>This is Part 5 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>.</em></p><h2>Database Connection Pooling</h2><p>When a Rails application needs to interact with a database, it establishes aconnection, which is a dedicated communication channel between the applicationand the database server. When a new request comes to Rails, the operation can behandled like this.</p><ol><li>Create a connection</li><li>Do database operation</li><li>Close the connection</li></ol><p>When the next request comes, then repeat the above process.</p><p>Creating new database connections is an expensive operation - it takes time toestablish the connection, authenticate, and set up the communication channel. Itmeans that every single time a request comes, we are spending time in setting upthe connection.</p><p>Wouldn't it be better to store the established connection to somewhere and whena new request comes, then get the pre-established connection from this pool.This expedites the process since we don't need to create a connection and closea connection in every single request.</p><p>The new process might look like this.</p><ol><li>Create a connection</li><li>Do database operation</li><li>Put the connection in a pool</li></ol><p>Now, when a new request comes, the operation will look like this.</p><ol><li>Get the connection from the pool</li><li>Do database operation</li><li>Return the connection to the pool</li></ol><p>Database connection pooling is a performance optimization technique thatmaintains a set of reusable database connections.</p><h2>Active Record Connection Pool Implementation</h2><p>Active Record manages a pool of database connections for each web and backgroundprocess. Each process will have a connection pool of its own, which means aRails application running with multiple processes (like Puma processes, Sidekiqprocesses) will have multiple independent connection pools. The pool is a set ofdatabase connections that are shared among threads in the <strong>same process</strong>.</p><p>Note that the pooling happens at the process level. A thread from process Acan't get a connection from process B.</p><p><img src="/blog_images/2025/understanding-active-record-connection-pooling/without-pg-bouncer.png" alt="Connection pooling"></p><p>When a connection is needed, the thread checks out a connection from the pool,perform operations, and then returns the connection to the pool. This is done ata query level now. For each individual query, a connection is leased, used, andthen returned back to the pool.</p><p>Pre Rails 7.2, the connection used to be leased and held till the end of therequest if it is a web request and till the job is done if it is a backgroundjob. This was a problem for applications that spent a lot of time doing I/O. Thethread will hog the connection for the entire duration of the I/O operationlimiting the number of queries that can be executed concurrently. To facilitatethis change and make query caching work, the query cache has been<a href="https://github.com/rails/rails/pull/50938/">updated</a> to be owned by the pool.</p><p>This means that the query cache is now shared across all connections in thepool. Previously, each connection had its own query cache. As the whole requestused the same connection, this was fine. But now, as the connection is leasedfor each query, the query cache needs to be shared across all connections in thepool.</p><p><img src="/blog_images/2025/understanding-active-record-connection-pooling/connection-leasing-comparison.png" alt="Connection-leasing-comparison"></p><h2>Connection Pool Configuration Options</h2><p>Active Record's connection pool behavior can be customized through severalconfiguration options in the database.yml file:</p><ul><li><a href="https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html#method-i-pool">pool</a>:Sets the maximum number of connections the pool will maintain. The default istied to <code>RAILS_MAX_THREADS</code>, but you can set it to any value. There is a smallproblem when you set it to <code>RAILS_MAX_THREADS</code> which we'll discuss later.</li><li><a href="https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html#method-i-checkout_timeout">checkout timeout</a>:Determines how long a thread will wait to get a connection before timing out.The default is 5 seconds. If all connections are in use and a thread waitslonger than this value, an <code>ActiveRecord::ConnectionTimeoutError</code> exceptionwill be raised.</li><li><a href="https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html#method-i-idle_timeout">idle timeout</a>:Specifies how long a connection can remain idle before it's removed from thepool. The default is 300 seconds. This helps reclaim resources fromconnections that aren't being used.</li><li><a href="https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html#method-i-reaping_frequency">reaping frequency</a>:Controls how often the Reaper(which we'll discuss shortly) process runs toremove dead or idle connections. The default is 60 seconds.</li></ul><h2>Active Record Connection Pool Reaper</h2><p>Database connections can sometimes become &quot;dead&quot; due to issues like databaserestarts, network problems etc. Active Record provides Reaper to handle this.</p><p>The Reaper periodically checks connections in the pool and removes deadconnections as well as idle connections that have been checked out for a longtime.</p><p>It acts somewhat like a garbage collector for database connections. The Reaperuses the <code>idle_timeout</code> setting to determine how long a connection can remainidle before being removed, tracking idle time based on when connections werelast used.</p><p>There is another configuration option called <code>reaping_frequency</code> that controlshow often the Reaper runs to remove dead or idle connections from the pool. Bydefault, this is set to 60 seconds. It means the Reaper will wake up once everyminute to perform its maintenance tasks.</p><p>If your application is spiky and receives a lot of traffic in surges, then setthe reaping frequency and idle timeout to a lower value. This will ensure thatthe reaper runs more frequently and removes idle connections more quickly,helping to keep the connection pool healthy and responsive.</p><h2>Why are idle connections bad?</h2><p>Idle database connections can significantly impact database performance forseveral interconnected reasons:</p><p><strong>Memory Consumption</strong>: Each database connection, even when idle, maintains itsown memory allocation. The database must reserve memory for session state,buffers, user context, and transaction workspace. This memory remains allocatedeven when the connection isn't doing any work. For example, if each connectionuses 10 MB of memory, 100 idle connections would unnecessarily consume 1 GB ofyour database's memory that could otherwise be used for active queries, caching,or other productive work.</p><p><strong>CPU overhead</strong>: While &quot;idle&quot; suggests no activity, the database still performsregular maintenance work for each connection. It must monitor connection healthvia keepalive checks, manage process tables etc.</p><p>The crucial issue is that the overhead of having idle connections scalesnon-linearly. As we add more idle connections, the database spends an increasingproportion of its CPU time just managing these connections rather thanprocessing actual queries. Thankfully, the reaper handles this for us.</p><h2>How many database connections will the web and background processes utilize at maximum?</h2><p>As we learned, the connection pool is managed at the process level. Each Railsprocess maintains its own pool.</p><ol><li><strong>In web processes (Puma)</strong>:</li></ol><p>Each Puma process is a separate process with its own connection pool. In aprocess, each thread can check out one connection. Therefore, maximumconnections needed per process equals <code>max_threads</code> setting in Puma.</p><ol start="2"><li><strong>In background processes (Sidekiq)</strong>:</li></ol><p>Sidekiq runs as a separate process with its own connection pool. The Sidekiq<code>concurrency</code> setting determines the number of threads and therefore the maximumconnections needed equals the <code>concurrency</code> value.</p><p><em>Note: If you're using Sidekiq swarm and running multiple Sidekiq processes,then take that it into account.</em></p><p>We can calculate the total potential connections for a typical application asshown below.</p><pre><code>Web connections = Number of web dynos * Number of Puma processes                  * `max_threads` valueBackground connections = Number of worker dynos * Number of Sidekiq processes                         * Threads per processTotal number of connections = Web connections + Background connections</code></pre><p>The key thing to note here is that the database needs to support at least thesemany simultaneous connections.</p><p><em>Note that if preboot is enabled, then the maximum number of connections will be<strong>double</strong> the above value. This is because during the release phase, there is asmall window in which both the old dynos and new dynos are running.</em></p><p>In Rails 7,<a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-load_async"><code>load_async</code></a>was introduced which allows us to run database queries asynchronously in abackground thread. When <code>load_async</code> is in used, the calculation for maximumnumber of connections needed changes a bit. First, let's understand how<code>load_async</code> works.</p><h2>How <code>load_async</code> works</h2><p><code>load_async</code> allows Rails to execute database queries asynchronously inbackground threads. Unlike regular ActiveRecord queries which are lazily loaded,<code>load_async</code> queries are always executed immediately in background threads andjoined to the main thread when results are needed.</p><p>The async executor is configured through the<code>config.active_record.async_query_executor</code> setting. There are three possibleconfigurations:</p><ol><li><code>nil</code> (default): Async queries are disabled, and <code>load_async</code> will executequeries synchronously.</li><li><code>:global_thread_pool</code>: Uses a single thread pool for all databaseconnections.</li><li><code>:multi_thread_pool</code>: Uses separate thread pools for each databaseconnection.</li></ol><p>Rails provides a configuration option named<a href="https://guides.rubyonrails.org/configuring.html#config-active-record-global-executor-concurrency">global_executor_concurrency</a>(default: 4) that controls how many concurrent async queries can run perprocess. So, the maximum number of connections per process when <code>load_async</code> isused.</p><pre><code class="language-ruby">Maximum connections per process = Process level concurrency                                  + global_executor_concurrency + 1</code></pre><p>Here Process level concurrency means <code>max_threads</code> for the Puma process and<code>sidekiq_conurrency</code> for the Sidekiq process.</p><p>The &quot;+1&quot; accounts for the main control thread, which may occasionally need aconnection (e.g., during model introspection at class load time).</p><p>There is a nice<a href="https://judoscale.com/tools/heroku-postgresql-connection-calculator">calculator</a>created by the folks at <a href="https://judoscale.com/">Judoscale</a> which can be used tocalculate the maximum number of connections needed for your application.</p><h2>Setting Database Pool Size Configuration</h2><p>Our <code>database.yml</code> file has the following line.</p><pre><code class="language-yaml">pool: &lt;%%= ENV.fetch(&quot;RAILS_MAX_THREADS&quot;) { 5 } %&gt;</code></pre><p>We know that a thread doesn't take more than one DB connection. So the maximumnumber of connections needed per pool is equal to the total number of threads.So the above configuration looks fine.</p><p>However this doesn't take into account whether we use <code>load_async</code> or not. If weuse <code>load_async</code>, then the number of connections needed per process will be<code>RAILS_MAX_THREADS + global_executor_concurrency + 1</code>.</p><p>Do we really need to go into this much detail to determine the pool size? Turnsout there is a much easier answer.</p><p>Almost all database hosting providers mention the maximum number of connectionsallowed in their plan. We can just set the pool config to the maximum number ofconnections supported by our database plan. Let us say we have a Standard-0database on Heroku. It supports up to 120 connections. So we can set the poolconfig to 120.</p><pre><code class="language-yaml">pool: 120</code></pre><p>We can do this because the database connections are lazily initialized in thepool. The application doesn't create more database connections than it needs. Sowe needn't be conservative here.</p><p>The only thing we need to ensure is that the maximum connection utilizationdoesn't exceed the database plan limit. If that happens, then we have anothersolution - PgBouncer.</p><h2>PgBouncer</h2><p>PgBouncer is a lightweight connection pooler for PostgreSQL. It sits between ourapplication(s) and our PostgreSQL database and manages a pool of databaseconnections.</p><p>While both PgBouncer and Active Record provide connection pooling, they operateat different levels and serve different purposes.</p><p>Active Record connection pool operates within a single Ruby process and managesconnections for threads within the process, whereas PgBouncer is an externalconnection pooler that sits between the application and the database and managesconnections across all the application processes.<img src="/blog_images/2025/understanding-active-record-connection-pooling/with-pg-bouncer.png" alt="With PgBouncer"></p><h2>The dreaded ActiveRecord::ConnectionTimeoutError</h2><p>This error comes up when a thread waits more than <code>checkout_timeout</code> seconds toacquire a connection. This usually happens when the <code>pool</code> size is set to avalue less than the concurrency.</p><p>For example, lets say we have set the Sidekiq concurrency to 10 and pool sizeto 5. If we have more than 5 threads wanting a connection at any point of time,the threads will have to wait.</p><p><img src="/blog_images/2025/understanding-active-record-connection-pooling/threads-waiting-for-connection.png" alt="Connection pooling"></p><p>What's the solution? As we discussed earlier setting the <code>pool</code> to a really highvalue should fix the error in most cases.</p><p>Even after setting the config correctly, <code>ActiveRecord::ConnectionTimeoutError</code>can still happen and it could be puzzling. Let is discuss a few scenarios wherethis can happen.</p><h2>Custom code spinning up new threads and taking up connections</h2><pre><code class="language-ruby">class SomeService  def process    threads = []    5.times do |index|      threads &lt;&lt; Thread.new do        ActiveRecord::Base.connection.execute(&quot;select pg_sleep(5);&quot;)      end    end    threads.each(&amp;:join)  endend</code></pre><p>Here 5 threads are spun up. Note that these threads also take up connectionsfrom the same pool allotted to the process.</p><h3>Active Storage proxy mode</h3><p>Even if our application code is not spinning up new threads, Rails itself cansometimes spin up additional threads. For example Active Storage configured in<a href="https://edgeguides.rubyonrails.org/active_storage_overview.html#proxy-mode">proxy mode</a>.</p><p>Active Storages proxy controllers<a href="https://github.com/rails/rails/blob/b97a7625970c74f2273211ccb17046049f409110/activestorage/app/controllers/active_storage/blobs/proxy_controller.rb">1</a>,<a href="https://github.com/rails/rails/blob/b97a7625970c74f2273211ccb17046049f409110/activestorage/app/controllers/active_storage/representations/proxy_controller.rb">2</a>generate responses as streams, which require dedicated threads for processing.</p><p>This means that when serving an Active Storage file through one of these proxycontrollers, Rails actually utilizes two separate threads - one for the mainrequest and another for the streaming process. Each of these threads requiresits own separate database connection from the ActiveRecord connection pool.</p><h3>Rack timeouts</h3><p><a href="https://github.com/zombocom/rack-timeout">rack-timeout</a> is commonly used acrossRails applications to automatically terminate long-running requests. While ithelps prevent server resources from being tied up by slow requests, it can alsocause a few issues.</p><p>Rack timeout uses Ruby's<a href="https://rubyapi.org/3.4/o/thread#method-i-raise">Thread#raise</a> API to terminaterequests that exceed the configured timeout. When a timeout occurs, rack-timeoutraises a <code>Rack::Timeout::RequestTimeoutException</code> from another thread. If thisexception is raised while a thread is in the middle of database operations, itcan prevent proper cleanup of database connections.</p><h2>Tracking down ActiveRecord::ConnectionTimeoutErrors</h2><p>If we still frequently see <code>ActiveRecord::ConnectionTimeoutError</code> exceptions inour application, we can get additional context by logging the connection poolinfo to our error monitoring service. This can help identify which all threadswere holding onto the connections when the error occurred.</p><pre><code class="language-ruby">config.before_notify do |notice|  if notice.error_class == &quot;ActiveRecord::ConnectionTimeoutError&quot;    notice.context = { connection_pool_info: detailed_connection_pool_info }  endenddef detailed_connection_pool_info  connection_info = {}  ActiveRecord::Base.connection_pool.connections.each_with_index do |conn, index|    connection_info[&quot;connection_#{index + 1}&quot;] = conn.owner ? conn.owner.inspect : &quot;[UNUSED]&quot;  end  connection_info[&quot;current_thread&quot;] = Thread.current.inspect  connection_infoend</code></pre><p><code>&lt;thread_obj&gt;.inspect</code> gives us the name, id and status of the thread. Forexample, if one entry in the hash looks like<code>#&lt;Thread:0x00006a42eca73ba0@puma srv tp 002 /app/.../gems/puma-6.2.2/lib/puma/thread_pool.rb:106 sleep_forever&gt;</code>then it means that the connection is taken up by a Puma thread.</p><h2>Monitoring Active Record Connection Pool Stats</h2><p>If we want to monitor Active Record Connection Pool stats, then periodically weneed to send the stats to a service provider which can display the datagraphically. For periodically checking the stat, we are using<a href="https://github.com/jmettraux/rufus-scheduler">rufus-scheduler</a> gem. Forcollecting the data and showing the data we are using NewRelic but you can useany APM of your choice. We have configured to send the pool stat every 15seconds.</p><p><a href="https://gist.github.com/vishnu-m/8cfae21cac385aa07819c8805e491872">Here</a> is thegist which collects and sends data.</p><p><em>This was Part 5 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>. If any part of theblog is not clear to you then please write to us at<a href="https://www.linkedin.com/company/bigbinary">LinkedIn</a>,<a href="https://twitter.com/bigbinary">Twitter</a> or<a href="https://bigbinary.com/contact">BigBinary website</a>.</em></p>]]></content>
    </entry><entry>
       <title><![CDATA[Finding ideal number of threads per process using GVL instrumentation]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/tuning-puma-max-threads-configuration-with-gvl-instrumentation"/>
      <updated>2025-05-06T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/tuning-puma-max-threads-configuration-with-gvl-instrumentation</id>
      <content type="html"><![CDATA[<p><em>This is Part 4 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>.</em></p><p>In<a href="https://bigbinary.com/blog/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance">part 1</a>we saw how to find ideal number of processes for our Rails application.</p><p>In<a href="https://bigbinary.com/blog/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency">part 3</a>,we learned about Amdahl's law, which helps us find the ideal number of threadstheoretically.</p><p>In this blog, we'll run a bunch of tests on our real production application tosee what the actual number of threads should be for each process.</p><p>In<a href="https://bigbinary.com/blog/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance">part 1</a>we discussed the presence of GVL and the concept of thread switching. Based onthe GVL's interaction, a thread can be in one of these three states.</p><ol><li><strong>Running</strong>: The thread has the GVL and is executing Ruby code.</li><li><strong>Idle</strong>: The thread doesn't want the GVL because it is performing I/Ooperations.</li><li><strong>Stalled</strong>: The thread wants the GVL and is waiting for it in the GVL waitqueue.</li></ol><p><img src="/blog_images/2025/tuning-puma-max-threads-configuration-with-gvl-instrumentation/thread-states.png" alt="Thread states"></p><p>Based on the above diagram, we can approximately equate <code>idle time</code> to<code>I/O time</code>.</p><h2>GVL instrumentation using perfm</h2><p>Thanks to Jean Boussier's work on the<a href="https://bugs.ruby-lang.org/issues/18339">GVL instrumentation API</a> and JohnHawthorn's work on <a href="https://github.com/jhawthorn/gvl_timing">gvl_timing</a>, we cannow measure the time a thread spends in each of these states for apps running onRuby 3.2 or higher.</p><p>Using the great work done by these folks, we have created<a href="https://github.com/bigbinary/perfm">perfm</a>, to help us figure out the idealnumber of Puma threads based on the application's workload.</p><p>Perfm inserts a Rack middleware to our Rails application. This middlewareinstruments the GVL, collects the required metrics and stores them in a table.It also has a <code>Perfm::GvlMetricsAnalyzer</code> class which can be used to generate areport on the data collected.</p><h3>Using perfm to measure the application's I/O percentage</h3><p>To use perfm, we need to add the following line to our Gemfile.</p><pre><code class="language-ruby">gem 'perfm'</code></pre><p>We'll run <code>bin/rails generate perfm:install</code>. This will generate the migrationto create <code>perfm_gvl_metrics</code> which will be used to store request-level metrics.</p><p>Now we'll create an initializer <code>config/initializers/perfm.rb</code>.</p><pre><code class="language-ruby">Perfm.configure do |config|  config.enabled = true  config.monitor_gvl = true  config.storage = :localendPerfm.setup!</code></pre><p>After deploying the code to production, we need to collect around 20K requestsas that will give us a fair number of data points to analyze. The GVL monitoringcan be disabled after that by setting <code>config.monitor_gvl</code> to <code>false</code> so thatthe table doesn't keep growing.</p><p>After collecting the request data, now it's time to analyze it.</p><p>Run the following code in the Rails console.</p><pre><code class="language-ruby">irb(main):001* gvl_metrics_analyzer = Perfm::GvlMetricsAnalyzer.new(irb(main):002*   start_time: 2.days.ago, # configure thisirb(main):003*   end_time: Time.currentirb(main):004&gt; )irb(main):005&gt;irb(main):006&gt; results = gvl_metrics_analyzer.analyzeirb(main):007&gt; io_percentage = results[:summary][:total_io_percentage]=&gt; 45.09</code></pre><p>This will give us the percentage of time spent doing I/O. We ran it in our<a href="https://neeto.com/cal">NeetoCal</a> production application and we got a value of45%.</p><p>As we discussed in<a href="/blog/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency">part 3</a>,Amdahl's law gives us a theoretical maximum speedup based on the parallelizableportion of our workload. The formula is given below.<img src="/blog_images/2025/tuning-puma-max-threads-configuration-with-gvl-instrumentation/amdahls-law.png" alt="Amdahl's law formula"></p><p>Where:</p><ul><li><code>p</code> is the portion that can be parallelized (in our case, it's 0.45)</li><li><code>N</code> is the number of threads</li><li><code>(1 - p)</code> is the portion that must run sequentially (in our case, it's 0.55)</li></ul><p>Let's calculate the theoretical speedup for different numbers of threads with p= 0.45:</p><table><thead><tr><th>Thread Count (N)</th><th>Speedup</th><th>% Improvement from previous run</th></tr></thead><tbody><tr><td>1</td><td>1.00</td><td>-</td></tr><tr><td>2</td><td>1.29</td><td>29%</td></tr><tr><td>3</td><td>1.43</td><td>11%</td></tr><tr><td>4</td><td>1.52</td><td>6%</td></tr><tr><td>5</td><td>1.57</td><td>3%</td></tr><tr><td>6</td><td>1.60</td><td>2%</td></tr><tr><td>8</td><td>1.64</td><td>&lt;2%</td></tr><tr><td>16</td><td>1.69</td><td>&lt;1%</td></tr><tr><td></td><td>1.82</td><td>-</td></tr></tbody></table><p>We can see that after 4 threads, the percentage improvement drops below 5%. Thismeans that 4 is a reasonable value for <code>max_threads</code>. We can set the value of<code>RAILS_MAX_THREADS</code> to 4.</p><p><img src="/blog_images/2025/tuning-puma-max-threads-configuration-with-gvl-instrumentation/speedup-vs-thread-count.png" alt="Speedup V/S Number of threads"></p><p>Looking at the table, adding a 5th thread would only give us a 3% performanceimprovement, which may not justify the additional memory usage and potential GVLcontention.</p><p>We have also created a small application to help visualize and find the idealnumber of threads when the I/O percentage is provided as input.<a href="https://v0-single-page-application-lake.vercel.app/">Here</a> is the link to theapp.</p><h2>Validate thread count using stall time</h2><p>This value of <code>4</code> we got theoretically by using Amdahl's law. Now it's time toput this law to test. Let's see in the real world if the value of <code>4</code> is thecorrect value or not.</p><p>What we need to do is start with <code>RAILS_MAX_THREADS</code> env variable (Puma<code>max_threads</code>) set to <code>4</code> and then check if this value provides minimal GVLcontention. By GVL contention, we mean the amount of time a thread spendswaiting for the GVL i.e the stall time.</p><p>If the stall time is high, that means the set thread count is high. We don'twant our request threads to spend their time doing nothing causing latencyspikes.<code>75ms</code> is an acceptable value for stall time. The lesser the better ofcourse.</p><p>The average stall time can be found in the perfm analyzer results. As wementioned earlier, we had collected data for <a href="https://neeto.com/cal">NeetoCal</a>.Now let's find the average stall time.</p><pre><code class="language-ruby">irb(main):001* gvl_metrics_analyzer = Perfm::GvlMetricsAnalyzer.new(irb(main):002*   start_time: 2.days.ago,irb(main):003*   end_time: Time.current,irb(main):004*   puma_max_threads: 4irb(main):005&gt; )irb(main):006&gt; results = gvl_metrics_analyzer.analyzeirb(main):007&gt; avg_stall_ms = results[:summary][:average_stall_ms]=&gt; 110.24</code></pre><p>The stall time seems a bit high. Let us decrease the <code>RAILS_MAX_THREADS</code> valueby 1 and collect a few data points(i.e around 20K requests). Now the value of<code>RAILS_MAX_THREADS</code> will be <code>3</code>. This process has to be repeated until we findthe value for which the average stall time is less than <code>75ms</code>.</p><pre><code class="language-ruby">irb(main):001* gvl_metrics_analyzer = Perfm::GvlMetricsAnalyzer.new(irb(main):002*   start_time: 2.days.ago,irb(main):003*   end_time: Time.current,irb(main):004*   puma_max_threads: 3irb(main):005&gt; )irb(main):006&gt; results = gvl_metrics_analyzer.analyzeirb(main):007&gt; avg_stall_ms = results[:summary][:average_stall_ms]=&gt; 79.38</code></pre><p>Now the output is closer to <code>75 ms</code>.</p><p>Hence we can finalize on the value 3 as the value for <code>RAILS_MAX_THREADS</code>. If wedecrease the value again by one i.e set it to 2, the stall time will decreasebut we're limiting the concurrency of our application. It is a trade-off.</p><p>Remember that our goal is to maximize concurrency while minimizing GVLcontention. But if our app spends a lot of time doing I/O - for instance, if wehave a proxy application that makes a lot of external API calls directly fromthe controller, then we can switch the app server to<a href="https://github.com/socketry/falcon">Falcon</a>. Falcon is tailor-made for such usecases.</p><p>Broadly speaking, one should take care of the following items to ensure that thetime spent by the request doing I/O is minimal.</p><ul><li>Remove N+1 queries</li><li>Remove long-running queries</li><li>Move inline third party API calls to background job processor</li><li>Move heavy computational stuff to background job processor</li></ul><p>For a finely optimized Rails application, the <code>max_threads</code> value will bearound 3. That's why the default value of <code>max_threads</code> for Rails applicationsis <code>3</code> now. This has been decided after a lot of discussion<a href="https://github.com/rails/rails/issues/50450">here</a>. We recommend you read thewhole discussion. It is very interesting.</p><p><em>This was Part 4 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>. If any part of theblog is not clear to you then please write to us at<a href="https://www.linkedin.com/company/bigbinary">LinkedIn</a>,<a href="https://twitter.com/bigbinary">Twitter</a> or<a href="https://bigbinary.com/contact">BigBinary website</a>.</em></p>]]></content>
    </entry><entry>
       <title><![CDATA[Amdahl's Law - The Theoretical Relationship Between Speedup and Concurrency]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency"/>
      <updated>2025-04-29T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency</id>
      <content type="html"><![CDATA[<p><em>This is Part 3 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>.</em></p><p>We have only two parameters to work with if we want to fine-tune our Pumaconfiguration.</p><ol><li>The number of processes.</li><li>The number of threads each process can have.</li></ol><p>In<a href="https://bigbinary.com/blog/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance">part 1</a>of <a href="https://www.bigbinary.com/blog/scaling-rails-series">Scaling Rails series</a>,we saw what the number of processes should be. Now let's look at what the numberof threads in each process should be.</p><h2>Amdahl's law</h2><p>Each application has a few things which must be performed in &quot;serial order&quot; anda few things which can be &quot;parallelized&quot;. If we draw a diagram, then this iswhat it will look like.</p><p><img src="/blog_images/2025/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency/amdahls-gantt-chart1.png" alt="Amdahl's law Gantt chart"></p><p>Let's say that <code>T1'</code> and <code>T2'</code> are the enhanced times. These are the times theapplication would take after the enhancement has been applied. In this case theenhancement will come in the form of increasing the threads in a process.</p><p><code>T1'</code> will be same as <code>T1</code> since it's the serial part. <code>T2'</code> will be lower than<code>T2</code> since we will parallelize some of the code. After the parallelization isdone, the enhanced version would look something like this.</p><p><img src="/blog_images/2025/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency/amdahls-gantt-chart.png" alt="Amdahl's law Gantt chart"></p><p>It's clear that the serial part (T1) will limit how much speedup we can get nomatter how much we parallelize <code>T2</code>.</p><p>Computer scientist <a href="https://en.wikipedia.org/wiki/Gene_Amdahl">Gene Amdahl</a> cameup with <a href="https://en.wikipedia.org/wiki/Amdahl%27s_law">Amdahl's law</a> which givesthe mathematical value for the overall speedup that can be achieved.</p><p><img src="/blog_images/2025/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency/amdahls-law.png" alt="Amdahl's law picture"></p><p>I made a video explaining how this formula came about.</p><p>&lt;iframewidth=&quot;966&quot;height=&quot;604&quot;src=&quot;https://www.youtube.com/embed/2hYs2X6Fb1M?si=f-P_-pcwnotnyUKT&quot;title=&quot;Amdahl's Law&quot;frameborder=&quot;0&quot;allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot;allowfullscreen</p><blockquote><p>&lt;/iframe&gt;</p></blockquote><p><em>Amdahl's law states that the theoretical speedup gained from parallelization isdirectly determined by the fraction of sequential code in the program.</em></p><p>Now, let's see how we can use Amdahl's law to determine the ideal number ofthreads.</p><p>The parallelizable portion in this case is the portion of the application thatspends time doing I/O. The non-parallelizable portion is the time spent by theapplication executing Ruby code. Remember that because of GVL, within a process,only one thread has access to CPU at any point of time.</p><p>Now we need to know what percentage of time our app spends doing I/O. This willbe the value <code>p</code> as per the video.</p><p>Later in this series, we'll show you how to calculate what percentage of thetime the Rails application is spending doing I/O. For this blog let's assumethat our application spends 37% of the time doing I/O i.e the value of <code>p</code> is<strong>0.37</strong>.</p><p>Let's calculate how much speedup we will get if we use one thread(n is 1). Nowlet's change n to 2 and get the speedup value. Similarly, we bump up n all theway to 15 and we record the speedup.</p><p>Now let's draw a graph between the overall speedup and the number of threads.</p><p><img src="/blog_images/2025/amdahls-law-the-theoretical-relationship-between-speedup-and-concurrency/speedup-vs-thread-count.png" alt="Speedup V/S Number of threads"></p><p>From the graph, it can be seen that the speedup increases as the number ofthreads increases, but the rate of increase diminishes as more threads areadded. This is because the serial portion remains constant and is unaffected bythe increase in threads.</p><table><thead><tr><th>Threads(N)</th><th>Speedup(S)</th><th>% Improvement from previous run</th></tr></thead><tbody><tr><td>1</td><td>1.000</td><td>-</td></tr><tr><td>2</td><td>1.227</td><td>22.7%</td></tr><tr><td>3</td><td>1.366</td><td>11.3%</td></tr><tr><td>4</td><td>1.456</td><td>6.6%</td></tr><tr><td>5</td><td>1.518</td><td>4.2%</td></tr><tr><td>6</td><td>1.562</td><td>2.9%</td></tr><tr><td>7</td><td>1.594</td><td>2.0%</td></tr><tr><td>8</td><td>1.619</td><td>1.6%</td></tr></tbody></table><p>By examining the graph we can observe that the speedup gain from increasingthreads seem significant up to 4 threads, after which the incremental gain inspeedup starts to plateau.</p><p>Remember that these are theoretical maximums based on Amdahl's law. In practice,we need to use fewer threads as adding more threads can cause an increase inmemory usage and GVL contention, thereby causing latency spikes.</p><p>It's obvious that if we add more threads then more requests can be handled byPuma concurrently. What it means is that requests will be waiting for lessertime at the load balancer layer as there are more Puma threads waiting to pickup the request for processing. But in part 1, we saw that just because we havemore threads, it doesn't mean things will move faster. More threads might causeother threads to wait for the GVL.</p><p>There is no point in accepting requests if our web server can't respond to itpromptly. Whereas, if the <code>max_threads</code> value is set to a lower value, requestswill queue up at the Load Balancer layer which is better than overwhelming theapplication server.</p><p>If more and more requests are waiting at the load balancer level, then therequest queue time will shoot up. The right way to solve this problem is to addmore Puma processes. It is advised to increase the capacity of the Puma serverby adding more processes rather than increasing the number of threads.</p><p><a href="https://gist.github.com/neerajsingh0101/35e5307fb197b08ac6a62aa725cafec6">Here</a>is a middleware that can be used to track the request queue time. This code istaken from<a href="https://github.com/judoscale/judoscale-ruby/blob/15a4e9bd59734defb76656b59cba067b60aed473/judoscale-ruby/lib/judoscale/request_metrics.rb">judoscale</a>.</p><p>Note that <strong>Request Queue Time</strong> is the time spent waiting before the request ispicked up for processing.</p><p>This middleware will only work if the load balancer is adding the<code>HTTP_REQUEST_START</code> header. Heroku automatically adds this header.</p><p>Now we need to use this middleware and for that open <code>config/application.rb</code>file and we need to add the following line.</p><pre><code class="language-ruby">config.middleware.use RequestQueueTimeMiddleware</code></pre><p><em>This was Part 3 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>. If any part of theblog is not clear to you then please write to us at<a href="https://www.linkedin.com/company/bigbinary">LinkedIn</a>,<a href="https://twitter.com/bigbinary">Twitter</a> or<a href="https://bigbinary.com/contact">BigBinary website</a>.</em></p>]]></content>
    </entry><entry>
       <title><![CDATA[GVL in Ruby and the impact of GVL in scaling Rails applications]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/gvl-in-ruby-and-its-impact-in-scaling-rails-applications"/>
      <updated>2025-04-24T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/gvl-in-ruby-and-its-impact-in-scaling-rails-applications</id>
      <content type="html"><![CDATA[<p><em>This is Part 2 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>.</em></p><p>Let's start from the basics. Let's see how a standard web application mostlybehaves.</p><h2>Web applications and CPU usage</h2><p>Code in a web application typically works like this.</p><ul><li>Do some data manipulation.</li><li>Make a few database calls.</li><li>Do more calculations.</li><li>Make some network calls.</li><li>Do more calculations.</li></ul><p>Visually, it'll look something like this.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/work-done-in-processing-web-request.png" alt="Three threads 1 process &amp; 2 cores"></p><p>CPU work includes operations like view rendering, string manipulation, any kindof business logic processing etc. In short, anything that involves Ruby codeexecution can be considered CPU work. For the rest of the work, like databasecalls, network call etc. CPU is idle. Another way of looking at when the CPU isworking and when it's idle is this picture.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/cpu-working-idle.png" alt="CPU sometimes working &amp; sometimes idle"></p><p>When a program is using CPU, then that portion of the code is called <strong>CPUbound</strong> and when program is not using CPU, then that portion of the code iscalled <strong>IO bound</strong>.</p><h3>CPU bound or IO bound</h3><p>Let us understand what <strong>CPU bound</strong> truly means. Consider the following pieceof code.</p><pre><code class="language-ruby">10.times do  Net::HTTP.get(URI.parse(&quot;https://bigbinary.com&quot;))end</code></pre><p>In the above code, we are hitting the BigBinary website 10 times sequentially.Running the above code takes time because making a network connection is atime-consuming process.</p><p>Let's assume the code above takes 10 seconds to finish. We want the code to runfaster. So we bought a better CPU for the server. Do you think now the code willrun faster?</p><p>It will not. That's because the above code is <strong>not</strong> CPU bound. CPU is not thelimiting factor in this case. This code is I/O bound.</p><p>A program is <strong>CPU bound</strong> if the program will run faster if the CPU werefaster.</p><p>A program is <strong>I/O bound</strong> if the program will run faster if the I/O operationswere faster.</p><p>Some of the examples of I/O bound operations are:</p><ul><li><strong>making database calls</strong>: reading data from tables, creating new tables etc.</li><li><strong>making network calls</strong>: reading data from a website, sending emails etc.</li><li><strong>dealing with file systems</strong>: reading files from the file system.</li></ul><p>Previously, we saw that our CPU was idle sometimes. Now we know that thetechnical term for that idleness is <strong>IO bound</strong> let's update the picture.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/cpu-bound-io-bound.png" alt="CPU bound and IO bound"></p><p>When a program is I/O bound, the CPU is not doing anything. We don't wantprecious CPU cycles to be wasted. So what can we do so that the CPU is fullyutilized?</p><p>So far we have been dealing with only one thread. We can increase the number ofthreads in the process. In this way, whenever the CPU is done executing CPUbound code of one thread and that thread is doing an I/O bound operation, thenthe CPU can switch and handle the work from another thread. This will ensurethat the CPU is efficiently utilized. We will look at how the switching betweenthreads works a bit later in the article.</p><h2>Concurrency vs Parallelism</h2><p>Concurrency and parallelism sound similar, and in your daily life, you cansubstitute one for another, and you will be fine. However, from the computerengineering point of view, there is a difference between work happeningconcurrently and work happening in parallel.</p><p>Imagine a person who has to respond to 100 emails and 100 Twitter messages. Theperson can reply to an email and then reply to a Twitter message, then do thesame all over again: reply to an email and reply to a Twitter message.</p><p>The boss will see the count of pending emails and Twitter messages go down from100 to 99 to 98. The boss might think that the work is happening in &quot;parallel.&quot;But that's not true.</p><p>Technically, the work is happeningconcurrently. For a system to be parallel, itshould have two or more actions executed simultaneously. In this case, at anygiven moment, the person was either responding to email or responding toTwitter.</p><p>Another way to look at it is that <strong>Concurrency is about dealing</strong> with lots ofthings at the same time. <strong>Parallelism is about doing</strong> lots of things at thesame time.</p><p>If you find it hard to remember which one is which then remember that<strong>concurrency</strong> starts with the word <strong>con</strong>. Concurrency is the <em>conman</em>. It'spretending to be doing things &quot;in parallel,&quot; but it's only doing thingsconcurrently.</p><h2>Understanding GVL in Ruby</h2><p>GVL (Global VM Lock) in Ruby is a mechanism that prevents multiple threads fromexecuting Ruby code simultaneously. The GVL acts like a traffic light in aone-lane bridge. Even if multiple cars (threads) want to cross the bridge at thesame time, the traffic light (GVL) allows only one car to pass at a time. Onlywhen one car has made it safely to the other end, the second car is allowed bythe traffic light(GVL) to start.</p><p>Ruby's memory management(like garbage collection) and some other parts of Rubyare not thread-safe. Hence, GVL ensures that only one thread runs Ruby code at atime to avoid any data corruption.</p><p>When a thread &quot;holds the GVL&quot;, it has exclusive access to modify the VMstructures.</p><p>It's important to note that GVL is there to protect how Ruby works and managesRuby's internal VM state. GVL is not there to protect our application code. It'sworth repeating. The presence of GVL doesn't mean that we can write our code ina thread unsafe manner and expect Ruby to take care of all threading issues inour code.</p><p>Ruby offers tools like <a href="https://ruby-doc.com/3.3.6/Thread/Mutex.html">Mutex</a> and<a href="https://github.com/ruby-concurrency/concurrent-ruby">concurrent-ruby</a> gem tomanage concurrent code. For example, the followingcode(<a href="https://www.youtube.com/watch?v=rI4XlFvMNEw&amp;t=575s">source</a>) is not threadsafe and the GVL will not protect our code from race conditions.</p><pre><code class="language-ruby">from = 100_000_000to = 050.times.map do  Thread.new do    while from &gt; 0      from -= 1      to += 1    end  endend.map(&amp;:join)puts &quot;to = #{to}&quot;</code></pre><p>When we run this code, we might expect the result to always equal 100,000,000since we're just moving numbers from <code>from</code> to <code>to</code>. However, if we run itmultiple times, we'll get different results.</p><p>This happens because multiple threads are trying to modify the same variables(from and to) simultaneously without any synchronization. This is called racecondition and it happens because the operation <code>to += 1</code> and <code>from -= 1</code> arenon-atomic at the CPU-level. In simpler terms operation <code>to += 1</code> can be writtenas three CPU-level operations.</p><ol><li>Read current value of <code>to</code>.</li><li>Add 1 to it.</li><li>Store the result back to <code>to</code>.</li></ol><p>To fix this race condition the above code can be re-written using a<a href="https://docs.ruby-lang.org/en/master/Thread/Mutex.html">Mutex</a>.</p><pre><code class="language-rb">from = 100_000_000to = 0lock = Mutex.new50.times.map do  Thread.new do    while from &gt; 0      lock.synchronize do        if from &gt; 0          from -= 1          to += 1        end      end    end  endend.map(&amp;:join)puts &quot;to = #{to}&quot;</code></pre><p>It's worth nothing that Ruby implementations like JRuby and TruffleRuby don'thave a GVL.</p><h2>GVL dictates how many processes we will need</h2><p>Let's say that we deploy the production app to AWS's EC2's <code>t2.medium</code> machine.This machine has 2 vCPU as we can see from this chart.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/t2-medium.png" alt="T2 medium"></p><p>Without going into CPU vs vCPU discussion, let's keep things simple and assumethat the AWS machine has two cores. So we have deployed our code on a machinewith two cores but we have only one process running in production. No worries.We have three threads. So three threads can share two cores. You would thinkthat something like this should be possible.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/puma-one-process-2-cores.png" alt="Three threads 1 process &amp; 2 cores"></p><p>But it's not possible. Ruby doesn't allow it.</p><p>Currently, it's not possible because Thread 1 and Thread 2 belong to the sameprocess. This is because of the <strong>Global VM Lock (GVL)</strong>.</p><p>The GVL ensures that only one thread can execute CPU bound code at a time withina single Ruby process. The important thing to note here is that this lock is<strong>only for the CPU bound code</strong> and <strong>only for the same process</strong>.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/gvl-lock.png" alt="Single Process Multi Core"></p><p>In the above case, all three threads can do DB operations in parallel. But twothreads of the same process can't be doing CPU operations in parallel.</p><p>We can see that &quot;Thread 1&quot; is using Core 1. Core 2 is available but &quot;Thread 2&quot;can't use Core 2. GVL won't allow it.</p><p>Again, let's revisit what GVL does. For the CPU bound code GVL will ensure thatonly one thread from a process can access CPU.</p><p>So now the question is how do we utilize Core 2. Well, the GVL is applied at aprocess level. Threads of the same process are not allowed to do CPU operationsin parallel. Hence, the solution is to have more processes.</p><p>To have two Puma processes we need to set the value of env variable<code>WEB_CONCURRENCY</code> to 2 and reboot Puma.</p><pre><code class="language-ruby">WEB_CONCURRENCY=2 bundle exec rails s</code></pre><p>Now we have two processes. Now both Core 1 and Core 2 are being utilized.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/gvl-two-process.png" alt="Multi Process Multi Core"></p><p>What if the machine has 5 cores. Do we need 5 processes?</p><p>Yes. In that case, we will need to have 5 processes to utilize all the cores.</p><p>Therefore for achieving maximum utilization, the rule of thumb is that thenumber of processes i.e <code>WEB_CONCURRENCY</code> should be set to the number of coresavailable in the machine.</p><h2>Thread switching</h2><p>Now let's see how switching between threads happens in a multi-threadedenvironment. Note that the number of threads is 2 in this case.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/thread1-thread2.png" alt="CPU bound and IO bound"></p><p>As we can see, the CPU switches between Thread 1 and Thread 2 whenever it'sidle. This is great. We don't waste CPU cycles now, as we saw in thesingle-threaded case. But the switching logic is much more nuanced than what isshown in the picture.</p><p>Ruby manages multiple threads at two levels: the operating system level and theRuby level. When we create threads in Ruby, they are &quot;native threads&quot; - meaningthey are real threads that the operating system (OS) can see and manage.</p><p>All operating systems have a component called the scheduler. In Linux, it'scalled the<a href="https://en.wikipedia.org/wiki/Completely_Fair_Scheduler">Completely Fair Scheduler</a>or CFS. This scheduler decides which thread gets to use the CPU and for howlong. However, Ruby adds its own layer of control through the Global VM Lock(GVL).</p><p>In Ruby a thread can execute CPU bound code only if it holds the GVL. The RubyVM makes sure that a thread can hold the GVL for up to 100 milliseconds. Afterthat the thread will be forced to release GVL to another thread if there isanother thread waiting to execute CPU bound code. This ensures that the waitingRuby threads are not<a href="https://en.wikipedia.org/wiki/Starvation_(computer_science)">starved</a>.</p><p>When a thread is executing CPU-bound code, it will continue until either:</p><ol><li>It completes its CPU-bound work.</li><li>It hits an I/O operation (which automatically releases the GVL).</li><li>It reaches the limit of 100ms.</li></ol><p>When a thread starts running, the Ruby VM uses a background timer thread at theVM level that checks every 10ms how long the current Ruby thread has beenrunning. If the thread has been running longer than the thread quantum (100ms bydefault), the Ruby VM takes back the GVL from the active thread and gives it tothe next thread waiting in the queue. When a thread gives up the GVL (eithervoluntarily or is forced to give up), the thread goes to the back of the queue.</p><p>The default thread quantum is 100ms and starting from Ruby 3.3, it can beconfigured using the <code>RUBY_THREAD_TIMESLICE</code> environment variable.<a href="https://bugs.ruby-lang.org/issues/20861">Here</a> is the link to the discussion.This environment variable allows fine-tuning of thread scheduling behavior - asmaller quantum means more frequent thread switches, while a larger quantummeans fewer switches.</p><p>Let's see what happens when we have two threads.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/multi-threaded.png" alt="CPU bound and IO bound"></p><ol><li>T1 completes quantum limit of 100ms and gives up the GVL to T2.</li><li>T2 completes 50ms of CPU work and voluntarily gives up the GVL to do I/O.</li><li>T1 completes 75 ms of CPU work and voluntarily gives the GVL to do I/O.</li><li>Both T1 and T2 are doing I/O and doesn't want the GVL.</li></ol><p>It means that Thread 2 would be a lot faster if it had more access to CPU. Tomake CPU instantly available, we can have lesser number of threads CPU has tohandle. But we need to play a balancing game. If the CPU is idle then we arepaying for the processing cost for no reason. If the CPU is extremely busy thenthat means requests will take longer to process.</p><h2>Thread switching can lead to misleading data</h2><p>Let's take a look at a simple code given below. This code is taken from<a href="https://byroot.github.io/ruby/performance/2025/01/23/the-mythical-io-bound-rails-app.html">a blog</a>by <a href="https://x.com/_byroot">Jean Boussier</a>.</p><pre><code>start = Time.nowdatabase_connection.execute(&quot;SELECT ...&quot;)query_duration = (Time.now - start) * 1000.0puts &quot;Query took: #{query_duration.round(2)}ms&quot;</code></pre><p>The code looks simple. If the result is say <code>Query took: 80ms</code> then you wouldthink that the query actually took <code>80ms</code>. But now we know two things</p><ul><li>Executing database query is an IO operation (IO bound)</li><li>Once the IO bound operation is done then the thread might not immediately gethold of the GVL to execute CPU bound code.</li></ul><p>Think about it. What if the query took only <code>10ms</code> and the rest of the <code>70ms</code>The thread was waiting for the CPU because of the GVL. The only way to knowwhich portion took how much time is by instrumenting the GVL.</p><h2>Visualizing the effect of the GVL</h2><p>To better understand the effect of multiple threads when it comes to Ruby'sperformance, let's do a quick test. We'll start with a <strong>cpu_intensive</strong> methodthat performs pure arithmetic operations in nested loops, creating a workloadthat is heavily CPU dependent.</p><p><a href="https://gist.github.com/neerajsingh0101/de84bf200fae4e2003205ed81fcd9d7f">Here</a>is the code.</p><p>Running this script produced the following output:</p><pre><code class="language-ruby">Running demonstrations with GVL tracing...Starting demo with 1 threads doing CPU-bound workTime elapsed: 7.4921 secondsStarting demo with 3 threads doing CPU-bound workTime elapsed: 7.8146 seconds</code></pre><p>From the output, we can see that for CPU-bound work, a single thread performedbetter. Why? Let's visualize the result with the help of the traces generated inthe above script using the <a href="https://github.com/ivoanjo/gvl-tracing">gvl-tracing</a>gem. The trace files can be visualized using<a href="https://ui.perfetto.dev/">Perfetto</a>, which provides a timeline view showing howthreads interact with the GVL.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/cpu-single-multi.png" alt="Single and multi threads CPU bound"></p><p>We can see above that in the case of CPU-bound work if we have a single threadthen it's not waiting for GVL. However, if we have three threads then eachthread is waiting for GVL multiple times.</p><h3>Understanding the advantage of multiple threads in mixed workloads</h3><p>Now let's look at mixed workloads in single-threaded and multi-threadedenvironment. We'll use a separate script with a <strong>mixed_workload</strong> method thatcombines CPU-bound work with I/O operations. We use <code>IO.select</code> with blockingbehavior to simulate I/O operations. This creates actual I/O blocking thatreleases the GVL and shows as &quot;waiting&quot; in the GVL trace, accuratelyrepresenting real-world I/O operations like database queries.</p><p><a href="https://gist.github.com/neerajsingh0101/af1eb90a79c7da429d4287528d7bb788">Here</a>is the code for the mixed workload test.</p><p>Running this script with 1 thread and 3 threads produced the following output:</p><pre><code class="language-ruby">Running demonstrations with GVL tracing...Starting demo with 1 thread doing Mixed I/O and CPU workTime elapsed: 9.32 secondsStarting demo with 3 threads doing Mixed I/O and CPU workTime elapsed: 6.1344 seconds</code></pre><p>The key advantage of multiple threads in mixed workloads lies in how the GVL ismanaged during I/O operations. When a thread encounters an I/O operation (like adatabase query, network call, or file read), it voluntarily releases the GVL.This is fundamentally different from CPU-bound work, where threads compete forthe GVL and one thread must wait for another to finish or reach the 100msquantum limit.</p><p>During I/O operations, the thread is essentially blocked waiting for an externalresource (database, network, disk). While waiting, the thread doesn't need theGVL because it's not executing Ruby code. This creates an opportunity for otherthreads to acquire the GVL and do useful CPU work. The result is that CPU cyclesthat would otherwise be wasted during I/O waits are now being utilizedproductively by other threads.</p><p>Let's visualize this with the single-threaded case first:</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/mixed-single.png" alt="Single thread mixed workload"></p><p>In the single-threaded case, the threads wait for I/O operations to complete.During these I/O waits, the CPU sits idle. The thread performs some CPU work,then waits for I/O, then does more CPU work, then waits for I/O again. Duringall the I/O wait periods, no productive work is happening. The CPU is availablebut there's no other thread to utilize it.</p><p>Now let's look at the multi-threaded case with three threads:</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/mixed-multi.png" alt="Multi threaded mixed workload"></p><p>When there are three threads, the situation changes a bit. Threads nowoccasionally spend time waiting for the GVL, but the overall throughput issignificantly better.</p><p>When Thread 1 releases the GVL to perform I/O, Thread 2 can immediately acquireit and start executing CPU-bound work. While Thread 2 is working, Thread 1 mightstill be waiting for its I/O operation to complete. Then when Thread 2 releasesthe GVL for its own I/O operation, Thread 3 can acquire it. This creates apipeline effect where threads are constantly handing off the GVL to each otherensuring that the CPU is almost always doing useful work.</p><p>The small amount of GVL contention we see in the multi-threaded case (threadswaiting for GVL) is more than compensated for by the elimination of idle CPUtime. Instead of the CPU sitting idle during I/O operations, other threads keepit busy.</p><p>This is why Rails applications with typical workloads (lots of database queries,API calls, and other I/O operations) benefit significantly from having multiplethreads.</p><h2>Why can't we increase the thread count to a really high value?</h2><p>In the previous section, we saw that increasing the number of threads can helpin utilizing the CPU better. So why can't we increase the number of threads to areally high value? Let us visualize it.</p><p>In the hope of increasing performance, let us bump up the number of threads inthe previous code snippet to <code>20</code> and see the gvl-tracing result.</p><p><img src="/blog_images/2025/gvl-in-ruby-and-its-impact-in-scaling-rails-applications/20-threads.png" alt="20 threads"></p><p>As we can see in the above picture, the amount of GVL contention is massivehere. Threads are waiting to get a hold of the GVL. Same will happen inside aPuma process if we increase the number of threads to a very high value. As weknow, each request is handled by a thread. GVL contention therefore, means thatthe requests keep waiting, thereby increasing latency.</p><h2>What's next</h2><p>In the coming blogs, we'll see how we can figure out the ideal value for<code>max_threads</code>, both theoretically and empirically, based on our application'sworkload.</p><p><em>This was Part 2 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>. If any part of theblog is not clear to you then please write to us at<a href="https://www.linkedin.com/company/bigbinary">LinkedIn</a>,<a href="https://twitter.com/bigbinary">Twitter</a> or<a href="https://bigbinary.com/contact">BigBinary website</a>.</em></p>]]></content>
    </entry><entry>
       <title><![CDATA[Understanding how Puma handles requests]]></title>
       <author><name>Vishnu M</name></author>
      <link href="https://www.bigbinary.com/blog/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance"/>
      <updated>2025-04-23T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance</id>
      <content type="html"><![CDATA[<p><em>This is Part 1 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>.</em></p><p>If we do<code>rails new</code>to create a new Railsapplication,<a href="https://puma.io">Puma</a>will be the default web server. Let's startby explaining how Puma handles requests.</p><h2>How does Puma handle requests?</h2><p>Puma listens to incoming requests on a TCP socket. When a request comes in, thenthat request is queued up in the socket. The request is then picked up by a Pumaprocess. In Puma, a process is a separate OS process that runs an instance ofthe Rails application.</p><p><em>Note that Puma official documentation calls a Puma process a Puma worker. Sincethe term &quot;worker&quot; might confuse people with background workers like Sidekiq orSolidQueue, in this article, we have used the word Puma process at a few placesto remove any ambiguity</em>.</p><p>Now, let's look at how a request is processed by Puma step-by-step.</p><p><img src="/blog_images/2025/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance/puma-internals.png" alt="Puma internals"></p><ol><li><p>All the incoming connections are added to the socket backlog, which is an OSlevel queue that holds pending connections.</p></li><li><p>A separate thread (created by the<a href="https://msp-greg.github.io/puma/Puma/Reactor.html">Reactor</a> class) reads theconnection from the socket backlog. As the name suggests, this Reactor classimplements the<a href="https://en.wikipedia.org/wiki/Reactor_pattern">reactor pattern</a>. The reactorcan manage multiple connections at a time thanks to non-blocking I/O and anevent-driven architecture.</p></li><li><p>Once the incoming request is fully buffered in memory, the request is passedto the thread pool where the request resides in the <code>@todo</code> array.</p></li><li><p>A thread in the thread pool pulls a request from the <code>@todo</code> array andprocesses it. The thread calls the Rack application, which, in our case is aRails application, and generates a response.</p></li><li><p>The response is then sent back to the client via the same connection. Oncethis is complete, the thread is released back to the thread pool to handlethe next item from the <code>@todo</code> array.</p></li></ol><h2>Modes in Puma</h2><ol><li><p><strong>Single Mode</strong>: In single mode, only a single Puma process boots and doesnot have any additional child processes. It is suitable only for applicationswith low traffic.</p><p><img src="/blog_images/2025/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance/single-mode.png" alt="Single mode"></p></li><li><p><strong>Cluster Mode</strong>: In cluster mode, Puma boots up a master process, whichprepares the application and then invokes the<a href="https://en.wikipedia.org/wiki/Fork_(system_call)">fork()</a> system call tocreate one or more child processes. These processes are the ones that areresponsible for handling requests. The master process monitors and managesthese child processes.<img src="/blog_images/2025/understanding-puma-concurrency-and-the-effect-of-the-gvl-on-performance/cluster-mode.png" alt="Cluster mode"></p></li></ol><h2>Default Puma configuration in a new Rails application</h2><p>When we create a new Rails 8 or higher application, the default Puma<code>config/puma.rb</code> will have the following code.</p><p><em>Please note that we are mentioning Rails 8 here because the Puma configurationis different in prior versions of Rails.</em></p><pre><code class="language-ruby">threads_count = ENV.fetch(&quot;RAILS_MAX_THREADS&quot;, 3)threads threads_count, threads_countrails_env = ENV.fetch(&quot;RAILS_ENV&quot;, &quot;development&quot;)environment rails_envcase rails_envwhen &quot;production&quot;  workers_count = Integer(ENV.fetch(&quot;WEB_CONCURRENCY&quot;, 1))  workers workers_count if workers_count &gt; 1  preload_app!when &quot;development&quot;  worker_timeout 3600end</code></pre><p>For a brand new Rails application, the env variables <code>RAILS_MAX_THREADS</code> and<code>WEB_CONCURRENCY</code> won't be set. This means <code>threads_count</code> will be set to 3 and<code>workers_count</code> will be 1.</p><p>Now let's look at the second line from the above mentioned code.</p><pre><code class="language-ruby">threads threads_count, threads_count</code></pre><p>In the above code, <code>threads</code> is a method to which we are passing two arguments.The default value of <code>threads_count</code> is 3. So effectively, we are calling method<code>threads</code> like this.</p><pre><code>threads(3, 3)</code></pre><p>The threads method in Puma takes two arguments: <code>min</code> and <code>max</code>. These argumentsspecify the minimum and maximum number of threads that each Puma process willuse to handle requests. In this case Puma will initialize 3 threads in thethread pool.</p><p>Now let's look at the following line from the above mentioned code.</p><pre><code class="language-ruby">workers workers_count if workers_count &gt; 1</code></pre><p>The value of <code>workers_count</code> in this case is <code>1</code>, so Puma will run in <strong>single</strong>mode. As mentioned earlier in Puma a worker is basically a process. It's notbackground job worker.</p><p>What we have seen is that if we don't specify <code>RAILS_MAX_THREADS</code> or<code>WEB_CONCURRENCY</code> then, by default, Puma will boot a single process and thatprocess will have three threads. In other words Rails will boot with the abilityto handle 3 requests concurrently.</p><p>This is the default value for Puma for Rails booting in development or inproduction mode - a single process with three threads.</p><h2>Configuring Puma's concurrency and parallelism</h2><p>When it comes to concurrency and parallelism in Puma, there are two primaryparameters we can configure: the number of threads each process will have andthe number of processes we need.</p><p>To figure out the right value for each of these parameters, we need to know howRuby works. Specifically, we need to know how GVL in Ruby works and how itimpacts the performance of Rails applications.</p><p>We also need to know what kind of Rails application it is. Is it a CPU intensiveapplication, IO intensive or somewhere in between.</p><p>Don't worry in the next blog, we will start from the basics and will discuss allthis and much more.</p><p><em>This was Part 1 of our blog series on<a href="/blog/scaling-rails-series">scaling Rails applications</a>. If any part of theblog is not clear to you then please write to us at<a href="https://www.linkedin.com/company/bigbinary">LinkedIn</a>,<a href="https://twitter.com/bigbinary">Twitter</a> or<a href="https://bigbinary.com/contact">BigBinary website</a>.</em></p>]]></content>
    </entry><entry>
       <title><![CDATA[Upgrade Ruby using dual boot]]></title>
       <author><name>Vijay Vinod</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-upgrade-using-dual-boot"/>
      <updated>2024-09-04T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-upgrade-using-dual-boot</id>
      <content type="html"><![CDATA[<p>Recently, we upgraded all <a href="https://www.neeto.com/">neeto</a> product's Ruby versionfrom 3.2.2 to 3.3.0 using &quot;dual-booting&quot;.</p><p>Dual-booting is a process that allows you to run your application with differentsets of dependencies, making it easy to switch between them. This approachenables you to quickly test your code with both the current and the newerversion of what you are upgrading, ensuring that everything works smoothlybefore fully committing to the upgrade.</p><h4>How to dual-boot Ruby?</h4><p>The dual-boot technique involves maintaining two separate <code>Gemfile.lock</code> fileswithin your Rails project: one for the current version of Ruby and another forthe next version you're upgrading to.</p><p>To get started, first create a symbolic link for <code>Gemfile.next</code> with thefollowing command:</p><pre><code class="language-bash">ln -s Gemfile Gemfile.next</code></pre><p>This command creates <code>Gemfile.next</code> file, which you'll use for the new Rubyversion. This file isn't a separate copy but rather a pointer to your original<code>Gemfile</code> in the Rails project directory.</p><p>Next, add the following snippet at the top of your <code>Gemfile</code>:</p><pre><code class="language-ruby">def next?  File.basename(__FILE__) == &quot;Gemfile.next&quot;end</code></pre><p>This code snippet helps determine which <code>Gemfile</code> is in use, whether it's thestandard one or the <code>Gemfile.next</code> for the new Ruby version.</p><p>Now, let's utilize the <code>next?</code> method to dynamically set the Ruby version in the<code>Gemfile</code> using a conditional operator:</p><pre><code class="language-ruby">ruby_version = next? ? &quot;3.3.0&quot; : &quot;3.2.2&quot;ruby ruby_version</code></pre><p>This code snippet helps determine the Ruby version based on the <code>next?</code> method.If <code>next?</code> returns true, meaning you're operating within <code>Gemfile.next</code>, it setsthe Ruby version to &quot;3.3.0&quot;. Otherwise, if the standard <code>Gemfile</code> is beingprocessed, it defaults to &quot;3.2.2&quot;.</p><h4>How to install dependencies?</h4><p>With the dual-boot setup in place, you can effectively manage dependencies forboth your current and next versions of the application.</p><p>Installing current dependencies: To install dependencies for your currentversion, simply run:</p><pre><code class="language-bash">bundle install</code></pre><p>This command uses the standard <code>Gemfile</code> to resolve and install dependencies foryour current application.</p><p>Installing next dependencies: To install dependencies for the next version ofyour application, use the following command:</p><pre><code class="language-bash">BUNDLE_GEMFILE=Gemfile.next bundle install</code></pre><p>This command specifies <code>Gemfile.next</code> as the <code>Gemfile</code>, allowing you to installdependencies specifically for the next version.</p><p>Managing commands for the next version: To perform various operations for thenext version, you can use the syntax <code>BUNDLE_GEMFILE=Gemfile.next &lt;command&gt;</code>.For example, to start the Rails server with the next version's dependencies, youwould use:</p><pre><code class="language-bash">BUNDLE_GEMFILE=Gemfile.next rails s</code></pre><p>This approach ensures that <code>Gemfile.next</code> is explicitly used for the specifiedcommand, allowing you to work with the next version of your application whilekeeping dependencies and configurations correctly managed.</p><h4>Considerations for dual-boot setup</h4><p>When implementing a dual-boot setup, it's crucial to consider where both Rubyand gem versions are defined. While gem versions are usually specified only inthe <code>Gemfile</code>, the Ruby version can be defined in several locations. The mostcommon are:</p><ul><li><code>.ruby-version</code> File: Used by version managers like rbenv to specify the Rubyversion.</li><li><code>Gemfile</code>: This is where Bundler, RVM, Heroku, and similar tools reference theRuby version to manage the Ruby environment.</li><li><code>Gemfile.lock</code>: Although the Ruby version in this file is mostly informative,it's worth noting.</li><li><code>Dockerfile</code>: Defines the Ruby version for Docker containers if you're usingDocker.</li><li>CI setup steps and configurations.</li><li>Other less common locations within applications.</li></ul><p>We need to make sure that dual-boot setup is compatible with all of them toensure a smooth transition and consistency across different environments.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Using enable-load-relative flag in building Ruby binaries]]></title>
       <author><name>Vishal Yadav</name></author>
      <link href="https://www.bigbinary.com/blog/use-of-enable-load-relative-flag-in-building-ruby-binaries"/>
      <updated>2023-06-20T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/use-of-enable-load-relative-flag-in-building-ruby-binaries</id>
      <content type="html"><![CDATA[<p>I'm working on building <a href="https://neeto.com/neetoci">NeetoCI</a>, which is a CI/CDsolution. While building precompiled Ruby binaries, we encountered somechallenges. This blog post explores the problems we faced and how we solvedthem.</p><h2>Pre-compiled Ruby binaries</h2><p>Pre-compiled Ruby binaries are distribution-ready versions of Ruby that includeoptimized features for specific systems. These Ruby binaries save time byeliminating the need to compile Ruby source code manually. Pre-compiled Rubybinaries help users quickly deploy applications that use different versions ofRuby on multiple machines.</p><p><a href="https://rvm.io/">RVM</a> (Ruby Version Manager) is widely used for managing Rubyinstallations on Unix-like systems. RVM provides customized pre-compiled Rubybinaries tailored for various CPU architectures. These binaries offer additionalfeatures like readline support and SSL/TLS support. You can find them at<a href="https://rvm.io/binaries/">RVM binaries</a>.</p><h2>The Need for pre-compiled Ruby Binaries</h2><p><a href="https://www.neeto.com/neetoci">NeetoCI</a> must execute user code in acontainerized environment. A Ruby environment is essential for running Ruby onRails applications. However, relying on the system's Ruby version is impracticalsince it may differ from the user's required version. Although rbenv or rvm canbe used to install the necessary Ruby version, this approach could be slow. Tosave time, we chose to leverage pre-compiled Ruby binaries.</p><p>As a CI/CD system, NeetoCI must ensure that all versions of Ruby that anapplication requires are always available. Hence, we decided to build ourbinaries instead of relying on binaries provided by RVM. Also, this would allowus to do more system-specific optimizations to the Ruby binary at build time.</p><h2>Building pre-compiled Ruby binaries</h2><p>We built a Ruby binary following the<a href="https://github.com/ruby/ruby/blob/master/doc/contributing/building_ruby.md">official documentation</a>. We were able to execute it on our local development machines. But the samebinary ran into an error in our CI/CD environment.</p><p><img src="/blog_images/2023/use-of-enable-load-relative-flag-in-building-ruby-binaries/failing-binary-error-image.png" alt="Bad Interpreter"></p><pre><code class="language-bash">$ bundle config path vendor/bundle./ruby: bad interpreter: No such file or directory</code></pre><p>To debug the issue, we initially focused on <code>$PATH</code>. However, even afterresolving the <code>$PATH</code> issues, the problem persisted. We conducted a thoroughinvestigation to identify the root cause. Unfortunately, not much was written onthe Internet about this error. There was no mention of it in the official<a href="https://github.com/ruby/ruby/blob/master/doc/contributing/building_ruby.md">Ruby documentation</a>.</p><p>As the next step, we decided to download the binary for version 3.2.2 from<a href="https://rvm.io/binaries/">RVM</a>. While examining the configuration file, wenoticed that the following arguments were used with the configure command duringthe Ruby binary build process:</p><pre><code class="language-bash">configure_args=&quot;'--prefix=/usr/share/rvm/rubies/ruby-3.2.2' '--enable-load-relative' '--sysconfdir=/etc' '--disable-install-doc' '--enable-shared'&quot;</code></pre><p>Here are the explanations of the configuration arguments:</p><ol><li><p><code>--prefix=/usr/share/rvm/rubies/ruby-3.2.2</code>: This specifies the directorywhere the Ruby binaries, libraries and other files will be kept after theinstallation is done.</p></li><li><p><code>--enable-load-relative</code>: This specifies that Ruby can load relative pathsfor dynamically linked libraries. It allows the usage of relative pathsinstead of absolute paths when loading shared libraries. This feature can bebeneficial in specific deployment scenarios.</p></li><li><p><code>--sysconfdir=/etc</code>: This argument sets the directory where Ruby's systemconfiguration files will be installed. In this case, it specifies the <code>/etc</code>directory as the location for these files.</p></li><li><p><code>--disable-install-doc</code>: When this option is enabled, the installation ofdocumentation files during the build process is disabled. This can help speedup the build process and save disk space, especially if you do not requirethe documentation files.</p></li><li><p><code>--enable-shared</code>: Enabling this option allows the building of sharedlibraries for Ruby. Shared libraries enable Ruby to dynamically link and loadspecific functionality at runtime, leading to potential performanceimprovements and reduced memory usage.</p></li></ol><p>In simpler terms, when the <code>--enable-load-relative</code> flag is enabled, thecompiled Ruby binary can search for shared libraries in its own directory usingthe <code>$ORIGIN</code> variable.</p><p>When I built the binary on the Docker registry, then the passed <code>--prefix</code> wassomething like <code>/usr/share/neetoci</code>. When the binary is built, then binary had<code>/usr/share/neetoci</code> is hard-coded at various places. When we download thisbinary and use in CI then in the CI environment, Ruby is looking for<code>/user/share/neetoci</code> to load dependencies.</p><p>By enabling <code>--enable-load-relative</code> flag while building the binary Ruby willnot use the hard coded value. Rather Ruby will use <code>$ORIGIN</code> variable and willsearch for the dependencies in the directory mentioned in <code>$ORIGIN</code>.</p><p>This is particularly helpful when the Ruby binary is relocated to a differentdirectory or system. By using relative paths with <code>$ORIGIN</code>, the binary can findits shared libraries regardless of its new location. Without this flag, sharedlibraries are loaded using absolute paths, which can cause issues if the binaryis moved to a different location and cannot locate its shared libraries.</p><p>In our specific use case, where we create and download binaries in separatecontainers, we encountered an error due to the absolute paths. To overcome this,we enabled the <code>--enable-load-relative</code> flag. This allowed the binary to findits shared libraries successfully, and it worked as expected in our CI/CDenvironment.</p><p><img src="/blog_images/2023/use-of-enable-load-relative-flag-in-building-ruby-binaries/passing-ruby-binary-image.png" alt="Successful Build"></p>]]></content>
    </entry><entry>
       <title><![CDATA[Improving the application performance by harnessing the full potential of ancestry gem]]></title>
       <author><name>Shemin Anto</name></author>
      <link href="https://www.bigbinary.com/blog/how-neetoTestify-improved-test-suites-performance-utilizing-ancestry-gem"/>
      <updated>2023-05-23T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/how-neetoTestify-improved-test-suites-performance-utilizing-ancestry-gem</id>
      <content type="html"><![CDATA[<p><a href="https://www.neeto.com/neetotestify">NeetoTestify</a> is a test management platformfor manual and automated QA testing. It allows us to organize test cases intological groups called test suites. A single suite can contain multiple testcases and multiple suites. The image below shows how the suites are displayed inthe UI in a hierarchical order. The arrangement in which the suites aredisplayed resembles a tree data structure.</p><p><img src="/blog_images/2023/how-neetoTestify-improved-test-suites-performance-utilizing-ancestry-gem/neetoTestify-test-cases-page.png" alt="Suites displayed with their hierarchial structure in NeetoTestify"></p><p>To display test suites in a tree structure, we need to store some informationabout the parent-child relationship in the database. This is where<a href="https://github.com/stefankroes/ancestry">Ancestry</a> comes in. Ancestry is a gemthat allows Rails Active Record models to be organized as a tree structure.</p><p>Normally, web applications implement pagination to show a list of records. But,implementing pagination for a tree-structured data can be challenging and canmake the application more complex. To avoid pagination, the application musthave enough performance to display an entire tree having a large number ofnodes/records without significant delays.</p><p>In this blog, we will discuss on how we leveraged the full potential of theAncestry gem to address the performance issues encountered while listing suites.</p><h3>1. Migration to materialized_path2</h3><p>There are several ways to store hierarchical data in a relational database, suchas materialized paths, closure tree tables, adjacency lists, and nested sets.Ancestry Gem uses the materialized path pattern to store hierarchical data.</p><p>The materialized path pattern is a technique in which a single node is stored inthe database as a record and it has an additional column to store thehierarchical information. In the case of the Ancestry gem, this additionalcolumn is named as <code>ancestry</code>. The <code>ancestry</code> column is used to store IDs of theancestors of a node as a single string, separated by a delimiter.</p><p>In order to understand how Ancestry gem uses materialized path pattern, firstlet's look at the nodes we have in our example. In the screenshot posted above,we see the following four nodes:</p><table><thead><tr><th>Test suite name</th><th>Node ID</th></tr></thead><tbody><tr><td>Suite 1</td><td>s1</td></tr><tr><td>Suite 1.1</td><td>s11</td></tr><tr><td>Suite 1.1.1</td><td>s111</td></tr><tr><td>Suite 1.2</td><td>s12</td></tr></tbody></table><p>In our example, the s1 is a root node, s11 and s12 are the children of node s1,and s111 is the child of s11.</p><p>In order to store the hierarchical data, the gem offers two types of ancestryformats, <code>materialized_path</code> and <code>materialized_path2</code>. In these techniques, eachnode is represented by a record in the database. Our example consists of fournodes, so there will be four records in the database. The only differencebetween <code>materialized_path</code> and <code>materialized_path2</code> lies in the format inwhich, the IDs are stored in the <code>ancestry</code> column.</p><h4>materialized_path</h4><p>Here the IDs of ancestors are stored in the format &quot;id-1/id-2/id-3&quot;, were<code>id-1</code>, <code>id-2</code> and <code>id-3</code> are the IDs of three nodes with <code>/</code> as the delimiter.The <code>id-1</code> is the root node, <code>id-2</code> is the child of <code>id-1</code> and <code>id-3</code> is thechild of <code>id-2</code>. In case of a root node, the <code>ancestry</code> will be <code>null</code>.</p><p>The table below shows how the suites in our example are stored in the databaseusing <code>materialized_path</code>:</p><table><thead><tr><th>ID</th><th>ancestry</th></tr></thead><tbody><tr><td>s1</td><td>null</td></tr><tr><td>s11</td><td>s1</td></tr><tr><td>s111</td><td>s1/s11</td></tr><tr><td>s12</td><td>s1</td></tr></tbody></table><p>This arrangement of node IDs as a single string makes it easier to query for alldescendants of a node, as we use SQL string functions to match the <code>ancestry</code>column. Here is the SQL statement to get descendants of suite s1:</p><pre><code class="language-sql">SELECT &quot;suites&quot;.* FROM &quot;suites&quot; WHERE (&quot;suites&quot;.&quot;ancestry&quot; LIKE 's1/%' OR &quot;suites&quot;.&quot;ancestry&quot; = 's1')</code></pre><p>The result of the above query is:</p><table><thead><tr><th>ID</th><th>ancestry</th></tr></thead><tbody><tr><td>s11</td><td>s1</td></tr><tr><td>s111</td><td>s1/s11</td></tr><tr><td>s12</td><td>s1</td></tr></tbody></table><h4>materialized_path2</h4><p><code>materialized_path2</code> stores ancestors in the format &quot;/id-1/id-2/id-3/&quot;, were<code>id-1</code> is the root node, <code>id-2</code> is the child of <code>id-1</code>, and <code>id-3</code> is the childof <code>id-2</code>. Here the delimiter is <code>/</code> as same as <code>materialized_path</code>, but the<code>ancestry</code> will be starting with a <code>/</code> and ending with a <code>/</code>. For a root nodethe <code>ancestry</code> will be <code>/</code>.</p><p>The table below shows how the suites in our example are stored in the databaseusing <code>materialized_path2</code>:</p><table><thead><tr><th>ID</th><th>ancestry</th></tr></thead><tbody><tr><td>s1</td><td>/</td></tr><tr><td>s11</td><td>/s1/</td></tr><tr><td>s111</td><td>/s1/s11/</td></tr><tr><td>s12</td><td>/s1/</td></tr></tbody></table><p>The SQL statement to get the descendants of suite s1 is:</p><pre><code class="language-sql">SELECT &quot;suites&quot;.* FROM &quot;suites&quot; WHERE &quot;suites&quot;.&quot;ancestry&quot; LIKE '/s1/%'</code></pre><p>The result of above query is:</p><table><thead><tr><th>ID</th><th>ancestry</th></tr></thead><tbody><tr><td>s11</td><td>/s1/</td></tr><tr><td>s111</td><td>/s1/s11/</td></tr><tr><td>s12</td><td>/s1/</td></tr></tbody></table><p>If we compare the 2 SQL queries, we can see that <code>materialized_path2</code> has oneless &quot;OR&quot; statement. This gives <code>materialized_path2</code> a slight advantage inperformance.</p><p>In NeetoTestify, we previously used the <code>materialized_path</code> format, but now wehave migrated to <code>materialized_path2</code> for improved performance.</p><h3>2. Added collation to the ancestry column</h3><p><a href="https://www.npgsql.org/efcore/misc/collations-and-case-sensitivity.html?tabs=data-annotations">Collation</a>In database systems, the index specifies how data is sorted and compared in adatabase. Collation provides the sorting rules, case sensitivity, and accentsensitivity properties for the data in the database.</p><p>As mentioned above, our resulting query for fetching the descendants of a nodewould be</p><pre><code class="language-sql">SELECT &quot;suites&quot;.* FROM &quot;suites&quot; WHERE &quot;suites&quot;.&quot;ancestry&quot; LIKE '/s1/%'</code></pre><p>It uses a <code>LIKE</code> query for comparison with a wildcard character(%). In general,when using the <code>LIKE</code> query with a wildcard character (%) on the right-hand sideof the pattern, the database can utilize an index and potentially optimize thequery performance. This optimization holds true for ASCII strings.</p><p>However, it's important to note that this optimization may not necessarily holdtrue for Unicode strings, as Unicode characters can have varying lengths anddifferent sorting rules compared to ASCII characters.</p><p>In our case, the <code>ancestry</code> column contains only ASCII strings. If we let thedatabase know about this constraint, we can optimize the database's queryperformance. To do that, we need to specify the collation type of the <code>ancestry</code>column.</p><p>From<a href="https://www.postgresql.org/docs/current/collation.html">Postgres's documentation</a>:</p><blockquote><p>The C and POSIX collations both specify traditional C behavior, in whichonly the ASCII letters A through Z are treated as letters, and sorting isdone strictly by character code byte values.</p></blockquote><p>Since we are using Postgres in NeetoTestify, we use collation <code>C</code>. Instead if weuse MySQL, then the ancestry suggests using collation <code>utf8mb4_bin</code>.</p><pre><code class="language-rb">class AddAncestryToTable &lt; ActiveRecord::Migration[6.1]  def change    change_table(:table) do |t|      # postgres      t.string &quot;ancestry&quot;, collation: 'C', null: false      t.index &quot;ancestry&quot;      # mysql      t.string &quot;ancestry&quot;, collation: 'utf8mb4_bin', null: false      t.index &quot;ancestry&quot;    end  endend</code></pre><h3>3. Usage of arrange method</h3><p>Previously, we were constructing the tree structure of the suites by fetchingthe children of each node individually from the database. For this, we firstfetched the suites whose <code>ancestry</code> is <code>/</code> (root nodes). Then, for each of thesesuites, we fetched their children, and repeated this process until we reachedleaf-level suites.</p><p><img src="/blog_images/2023/how-neetoTestify-improved-test-suites-performance-utilizing-ancestry-gem/previous-approach-to-list-suites.png" alt="Previous approach to list suites"></p><p>This recursive approach results in a large number of database queries, causingperformance issues as the tree size increases. Constructing a tree with n(4)nodes required n+1(5) database queries, adding to the complexity of the process.</p><p><img src="/blog_images/2023/how-neetoTestify-improved-test-suites-performance-utilizing-ancestry-gem/current-approach-to-list-suites.png" alt="Current approach to list suites"></p><p>The <code>arrange</code> method provided by Ancestry gem, converts the array of nodes intonested hashes, utilizing the <code>ancestry</code> column information. Also by using thismethod the number of database queries will remain 1, even if the number ofsuites and nested suites increases.</p><pre><code class="language-rb">suites = project.suites# SELECT &quot;suites&quot;.* FROM &quot;suites&quot; WHERE &quot;suites&quot;.&quot;project_id&quot; = &quot;p1&quot;# [#   &lt;Suite id: &quot;s1&quot;, project_id: &quot;p1&quot;, name: &quot;Suite 1&quot;, ancestry: &quot;/&quot;&gt;,#   &lt;Suite id: &quot;s11&quot;, project_id: &quot;p1&quot;, name: &quot;Suite 1.1&quot;, ancestry: &quot;/s1/&quot;&gt;,#   &lt;Suite id: &quot;s111&quot;, project_id: &quot;p1&quot;, name: &quot;Suite 1.1.1&quot;, ancestry: &quot;/s1/s11/&quot;&gt;,#   &lt;Suite id: &quot;s12&quot;, project_id: &quot;p1&quot;, name: &quot;Suite 1.2&quot;, ancestry: &quot;/s1/&quot;&gt;# ]suites.arrange# {#   &lt;Suite id: s1, project_id: &quot;p1&quot;, name: &quot;Suite 1&quot;, ancestry: &quot;/&quot;&gt; =&gt; {#     &lt;Suite id: s11, project_id: &quot;p1&quot;, name: &quot;Suite 1.1&quot;, ancestry: &quot;/s1/&quot;&gt; =&gt; {#       &lt;Suite id: s111, project_id: &quot;p1&quot;, name: &quot;Suite 1.1.1&quot;, ancestry: &quot;/s1/s11/&quot;&gt; =&gt; {}#     },#     &lt;Suite id: s12, project_id: &quot;p1&quot;, name: &quot;Suite 1.2&quot;, ancestry: &quot;/s1/&quot;&gt; =&gt; {}#   }# }</code></pre><p>The recursive approach took 5.72 seconds to retrieve 170 suites, but the arrayconversion approach of <code>arrange</code> method, retrieved the same number of suites in728.72 ms.</p><p><img src="/blog_images/2023/how-neetoTestify-improved-test-suites-performance-utilizing-ancestry-gem/performance-comparison.png" alt="Performance comparison"></p><p>The above image shows the advantage in performance while using the <code>arrange</code>method over the recursive approach. For the comparison of two approaches 170suites and 1650 test cases were considered.</p><p>By implementing the above 3 best practices, we were able to considerably improvethe overall performance of the application.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Three case studies of debugging redis running out of memory]]></title>
       <author><name>Unnikrishnan KP</name></author>
      <link href="https://www.bigbinary.com/blog/debugging-redis-memory-issue"/>
      <updated>2022-09-12T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/debugging-redis-memory-issue</id>
      <content type="html"><![CDATA[<p>In this blog, we will discuss three separate case studies of Redis runningout of memory. All three case studies have videos demonstrating how thedebugging was done.</p><p>All three videos were prepared for my team members to show how to go aboutdebugging. The videos are being presented &quot;as it was recorded&quot;.</p><h2>First Case Study</h2><p>When a job fails in <a href="https://sidekiq.org/">Sidekiq</a>, Sidekiq puts that job in<a href="https://github.com/mperham/sidekiq/wiki/API#retries">RetrySet</a> and retries thatjob until the job succeeds or the job reaches the maximum number of retries. Bydefault the maximum number of retries is 25. If a job fails 25 times, then thatjob is moved to the <a href="https://github.com/mperham/sidekiq/wiki/API#dead">DeadSet</a>.By default, Sidekiq will store up to 10,000 jobs in the deadset.</p><p>We had a situation where Redis was running out of memory. Here is how thedebugging was done.</p><p>&lt;iframewidth=&quot;560&quot;height=&quot;315&quot;src=&quot;https://www.youtube.com/embed/dg-K_IoT-x0&quot;title=&quot;YouTube video player&quot;frameborder=&quot;0&quot;allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;allowfullscreen</p><blockquote><p>&lt;/iframe&gt;</p></blockquote><h3>How to inspect the deadset</h3><pre><code class="language-ruby">ds = Sidekiq::DeadSet.newds.each do |job|  puts &quot;Job #{job['jid']}: #{job['class']} failed at #{job['failed_at']}&quot;end</code></pre><p>Running the following to view the latest entry to the dataset:</p><pre><code class="language-ruby">ds.firstds.count</code></pre><p>To see the memory usage following commands were executed in the Redis console.</p><pre><code>&gt; memory usage dead30042467&gt; type deadzset</code></pre><p>As discussed in the video large amount of payload was being sent. This is notthe right way to send data to the worker. Ideally, some sort of <code>id</code> should besent to the worker and the worker should be able to get the necessary data fromthe database based on the received <code>id</code>.</p><h4>References</h4><ol><li><a href="https://github.com/mperham/sidekiq/discussions/5011">How to increase the number of jobs in the Sidekiq deadset or disable deadset</a></li><li><a href="https://github.com/mperham/sidekiq/blob/main/lib/sidekiq/job_retry.rb#L71">Maximum number of job retries in Sidekiq</a></li><li><a href="https://github.com/mperham/sidekiq/blob/a89d84509c569a78882e24e0e28913a22c9311f5/lib/sidekiq.rb#L38">Maximum number of jobs in Sidekiq Deadset</a></li></ol><h2>Second case study</h2><p>In this case, the Redis instance of <a href="https://www.neeto.com/neetochat/">neetochat</a>was running out of memory. The Redis instance had 50MB capacity, but we weregetting the following error.</p><pre><code>ERROR: heartbeat: OOM command not allowed when used memory &gt; 'maxmemory'.</code></pre><p>We were pushing too many geo info records to Redis and that caused the memory tofill up. Here is the video capturing the debugging session.</p><p>&lt;iframewidth=&quot;560&quot;height=&quot;315&quot;src=&quot;https://www.youtube.com/embed/oz7Pcbc_zxM&quot;title=&quot;YouTube video player&quot;frameborder=&quot;0&quot;allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;allowfullscreen</p><blockquote><p>&lt;/iframe&gt;</p></blockquote><p>The following are the commands executed while debugging.</p><pre><code>&gt; pingPONG&gt; info&gt; info memory&gt; info keyspace&gt; keys *failed*&gt; keys *process*&gt; keys *geocoder*&gt; get getocoder:http://ipinfo.io/41.174.30.55/geo?</code></pre><h2>Third Case Study</h2><p>In this case, the authentication service of <a href="https://www.neeto.com/">Neeto</a> wasfailing because of memory exhaustion.</p><p>Here the number of keys was limited, but the payload data was huge and all thatpayload data was hogging the memory. Here is the video capturing the debuggingsession.</p><p>&lt;iframewidth=&quot;560&quot;height=&quot;315&quot;src=&quot;https://www.youtube.com/embed/a_Ygbcreokw&quot;title=&quot;YouTube video player&quot;frameborder=&quot;0&quot;allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;allowfullscreen</p><blockquote><p>&lt;/iframe&gt;</p></blockquote><p>The following are the commands executed while debugging.</p><pre><code>&gt; ping&gt; info keyspacedb0:keys=106, expires=86,avg_ttl=1233332728573&gt; key * (to see all the keys)</code></pre><p>The last command listed all 106 keys. Next, we needed to find how much memoryeach of these keys are using. For that, the following commands were executed.</p><pre><code>&gt; memory usage organizations/subdomains/bigbinary/neeto_app_links736 bytes&gt; memory usage failed10316224 (10MB)&gt; memory usage dead29871174 (29MB)</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3.1 adds Class#subclasses]]></title>
       <author><name>Ashik Salman</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-1-adds-class-subclasses"/>
      <updated>2021-12-27T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-1-adds-class-subclasses</id>
      <content type="html"><![CDATA[<p>Ruby 3.1 introduces the <code>Class#subclasses</code> method, which returns all classesdirectly inheriting from the receiver without including singleton classes.</p><p>We can see many implementations for calculating all subclasses of a particularclass from the Ruby community with different gems. The<a href="https://api.rubyonrails.org/classes/ActiveSupport/DescendantsTracker.html#method-c-subclasses">ActiveSupport::DescendantsTracker</a>is one of such implementations used in Rails framework. Finally, Ruby has addedthe <code>Class#subclasses</code> native implementation for it's 3.1 version release.</p><h2>After Ruby 3.1</h2><pre><code class="language-ruby">=&gt; class User; end=&gt; class Employee &lt; User; end=&gt; class Client &lt; User; end=&gt; class Manager &lt; Employee; end=&gt; class Developer &lt; Employee; end=&gt; User.subclasses=&gt; [Employee, Client]=&gt; Employee.subclasses=&gt; [Manager, Developer]=&gt; Developer.subclasses=&gt; []</code></pre><p>Here's the relevant <a href="https://github.com/ruby/ruby/pull/5045">pull request</a> and<a href="https://bugs.ruby-lang.org/issues/18273">feature discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3.1 adds MatchData#match & MatchData#match_length]]></title>
       <author><name>Ashik Salman</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-1-adds-match-data-methods"/>
      <updated>2021-11-09T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-1-adds-match-data-methods</id>
      <content type="html"><![CDATA[<p>Ruby 3.1 introduces the <code>MatchData#match</code> &amp; <code>MatchData#match_length</code> methodswhich returns the substring matched against a regular expression &amp; it's lengthrespectively.</p><pre><code class="language-ruby">=&gt; str = &quot;Ruby 3.1 introduces MatchData#match method&quot;=&gt;  m = /(?&lt;lang&gt;\S+)(\s)(?&lt;version&gt;[\d\.]+)/.match(str)=&gt; #&lt;MatchData &quot;Ruby 3.1&quot; lang:&quot;Ruby&quot; version:&quot;3.1&quot;&gt;</code></pre><h3>Before Ruby 3.1</h3><p>We have <code>MatchData#[]</code> method to access all the substring groups that arematched. We can access either a single match or multiple matches by giving asingle index or a range of indexes, respectively, using <code>MatchData#[]</code> method.</p><pre><code class="language-ruby">=&gt; m[:lang]=&gt; &quot;Ruby&quot;=&gt; m[1]=&gt; &quot;Ruby&quot;=&gt; m[:version]=&gt; &quot;3.1&quot;=&gt; m[0..2]=&gt; [&quot;Ruby 3.1&quot;, &quot;Ruby&quot;, &quot;3.1&quot;]=&gt; m[1..2]=&gt; [&quot;Ruby&quot;, &quot;3.1&quot;]=&gt; m[0].length=&gt; 8</code></pre><h3>After Ruby 3.1</h3><p>We have two new methods now to access the match data &amp; its length. The<code>MatchData#match</code> &amp; <code>MatchData#match_length</code> methods accepts either an index ora symbol as an argument to return the match data &amp; its length.</p><pre><code class="language-ruby">=&gt; m.match(0)=&gt; &quot;Ruby 3.1&quot;=&gt; m.match(:version)=&gt; &quot;3.1&quot;=&gt; m.match(3)=&gt; nil=&gt; m.match_length(0)=&gt; 8=&gt; m.match_length(:version)=&gt; 3=&gt; m.match_length(3)=&gt; nil</code></pre><p>Please note that <code>MatchData#match</code> is not same as <code>MatchData#[]</code> method. Thelater accepts an optional length or range as an argument to return the matcheddata but the former doesn't accept it, instead it allows only a single index orsymbol as an argument.</p><p>Here's the relevant <a href="https://github.com/ruby/ruby/pull/4851">pull request</a> and<a href="https://bugs.ruby-lang.org/issues/18172">feature discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3.1 adds Array#intersect?]]></title>
       <author><name>Ashik Salman</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-1-adds-array-intersect"/>
      <updated>2021-05-11T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-1-adds-array-intersect</id>
      <content type="html"><![CDATA[<p>Ruby 3.1 introduces the <code>Array#intersect?</code> method which returns boolean value<code>true</code> or <code>false</code> based on the given input arrays have common elements in it.</p><p>We already know<a href="https://ruby-doc.org/core-3.0.1/Array.html#method-i-intersection">Array#intersection or Array#&amp;</a>methods which are used to find the common elements between arrays.</p><pre><code class="language-ruby">=&gt; x = [1, 2, 5, 8]=&gt; y = [2, 4, 5, 9]=&gt; z = [3, 7]=&gt; x.intersection(y) # x &amp; y=&gt; [2, 5]=&gt; x.intersection(z) # x &amp; z=&gt; []</code></pre><p>The <code>intersection</code> or <code>&amp;</code> methods return an empty array or array having thecommon elements in it as result. We have to further call <code>empty?</code>, <code>any?</code> or<code>blank?</code> like methods to check whether two arrays intersect each other or not.</p><h2>Before Ruby 3.1</h2><pre><code class="language-ruby">=&gt; x.intersection(y).empty?=&gt; false=&gt; (x &amp; z).empty?=&gt; true=&gt; (y &amp; z).any?=&gt; false</code></pre><h2>After Ruby 3.1</h2><pre><code class="language-ruby">=&gt; x.intersect?(y)=&gt; true=&gt; y.intersect?(z)=&gt; false</code></pre><p>The <code>Array#intersect?</code> method accepts only single array as argument, but<code>Array#intersection</code> method can accept multiple arrays as arguments.</p><pre><code class="language-ruby">=&gt; x.intersection(y, z) # x &amp; y &amp; z=&gt; []</code></pre><p>The newly introduced <code>intersect?</code> method is faster than the above describedchecks using <code>intersection</code> or <code>&amp;</code> since the new method avoids creating anintermediate array while evaluating for common elements. Also new method returns<code>true</code> as soon as it finds a common element between arrays.</p><p>Here's the relevant <a href="https://github.com/ruby/ruby/pull/1972">pull request</a> and<a href="https://bugs.ruby-lang.org/issues/15198">feature discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3.1 accumulates Enumerable#tally results]]></title>
       <author><name>Ashik Salman</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-1-accumulates-enumerable-tally-results"/>
      <updated>2021-04-20T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-1-accumulates-enumerable-tally-results</id>
      <content type="html"><![CDATA[<p>We already know the<a href="https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-tally">Enumerable#tally</a>method is used to count the occurrences of each element in an <code>Enumerable</code>collection. The <code>#tally</code> method was introduced in ruby 2.7.0. Please check<a href="https://bigbinary.com/blog/ruby-2-7-adds-enumerable-tally">our blog</a> for moredetails on it.</p><p>Ruby 3.1 introduces an optional hash argument for the <code>Enumerable#tally</code> methodto count. If a hash is given, the total number of occurrences of each element isadded to the hash values and the final hash is returned.</p><h2>Ruby 2.7.0+</h2><pre><code class="language-ruby">=&gt; letters = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;a&quot;, &quot;d&quot;, &quot;c&quot;, &quot;a&quot;, &quot;c&quot;, &quot;a&quot;]=&gt; result = letters.tally=&gt; {&quot;a&quot;=&gt;4, &quot;b&quot;=&gt;1, &quot;c&quot;=&gt;3, &quot;d&quot;=&gt;1}</code></pre><h2>Before Ruby 3.1</h2><pre><code class="language-ruby">=&gt; new_letters = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;a&quot;, &quot;c&quot;, &quot;a&quot;]=&gt; new_letters.tally(result)=&gt; ArgumentError (wrong number of arguments (given 1, expected 0))</code></pre><h2>After Ruby 3.1</h2><pre><code class="language-ruby">=&gt; new_letters = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;a&quot;, &quot;c&quot;, &quot;a&quot;]=&gt; new_letters.tally(result)=&gt; {&quot;a&quot;=&gt;7, &quot;b&quot;=&gt;2, &quot;c&quot;=&gt;5, &quot;d&quot;=&gt;1}</code></pre><p>The value corresponding to each element in the hash must be an integer.Otherwise, the method raises <code>TypeError</code> on execution.</p><p>If the default value is defined for the given hash, it will be ignored and thecount of occurrences will be added in the returned hash.</p><pre><code class="language-ruby">=&gt; letters = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;a&quot;]=&gt; letters.tally(Hash.new(10))=&gt; {&quot;a&quot;=&gt;2, &quot;b&quot;=&gt;1, &quot;c&quot;=&gt;1}</code></pre><p>Here's the relevant <a href="https://github.com/ruby/ruby/pull/4318">pull request</a> and<a href="https://bugs.ruby-lang.org/issues/17744">feature discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3.1 adds Enumerable#compact and Enumerator::Lazy#compact]]></title>
       <author><name>Ashik Salman</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-1-adds-enumerable-compact"/>
      <updated>2021-04-06T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-1-adds-enumerable-compact</id>
      <content type="html"><![CDATA[<p>We are familiar with the<a href="https://apidock.com/ruby/v1_9_3_392/Array/compact">compact</a> method associatedwith arrays. The <code>compact</code> method returns a copy of the array after removing all<code>nil</code> elements.</p><p>Ruby 3.1 introduces the <code>compact</code> method in the <code>Enumerable</code> module. Now we canuse the <code>compact</code> method along with the <code>Enumerator</code> and <code>Enumerator::Lazy</code>classes which include the <code>Enumerable</code> module.</p><h2>Before Ruby 3.1</h2><pre><code class="language-ruby">=&gt; enum = [1, nil, 3, nil, 5].to_enum=&gt; #&lt;Enumerator: ...&gt;=&gt; enum.compact=&gt; NoMethodError (undefined method `compact' for #&lt;Enumerator: [1, nil, 3, nil, 5]:each&gt;)=&gt;  enum.reject { |x| x.nil? }=&gt; [1, 3, 5]</code></pre><h2>After Ruby 3.1</h2><pre><code class="language-ruby">=&gt; enum = [1, nil, 3, nil, 5].to_enum=&gt; #&lt;Enumerator: ...&gt;=&gt; enum.compact=&gt; [1, 3, 5]</code></pre><p>We can access the <code>compact</code> method to remove all <code>nil</code> occurrences from anyclasses where we include the <code>Enumerable</code> module.</p><pre><code class="language-ruby">class Person  include Enumerable  attr_accessor :names  def initialize(names = [])    @names = names  end  def each &amp;block    @names.each(&amp;block)  endend=&gt; list = Person.new([&quot;John&quot;, nil, &quot;James&quot;, nil])=&gt; #&lt;Person:0x0000000101cd3de8 @names=[&quot;John&quot;, nil, &quot;James&quot;, nil]&gt;=&gt; list.compact=&gt; [&quot;John&quot;, &quot;James&quot;]</code></pre><p>Similarly, lazy evaluation can be chained with the <code>compact</code> method to removeall <code>nil</code> entries from the <code>Enumerator</code> collection.</p><pre><code class="language-ruby">=&gt; enum = [1, nil, 3, nil, 5].to_enum.lazy.compact=&gt; #&lt;Enumerator::Lazy: ...&gt;=&gt; enum.force=&gt; [1, 3, 5]=&gt; list = Person.new([&quot;John&quot;, nil, &quot;James&quot;, nil]).lazy.compact=&gt; #&lt;Enumerator::Lazy: ...&gt;=&gt; list.force=&gt; [&quot;John&quot;, &quot;James&quot;]</code></pre><p>Here's the relevant <a href="https://github.com/ruby/ruby/pull/3851">pull request</a> and<a href="https://bugs.ruby-lang.org/issues/17312">feature discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3 is released - The list of Ruby 3 features]]></title>
       <author><name>Datt Dongare</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-features"/>
      <updated>2020-12-25T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-features</id>
      <content type="html"><![CDATA[<p>For all Rubyists, <strong>2020</strong> was a special year. Why wouldn't it be? Ruby 2 wasreleased in 2013. We have been using Ruby 2.x for almost 7 years and we havebeen waiting to see Ruby 3 get released. Finally, the wait is over now.<a href="https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/">Ruby 3.0.0 has been released</a>.It's time to unwrap the gift box and see all the Ruby 3 features we got.</p><h2>Ruby 3 major updates</h2><p>The number <strong>3</strong> is very significant in the Ruby 3 release. Be it releaseversion number, making performance 3x faster, or the trio of corecontributors(Matz, TenderLove, Koichi). Similarly, there were 3 major goals ofRuby 3: being faster, having better concurrency, and ensuring correctness.</p><p><img src="/blog_images/2020/ruby-3-features/ruby-3-features.jpg" alt="Ruby 3 features"></p><h3>1. Ruby 3 performance</h3><p>One of the major focuses for Ruby 3 was the performance. In fact, the initialdiscussion for Ruby 3 was started around it. Matz had set a very ambitious goalof making Ruby 3 times faster.</p><h4>What is Ruby 3x3?</h4><p>Before discussing this, let's revisit Ruby's core philosophy.</p><blockquote><p>&quot;I hope to see Ruby help every programmer in the world to be productive, andto enjoy programming, and to be happy.&quot; - Matz</p></blockquote><p>About Ruby 3x3, some asked whether the goal was to make Ruby the fastestlanguage? The answer is no. The main goal of Ruby 3x3 was to make Ruby 3 timesfaster than Ruby 2.</p><blockquote><p>No language is fast enough. - Matz</p></blockquote><p>Ruby was not designed to be fastest and if it would have been the goal, Rubywouldn't be the same as it is today. As Ruby language gets performance boost, itdefinitely helps our application be faster and scalable.</p><blockquote><p>&quot;In the design of the Ruby language we have been primarily focused onproductivity and the joy of programming. As a result, Ruby was too slow.&quot; -Matz</p></blockquote><p>There are two areas where performance can be measured: memory and CPU.</p><h4>CPU optimization</h4><p>Some enhancements in Ruby internals have been made to improve the speed. TheRuby team has optimized the JIT(Just In Time) compiler from previous versions.<a href="https://bigbinary.com/blog/mjit-support-in-ruby-2-6">Ruby MJIT compiler</a> wasfirst introduced in Ruby 2.6. Ruby 3 MJIT comes with better security and seemsto improve web apps performance to a greater extent.</p><p><img src="/blog_images/2020/ruby-3-features/machine-performance.jpg" alt="CPU optimization"></p><p>MJIT implementation is different from the usual JIT. When methods get calledrepeatedly e.g. 10000 times, MJIT will pick such methods which can be compiledinto native code and put them into a queue. Later MJIT will fetch the queue andconvert them to native code.</p><p>Please check<a href="https://engineering.appfolio.com/appfolio-engineering/2019/7/18/jit-and-rubys-mjit">JIT vs MJIT</a>for more details.</p><h4>Memory optimization</h4><p>Ruby 3 comes with an enhanced garbage collector. It has python's buffer-like APIwhich helps in better memory utilization. Since Ruby 1.8, Ruby has continuouslyevolved in<a href="https://scoutapm.com/blog/ruby-garbage-collection">Garbage collection</a>algorithms.</p><h5>Automatic Garbage Compaction</h5><p>The latest change in garbage collection is<a href="https://engineering.appfolio.com/appfolio-engineering/2019/3/22/ruby-27-and-the-compacting-garbage-collector">Garbage Compaction</a>.It was introduced in Ruby 2.7 where the process was a bit manual. But in version3 it is fully automatic. The compactor is invoked aptly to make sure propermemory utilization.</p><h5>Objects Grouping</h5><p>The garbage compactor moves objects in the heap. It groups dispersed objectstogether at a single place in the memory so that this memory can be used even byheavier objects later.</p><p><img src="/blog_images/2020/ruby-3-features/binary-background.jpg" alt="Memory optimization"></p><h3>2. Parallelism and Concurrency in Ruby 3</h3><p>Concurrency is one of the important aspects of any programming language. Matzfeels that Threads are not the right level of abstraction for Ruby programmersto use.</p><blockquote><p>I regret adding Threads. - Matz</p></blockquote><p>Ruby 3 makes it a lot easier to make applications where concurrency is a majorfocus. There are several features and improvements added in Ruby 3 related toconcurrency.</p><h4>Fibers</h4><p>Fibers are considered a disruptive addition in Ruby 3. Fibers are light-weightworkers which appear like Threads but have some advantages. It consumes lessmemory than Threads. It gives greater control to the programmer to define codesegments that can be paused or resumed resulting in better I/O handling.</p><p><a href="https://github.com/socketry/falcon">Falcon Rack web server</a> uses Async Fibersinternally. This allows Falcon to not block on I/O. Asynchronously managing I/Ogives a great uplift to the Falcon server to serve requests concurrently.</p><h5>Fiber Scheduler</h5><p><a href="https://bugs.ruby-lang.org/issues/16786">Fiber Scheduler</a> is an experimentalfeature added in Ruby 3. It was introduced to intercept blocking operations suchas I/O. The best thing is that it allows lightweight concurrency and can easilyintegrate into the existing codebase without changing the original logic. It'san interface and that can be implemented by creating a wrapper for a gem like<code>EventMachine</code> or <code>Async</code>. This interface design allows separation of concernsbetween the event loop implementation and the application code.</p><p>Following is an example to send multiple <code>HTTP</code> requests concurrently using<code>Async</code>.</p><pre><code class="language-ruby">require 'async'require 'net/http'require 'uri'LINKS = [  'https://bigbinary.com',  'https://basecamp.com']Async do  LINKS.each do |link|    Async do      Net::HTTP.get(URI(link))    end  endend</code></pre><p>Please check <a href="https://github.com/ruby/ruby/blob/master/doc/fiber.md">fibers</a> formore details.</p><h4>Ractors (Guilds)</h4><p>As we know Rubys global <code>VM lock (GVL)</code> prevents most Ruby Threads fromcomputing in parallel.<a href="https://github.com/ruby/ruby/blob/master/doc/ractor.md">Ractors</a> work aroundthe <code>GVL</code> to offer better parallelism. Ractor is an Actor-Model like concurrentabstraction designed to provide a parallel execution without thread-safetyconcerns.</p><p>Ractors allows Threads in different Ractors to compute at the same time. EachRactor has at least one thread, which may contain multiple fibers. In a Ractor,only a single thread is allowed to execute at a given time.</p><p>The following program returns the square root of a really large number. Itcalculates the result for both numbers in parallel.</p><pre><code class="language-ruby"># Math.sqrt(number) in ractor1, ractor2 run in parallelractor1, ractor2 = *(1..2).map do  Ractor.new do    number = Ractor.recv    Math.sqrt(number)  endend# send parametersractor1.send 3**71ractor2.send 4**51p ractor1.take #=&gt; 8.665717809264115e+16p ractor2.take #=&gt; 2.251799813685248e+15</code></pre><h3>3. Static Analysis</h3><p>We need tests to ensure correctness of our program. However by its very naturetests could mean code duplication.</p><blockquote><p>I hate tests because they aren't DRY. - Matz</p></blockquote><p>To ensure the correctness of a program, static analysis can be a great tool inaddition to tests.</p><p>The static analysis relies on inline type annotations which aren't DRY. Thesolution to address this challenge is having <code>.rbs</code> files parallel to our <code>.rb</code>files.</p><h4>RBS</h4><p>RBS is a language to describe the structure of a Ruby program. It provides us anoverview of the program and how overall classes, methods, etc. are defined.Using RBS, we can write the definition of Ruby classes, modules, methods,instance variables, variable types, and inheritance. It supports commonly usedpatterns in Ruby code, and advanced types like unions and duck typing.</p><p>The <code>.rbs</code> files are something similar to <code>.d.ts</code> files in TypeScript. Followingis a small example of how a <code>.rbs</code> file looks like. The advantage of having atype definition is that it can be validated against both implementation andexecution.</p><p>The below example is pretty self-explanatory. One thing we can note here though,<code>each_post</code> accepts a block or returns an enumerator.</p><pre><code class="language-ruby"># user.rbsclass User  attr_reader name: String  attr_reader email: String  attr_reader age: Integer  attr_reader posts: Array[Post]  def initialize: (name: String,                   email: String,                   age: Integer) -&gt; void  def each_post: () { (Post) -&gt; void } -&gt; void                   | () -&gt; Enumerator[Post, void]end</code></pre><p>Please check <a href="https://github.com/ruby/rbs">RBS gem documentation</a> for moredetails.</p><h4>Typeprof</h4><p>Introducing type definition was a challenge because there is already a lot ofexisting Ruby code around and we need a tool that could automatically generatethe type signature. Typeprof is a type analysis tool that reads plain Ruby codeand generates a prototype of type signature in RBS format by analyzing themethods, and its usage. Typeprof is an experimental feature. Right now onlysmall subset of ruby is supported.</p><blockquote><p>Ruby is simple in appearance, but is very complex inside, just like our humanbody. - Matz</p></blockquote><p>Let's see an example.</p><pre><code class="language-ruby"># user.rbclass User  def initialize(name:, email:, age:)    @name, @email, @age = name, email, age  end  attr_reader :name, :email, :ageendUser.new(name: &quot;John Doe&quot;, email: 'john@example.com', age: 23)</code></pre><p>Output</p><pre><code class="language-ruby">$ typeprof user.rb# Classesclass User  attr_reader name : String  attr_reader email : String  attr_reader age : Integer  def initialize : (name: String,                    email: String,                    age: Integer) -&gt; [String, String, Integer]end</code></pre><h2>Other Ruby 3 features and changes</h2><p>In the 7-year period, the Ruby community has seen significant improvement inperformance and other aspects. Apart from major goals, Ruby 3 is an excitingupdate with lots of new features, handy syntactic changes, and new enhancements.In this section, we will discuss some notable features.</p><blockquote><p>We are making Ruby even better. - Matz</p></blockquote><h3>One-line pattern matching syntax change</h3><p>Previously one-line pattern matching used the keyword <code>in</code>. Now it's replacedwith <code>=&gt;</code>.</p><h6>Ruby 2.7</h6><pre><code class="language-ruby">  { name: 'John', role: 'CTO' } in {name:}  p name # =&gt; 'John'</code></pre><h6>Ruby 3.0</h6><pre><code class="language-ruby">  { name: 'John', role: 'CTO' } =&gt; {name:}  p name # =&gt; 'John'</code></pre><h3>Find pattern</h3><p>The<a href="https://github.com/ruby/ruby/blob/9738f96fcfe50b2a605e350bdd40bd7a85665f54/test/ruby/test_pattern_matching.rb">find pattern</a>was introduced in <code>Ruby 2.7</code> as an experimental feature. This is now part of<code>Ruby 3.0</code>. It is similar to pattern matching in <code>Elixir</code> or <code>Haskell</code>.</p><pre><code class="language-ruby">users = [  { name: 'Oliver', role: 'CTO' },  { name: 'Sam', role: 'Manager' },  { role: 'customer' },  { name: 'Eve', city: 'New York' },  { name: 'Peter' },  { city: 'Chicago' }]users.each do |person|  case person  in { name:, role: 'CTO' }    p &quot;#{name} is the Founder.&quot;  in { name:, role: designation }    p &quot;#{name} is a #{designation}.&quot;  in { name:, city: 'New York' }    p &quot;#{name} lives in New York.&quot;  in {role: designation}    p &quot;Unknown is a #{designation}.&quot;  in { name: }    p &quot;#{name}'s designation is unknown.&quot;  else    p &quot;Pattern not found.&quot;  endend&quot;Oliver is the Founder.&quot;&quot;Sam is a Manager.&quot;&quot;Unknown is a customer.&quot;&quot;Eve lives in New York.&quot;&quot;Peter's designation is unknown.&quot;&quot;Pattern not found.&quot;</code></pre><h3>Endless Method definition</h3><p>This is another syntax enhancement that is optional to use. It enables us tocreate method definitions<a href="https://bigbinary.com/blog/ruby-3-adds-endless-method-definition">without end keyword</a>.</p><pre><code class="language-ruby">def: increment(x) = x + 1p increment(42) #=&gt; 43</code></pre><h3>Except method in Hash</h3><p>Sometimes while working on a non Rails app I get <code>undefined method except</code>. The<code>except</code> method was available only in Rails. In Ruby 3 <code>Hash#except</code> was<a href="https://bigbinary.com/blog/ruby-3-adds-new-method-hash-except">added to Ruby</a>itself.</p><pre><code class="language-ruby">user = { name: 'Oliver', age: 29, role: 'CTO' }user.except(:role) #=&gt; {:name=&gt; &quot;Oliver&quot;, :age=&gt; 29}</code></pre><h3>Memory View</h3><p>This is again an experimental feature. This is a C-API that will allow extensionlibraries to exchange raw memory area. Extension libraries can also sharemetadata of memory area that consists of shape and element format. It wasinspired by<a href="https://docs.python.org/3/c-api/buffer.html">Pythons buffer protocol</a>.</p><h3>Arguments forwarding</h3><p>Arguments forwarding <code>(...)</code> now supports leading arguments.</p><p>It is helpful in <code>method_missing</code>, where we need method name as well.</p><pre><code class="language-ruby">def method_missing(name, ...)  if name.to_s.end_with?('?')    self[name]  else    fallback(name, ...)  endend</code></pre><h3>Other Notable changes</h3><ul><li>Pasting in IRB is much faster.</li><li>The order of backtrace had been<a href="https://bigbinary.com/blog/ruby-2-5-prints-backstrace-and-error-message-in-reverse-order">reversed</a>.The error message and line number are printed first, rest of the backtrace isprinted later.</li><li><a href="https://bigbinary.com/blog/ruby-3-supports-transforming-hash-keys-using-a-hash-argument">Hash#transform_keys</a>accepts a hash that maps old keys with new keys.</li><li>Interpolated String literals are no longer frozen when<code># frozen-string-literal: true</code> is used.</li><li>Symbol#to_proc now returns a lambda Proc.</li><li><a href="https://bigbinary.com/blog/ruby-3-adds-symbol-name">Symbol#name</a> has beenadded, which returns the symbol's name as a frozen string.</li></ul><p>Many other changes can be checked at<a href="https://github.com/ruby/ruby/blob/v3_0_0_preview2/NEWS.md">Ruby 3 News</a> formore details.</p><h2>Transition</h2><p>A lot of core libraries have been modified to fit the Ruby 3 goal needs. Butthis doesn't mean that our old applications will suddenly stop working. The Rubyteam has made sure that these changes are backward compatible. We might see somedeprecation warnings in our existing code. The developers can fix these warningsto smoothly transition from an old version to the new version. We are all set touse new features and get all new performance improvements.</p><h2>Conclusion</h2><p>With great improvements in performance, memory utilization, static analysis, andnew features like Ractors and schedulers, we have great confidence in the futureof Ruby. With Ruby 3, the applications can be more scalable and more enjoyableto work with. The coming 2021 is not just a new year but rather a new era forall Rubyists. We at BigBinary thank everyone who contributed towards the Ruby 3release directly or indirectly.</p><p>Happy Holidays and Happy New Year folks!!!</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3 supports transforming hash keys using a hash argument]]></title>
       <author><name>Yedhin Kizhakkethara</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-supports-transforming-hash-keys-using-a-hash-argument"/>
      <updated>2020-12-15T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-supports-transforming-hash-keys-using-a-hash-argument</id>
      <content type="html"><![CDATA[<p>From Ruby 3 onwards, the <code>Hash#transform_keys</code> methodaccepts a hash argument for transformingexisting keys to new keys as specified in the argument.</p><h5>Usage before Ruby 3</h5><p>The following example shows how we used to apply <code>transform_keys</code>:</p><pre><code class="language-ruby"># 1. Declare address hashirb(main)&gt; address = {House: 'Kizhakkethara', house_no: 123, locality: 'India'}=&gt; {:House=&gt;&quot;Kizhakkethara&quot;, :house_no=&gt;123, :locality=&gt;&quot;India&quot;}# 2. Lowercase all the keysirb(main)&gt; address.transform_keys(&amp;:downcase)=&gt; {:house=&gt;&quot;Kizhakkethara&quot;, :house_no=&gt;123, :locality=&gt;&quot;India&quot;}# 3. Replace a particular key with a new key along with lowercasingirb(main)* address.transform_keys do |key|irb(main)*   new_key = keyirb(main)*   if key == :localityirb(main)*     new_key = :countryirb(main)*   endirb(main)*   new_key.to_s.downcase.to_symirb(main)&gt; end=&gt; {:house=&gt;&quot;Kizhakkethara&quot;, :house_no=&gt;123, :country=&gt;&quot;India&quot;}</code></pre><p>Although the changes required are trivial,we ended up writing a block to do the job.But what happens when the number of keysthat needs to be transformed increases?Do we need to write n-number of conditions within a block?Not anymore!</p><h5>Introducing Hash#transform_keys with hash argument</h5><p>Let's take the same example and provide a hash,which will be used for the transformation:</p><pre><code class="language-ruby"># 1. Declare address hashirb(main)&gt; address = {House: 'Kizhakkethara', house_no: 123, locality: 'India'}=&gt; {:House=&gt;&quot;Kizhakkethara&quot;, :house_no=&gt;123, :locality=&gt;&quot;India&quot;}# 2. Provide hash with transform_keysirb(main)&gt; address.transform_keys({House: :house, locality: :country})=&gt; {:house=&gt;&quot;Kizhakkethara&quot;, :house_no=&gt;123, :country=&gt;&quot;India&quot;}</code></pre><p>That does the job.But let's try to improve this code.Ultimately what happens when we invoke that methodis that it goes througheach of the keys in our variableandmaps the existing keys to the new keys.The <code>transform_keys</code> method accepts a block as a parameter.Thus let's pass in the <code>downcase</code> method as a <code>Proc</code> argument:</p><pre><code class="language-ruby"># 1. Passing in block parametersirb(main)&gt; address.transform_keys({locality: :country}, &amp;:downcase)=&gt; {:house=&gt;&quot;Kizhakkethara&quot;, :house_no=&gt;123, :country=&gt;&quot;India&quot;}</code></pre><p>An important point to be noted about the block parameter is that,<strong>it's only applied to keys which are not specified in the hash argument</strong>.</p><h3>Other common use cases</h3><h5>Transforming params received in the Rails controller</h5><pre><code class="language-ruby"># 1. Declare paramsirb(rails)&gt; params = ActionController::Parameters.new({&quot;firstName&quot;=&gt;&quot;oliver&quot;, &quot;lastName&quot;=&gt;&quot;smith&quot;, &quot;email&quot;=&gt;&quot;oliver@bigbinary.com&quot;})=&gt; &lt;ActionController::Parameters {&quot;firstName&quot;=&gt;&quot;oliver&quot;, &quot;lastName&quot;=&gt;&quot;smith&quot;, &quot;email&quot;=&gt;&quot;oliver@bigbinary.com&quot;} permitted: false&gt;# 2. Convert camelCase to snake_case using block parameterirb(rails)&gt; params.permit(:firstName, :lastName, :email).transform_keys(&amp;:underscore)=&gt; &lt;ActionController::Parameters {&quot;first_name&quot;=&gt;&quot;oliver&quot;, &quot;last_name&quot;=&gt;&quot;smith&quot;, &quot;email&quot;=&gt;&quot;oliver@bigbinary.com&quot;} permitted: true&gt;# 3. Or using hash argumentirb(rails)&gt; params.permit(:firstName, :lastName, :email).transform_keys({firstName: 'first_name', lastName: 'last_name'})=&gt; &lt;ActionController::Parameters {&quot;first_name&quot;=&gt;&quot;oliver&quot;, &quot;last_name&quot;=&gt;&quot;smith&quot;, &quot;email&quot;=&gt;&quot;oliver@bigbinary.com&quot;} permitted: true&gt;</code></pre><h5>Slicing hash along with key transformation</h5><pre><code class="language-ruby">irb(main)&gt; address.transform_keys({locality: :country}).slice(:house_no, :country)=&gt; {:house_no=&gt;123, :country=&gt;&quot;India&quot;}</code></pre><h5>Transforming keys in place using bang counterpart</h5><pre><code class="language-ruby">irb(main)&gt; address.transform_keys!({locality: :country}, &amp;:downcase)irb(main)&gt; address=&gt; {:house=&gt;&quot;Kizhakkethara&quot;, :house_no=&gt;123, :country=&gt;&quot;India&quot;}</code></pre><h5>References</h5><ul><li>Discussions regarding this feature can be found<a href="https://bugs.ruby-lang.org/issues/16274?tab=history">here</a>.</li><li>Commit for this feature can be found<a href="https://github.com/ruby/ruby/commit/b25e27277dc39f25cfca4db8452d254f6cc8046e">here</a>.</li></ul>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3 adds new method Hash#except]]></title>
       <author><name>Akhil Gautam</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-adds-new-method-hash-except"/>
      <updated>2020-11-11T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-adds-new-method-hash-except</id>
      <content type="html"><![CDATA[<p>Ruby 3 addsa new method, <code>except</code>, to the Hash class.<code>Hash#except</code> returns a hashexcluding the given keysandtheir values.</p><h3>Why do we need Hash#except?</h3><p>At times,we needto print or log everythingexcept some sensitive data.Let's saywe want to printuser detailsin the logsbut not passwords.</p><p>Before Ruby 3 we could have achievedit in the following ways:</p><pre><code class="language-ruby">irb(main):001:0&gt; user_details = { name: 'Akhil', age: 25, address: 'India', password: 'T:%g6R' }# 1. Reject with a block and include?irb(main):003:0&gt; puts user_details.reject { |key, _| key == :password }=&gt; { name: 'Akhil', age: 25, address: 'India' }# 2. Clone the hash with dup, tap into it and delete that key/value from the cloneirb(main):005:0&gt; puts user_details.dup.tap { |hash| hash.delete(:password) }=&gt; { name: 'Akhil', age: 25, address: 'India' }</code></pre><p>We know that ActiveSupport alreadycomes with <code>Hash#except</code>but for a simple Ruby applicationusing ActiveSupport wouldbe overkill.</p><h3>Ruby 3</h3><p>To make the above taskeasier and more explicit,Ruby 3 adds <code>Hash#except</code>to return a hashexcluding the given keys and their values:</p><pre><code class="language-ruby">irb(main):001:0&gt; user_details = { name: 'Akhil', age: 25, address: 'India', password: 'T:%g6R' }irb(main):002:0&gt; puts user_details.except(:password)=&gt; { name: 'Akhil', age: 25, address: 'India' }irb(main):003:0&gt; db_info = YAML.safe_load(File.read('./database.yml'))irb(main):004:0&gt; puts db_info.except(:username, :password)=&gt; { port: 5432, database_name: 'example_db_production' }</code></pre><p>Check out the<a href="https://github.com/ruby/ruby/commit/82ca8c73034b0a522fd2970ea39edfcd801955fe">commit</a>for more details.Discussion around it can be found <a href="https://bugs.ruby-lang.org/issues/15822">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3 adds Symbol#name]]></title>
       <author><name>Datt Dongare</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-adds-symbol-name"/>
      <updated>2020-10-12T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-adds-symbol-name</id>
      <content type="html"><![CDATA[<p>All are excited aboutwhat <code>Ruby 3.0</code> hasto offer to the Ruby developers.There is already a lot of buzzthat the feature set of <code>Ruby 3.0</code>will change the perspective of developershow they look at <code>Ruby</code>.</p><p>One of the important aspects of <code>Ruby 3.0</code> is optimization.The part of that optimization isthe introduction of <code>name</code> method for <code>Symbol</code>.In this blog,we will take a lookat what <code>name</code> method of class <code>Symbol</code> doesandwhy it was introduced.The new <code>name</code> method is introduced on <code>Symbol</code>to simply convert a symbol into a string.<code>Symbol#name</code> returns a string.Let's see how it works.</p><pre><code class="language-ruby">irb(main):001:0&gt; :simba.name=&gt; 'simba'irb(main):002:0&gt; :simba.name.class=&gt; Stringirb(main):003:0&gt; :simba.name === :simba.name=&gt; true</code></pre><p>Wait what?Don't we have <code>to_s</code>to convert a symbol into a string.Most of us have used <code>to_s</code> method on a <code>Symbol</code>.The <code>to_s</code> method returns a <code>String</code> objectandwe can simply use it.But why <code>name</code>?</p><p>Using <code>to_s</code> is okay in most cases.But the problem with <code>to_s</code> isthat it creates a new <code>String</code> objectevery time we call it on a symbol.We can verify this in <code>irb</code>.</p><pre><code class="language-ruby">irb(main):023:0&gt; :simba.to_s.object_id=&gt; 260irb(main):024:0&gt; :simba.to_s.object_id=&gt; 280</code></pre><p>Creating a new object for every <code>symbol</code> to a <code>string</code> conversionallocates new memory which increases overhead.The light was thrown on this issue by<a href="https://bugs.ruby-lang.org/users/6346">schneems (Richard Schneeman)</a>in a talk at RubyConf Thailandwhere he showed how <code>Symbol#to_s</code> allocationcauses significant overhead in <code>ActiveRecord</code>.This inspired <code>Ruby</code> communityto have a new method <code>name</code> on <code>Symbol</code>which returns a <code>frozen string</code> object.This reduces the string allocations dramaticallywhich results in reducing overhead.</p><pre><code class="language-ruby">irb(main):001:0&gt; :simba.name.frozen?=&gt; trueirb(main):002:0&gt; :simba.name.object_id=&gt; 200irb(main):003:0&gt; :simba.name.object_id=&gt; 200</code></pre><p>The reasonto bring this feature wasthat most of the timeswe want a simple string representationfor displaying purposeorto interpolate into another string.The result of <code>to_s</code> is rarely mutated directly.By introducing this methodwe save a lot of objectswhich helps in optimization.Now we know the benefits of <code>name</code>,we should prefer using <code>name</code> over <code>to_s</code>when we don't want to mutate a string.</p><p>For more information on discussion,official documentation,please head on to <a href="https://bugs.ruby-lang.org/issues/16150">Feature #16150</a> discussion,<a href="https://github.com/ruby/ruby/pull/3514">Pull request</a>and<a href="https://www.ruby-lang.org/en/news/2020/09/25/ruby-3-0-0-preview1-released/">Ruby 3.0 official release preview</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 3 adds endless method definition]]></title>
       <author><name>Akhil Gautam</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-3-adds-endless-method-definition"/>
      <updated>2020-09-15T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-3-adds-endless-method-definition</id>
      <content type="html"><![CDATA[<p>Ruby 3.0adds endless method definition.It enablesus to createmethod definitionswithout theneed of <code>end</code> keyword.It is marked as an experimental feature.</p><pre><code class="language-ruby"># endless method definition&gt;&gt; def raise_to_power(number, power) = number ** power&gt;&gt; raise_to_power(2, 5)=&gt; 32</code></pre><p>The discussion aroundit can be found <a href="https://bugs.ruby-lang.org/issues/16746">here</a>.Check out the<a href="https://github.com/ruby/ruby/pull/2996/files">pull request</a>for more details on this.</p>]]></content>
    </entry><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><entry>
       <title><![CDATA[MJIT Support in Ruby 2.6]]></title>
       <author><name>Sudeep Tarlekar</name></author>
      <link href="https://www.bigbinary.com/blog/mjit-support-in-ruby-2-6"/>
      <updated>2019-03-05T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/mjit-support-in-ruby-2-6</id>
      <content type="html"><![CDATA[<h3>What is JIT?</h3><p>JIT stands for Just-In-Time compiler. JIT converts repetitive code into bytecodewhich can then be sent to the processor directly, hence, saving time by notcompiling the same piece of code over and over.</p><h3>Ruby 2.6</h3><p>MJIT is introduced in Ruby 2.6. It is most commonly known as MRI JIT or MethodBased JIT.</p><p>It is a part of the Ruby 3x3 project started by Matz. The name &quot;Ruby 3x3&quot;signifies Ruby 3.0 will be 3 times faster than Ruby 2.0 and it will focus mainlyon performance. In addition to performance, it also aims for the followingthings:</p><ol><li>Portability</li><li>Stability</li><li>Security</li></ol><p>MJIT is still in development, therefore, MJIT is optional in Ruby 2.6. If youare running Ruby 2.6, then you can execute the following command.</p><pre><code class="language-shell">ruby --help</code></pre><p>You will see following options.</p><pre><code class="language-shell">--Jit-wait # Wait program execution until code compiles.--jit-verbose=num # Level information MJIT compiler prints for Ruby program.--jit-min-calls=num # Minimum count in loops for which MJIT should work.--jit-max-cache--jit-save-temps # Save compiled library to the file.</code></pre><p>Vladimir Makarov proposed improving performance by replacing VM instructionswith RTL(Register Transfer Language) and introducing the Method based JITcompiler.</p><p>Vladimir explained MJIT architecture in his<a href="https://youtu.be/qpZDw-p9yag?t=1655">RubyKaigi 2017 conference keynote</a>.</p><p>Ruby's compiler converts the code to YARV(Yet Another Ruby VM) instructions andthen these instructions are run by the Ruby Virtual Machine. Code that isexecuted too often is converted to RTL instructions, which runs faster.</p><p>Let's take a look at how MJIT works.</p><pre><code class="language-ruby"># mjit.rbrequire 'benchmark'puts Benchmark.measure {def test_whilestart_time = Time.nowi = 0    while i &lt; 4      i += 1    end    i    puts Time.now - start_timeend4.times { test_while }}</code></pre><p>Let's run this code with MJIT options and check what we got.</p><pre><code class="language-shell">ruby --jit --jit-verbose=1 --jit-wait --disable-gems mjit.rb</code></pre><pre><code class="language-shell">Time taken is 4.0e-06Time taken is 0.0Time taken is 0.0Time taken is 0.00.000082 0.000032 0.000114 ( 0.000105)Successful MJIT finish</code></pre><p>Nothing interesting right? And why is that? because we are iterating the loopfor 4 times and default value for MJIT to work is 5. We can always decide afterhow many calls MJIT should work by providing <code>--jit-min-calls=#number</code> option.</p><p>Let's tweak the program a bit so MJIT gets to work.</p><pre><code class="language-ruby">require 'benchmark'puts Benchmark.measure {def test_whilestart_time = Time.nowi = 0    while i &lt; 4_00_00_000      i += 1    end    puts &quot;Time taken is #{Time.now - start_time}&quot;end10.times { test_while }}</code></pre><p>After running the above code we can see some work done by MJIT.</p><pre><code class="language-shell">Time taken is 0.457916Time taken is 0.455921Time taken is 0.454672Time taken is 0.452823JIT success (72.5ms): block (2 levels) in &lt;main&gt;@mjit.rb:15 -&gt; /var/folders/v6/\_6sh53vn5gl3lct18w533gr80000gn/T//\_ruby_mjit_p66220u0.cJIT success (140.9ms): test_while@mjit.rb:4 -&gt; /var/folders/v6/\_6sh53vn5gl3lct18w533gr80000gn/T//\_ruby_mjit_p66220u1.cJIT compaction (23.0ms): Compacted 2 methods -&gt; /var/folders/v6/\_6sh53vn5gl3lct18w533gr80000gn/T//\_ruby_mjit_p66220u2.bundleTime taken is 0.463703Time taken is 0.102852Time taken is 0.103335Time taken is 0.103299Time taken is 0.103252Time taken is 0.1032612.797843 0.005357 3.141944 ( 2.801391)Successful MJIT finish</code></pre><p>Here's what's happening. Method ran 4 times and on the 5th call it found it isrunning same code again. So MJIT started a separate thread to convert the codeinto RTL instructions, which created a shared object library. Next, threads tookthat shared code and executed directly. As we passed option <code>--jit-verbose=1</code> wecan see what MJIT did.</p><p>What we are seeing in output is the following:</p><ol><li>Time taken to compile.</li><li>What block of code is compiled by JIT.</li><li>Location of compiled code.</li></ol><p>We can open the file and see how MJIT converted the piece of code to binaryinstructions but for that we need to pass another option which is<code>--jit-save-temps</code> and then just inspect those files.</p><p>After compiling the code to RTL instructions, take a look at the execution time.It dropped down to 0.10 ms from 0.46 ms. That's a neat speed bump.</p><p>Here is a comparison across some of the Ruby versions for some basic operations.</p><p>![Ruby time comparison in different versions](/blog_images/imageruby_mjit_execution_comparison.png)</p><h2>Rails comparison on Ruby 2.5, Ruby 2.6 and Ruby 2.6 with JIT</h2><p>Create a rails application with different Ruby versions and start a server. Wecan start the rails server with the JIT option, as shown below.</p><pre><code class="language-shell">RUBYOPT=&quot;--jit&quot; bundle exec rails s</code></pre><p>Now, we can start testing the performance on servers. We found that Ruby 2.6 isfaster than Ruby 2.5, but enabling JIT in Ruby 2.6 does not add more value tothe Rails application.</p><h2>MJIT status and future directions</h2><ul><li>It is in an early development stage.</li><li>Does not work on windows.</li><li>Needs more time to mature.</li><li>Needs more optimisations.</li><li>MJIT can use GCC or LLVM in the future C Compilers.</li></ul><h2>Further reading</h2><ol><li><a href="https://developers.redhat.com/blog/2018/03/22/ruby-3x3-performance-goal">Ruby 3x3 Performance Goal</a></li><li><a href="https://medium.com/@k0kubun/the-method-jit-compiler-for-ruby-2-6-388ee0989c13">The method JIT compiler for Ruby2.6</a></li><li><a href="https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch">Vladimir Makarov's Ruby Edition</a></li></ol>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 Range#cover? accepts Range object as argument]]></title>
       <author><name>Abhay Nikam</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-range-cover-now-accepts-range-object"/>
      <updated>2018-10-24T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-range-cover-now-accepts-range-object</id>
      <content type="html"><![CDATA[<p><code>Range#cover?</code> returns true if the object passed as argument is in the range.</p><pre><code class="language-ruby">(1..10).cover?(5)=&gt; true</code></pre><p><code>Range#cover?</code> returns false if the object passed as an argument isnon-comparable or is not in the range.</p><p>Before Ruby 2.6, <code>Range#cover?</code> used to return false if a Range object is passedas an argument.</p><pre><code class="language-ruby">&gt;&gt; (1..10).cover?(2..5)=&gt; false</code></pre><h4>Ruby 2.6</h4><p>In Ruby 2.6 <code>Range#cover?</code> can accept a Range object as an argument. It returnstrue if the argument Range is equal to or a subset of the Range.</p><pre><code class="language-ruby">(1..100).cover?(10..20)=&gt; true(1..10).cover?(2..5)=&gt; true(5..).cover?(4..)=&gt; false(&quot;a&quot;..&quot;d&quot;).cover?(&quot;x&quot;..&quot;z&quot;)=&gt; false</code></pre><p>Here is relevant<a href="https://github.com/ruby/ruby/commit/9ca738927293df1c7a2a1ed7e2d6cf89527b5438">commit</a>and <a href="https://bugs.ruby-lang.org/issues/14473">discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds RubyVM::AST module]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-adds-rubyvm-ast-module"/>
      <updated>2018-10-02T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-adds-rubyvm-ast-module</id>
      <content type="html"><![CDATA[<p>Ruby 2.6 added <code>RubyVM::AST</code> to generate the<a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> ofcode. Please note, this feature is experimental and under active development.</p><p>As of now, <code>RubyVM::AST</code> supports two methods: <code>parse</code> and <code>parse_file</code>.</p><p><code>parse</code> method takes a string as a parameter and returns the root node of thetree in the form of the object, RubyVM::AST::Node (Link is not available).</p><p><code>parse_file</code> method takes the file name as a parameter and returns the root nodeof the tree in the form of the object,<a href="https://ruby-doc.org/core-2.6.0.preview2/RubyVM/AST/Node.html">RubyVM::AST::Node</a>.</p><h4>Ruby 2.6.0-preview2</h4><pre><code class="language-ruby">irb&gt; RubyVM::AST.parse(&quot;(1..100).select { |num| num % 5 == 0 }&quot;)=&gt; #&lt;RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 1:38): &gt;irb&gt; RubyVM::AST.parse_file(&quot;/Users/amit/app.rb&quot;)=&gt; #&lt;RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 1:38): &gt;</code></pre><p><a href="https://ruby-doc.org/core-2.6.0.preview2/RubyVM/AST/Node.html">RubyVM::AST::Node</a>has seven public instance methods - <code>children</code>, <code>first_column</code>, <code>first_lineno</code>,<code>inspect</code>, <code>last_column</code>, <code>last_lineno</code> and <code>type</code>.</p><h4>Ruby 2.6.0-preview2</h4><pre><code class="language-ruby">irb&gt; ast_node = RubyVM::AST.parse(&quot;(1..100).select { |num| num % 5 == 0 }&quot;)=&gt; #&lt;RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 1:38): &gt;irb&gt; ast_node.children=&gt; [nil, #&lt;RubyVM::AST::Node(NODE_ITER(9) 1:0, 1:38): &gt;]irb&gt; ast_node.first_column=&gt; 0irb&gt; ast_node.first_lineno=&gt; 1irb&gt; ast_node.inspect=&gt; &quot;#&lt;RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 1:38): &gt;&quot;irb&gt; ast_node.last_column=&gt; 38irb&gt; ast_node.last_lineno=&gt; 1irb&gt; ast_node.type=&gt; &quot;NODE_SCOPE&quot;</code></pre><p>This module will majorly help in building a static code analyzer and formatter.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Configuring memory allocation in ImageMagick]]></title>
       <author><name>Ershad Kunnakkadan</name></author>
      <link href="https://www.bigbinary.com/blog/configuring-memory-allocation-in-imagemagick"/>
      <updated>2018-09-12T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/configuring-memory-allocation-in-imagemagick</id>
      <content type="html"><![CDATA[<p>ImageMagick has a security policy file<a href="https://www.imagemagick.org/source/policy.xml">policy.xml</a> using which we cancontrol and limit the execution of the program. For example, the default memorylimit of ImageMagick-6 is 256 MiB.</p><p>Recently, we saw following error while processing a gif image.</p><pre><code class="language-text">convert-im6.q16: DistributedPixelCache '127.0.0.1' @ error/distribute-cache.c/ConnectPixelCacheServer/244.convert-im6.q16: cache resources exhausted `file.gif' @ error/cache.c/OpenPixelCache/3945.</code></pre><p>This happens when ImageMagick cannot allocate enough memory to process theimage. This can be fixed by tweaking memory configuration in <code>policy.xml</code>.</p><p>Path of <code>policy.xml</code> can be located as follows.</p><pre><code class="language-text">$ identify -list policyPath: /etc/ImageMagick-6/policy.xml  Policy: Resource    name: disk    value: 1GiB</code></pre><p>Memory limit can be configured in the following line of <code>policy.xml</code>.</p><pre><code class="language-xml">&lt;policy domain=&quot;resource&quot; name=&quot;memory&quot; value=&quot;256MiB&quot;/&gt;</code></pre><p>Increasing this value would solve the error if you have a machine with larger amemory.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds Enumerable#filter as alias of Enumerable#select]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-adds-enumerable-filter-as-an-alias-of-enumerable-select"/>
      <updated>2018-08-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-adds-enumerable-filter-as-an-alias-of-enumerable-select</id>
      <content type="html"><![CDATA[<p>Ruby 2.6 has added <code>Enumerable#filter</code> as an alias of <code>Enumerable#select</code>. Thereason for adding <code>Enumerable#filter</code> as an alias is to make it easier forpeople coming from other languages to use Ruby. A lot of other languages,including Java, R, PHP etc., have a filter method to filter/select records basedon a condition.</p><p>Let's take an example in which we have to select/filter all numbers which aredivisible by 5 from a range.</p><h4>Ruby 2.5</h4><pre><code class="language-ruby">irb&gt; (1..100).select { |num| num % 5 == 0 }=&gt; [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]irb&gt; (1..100).filter { |num| num % 5 == 0 }=&gt; Traceback (most recent call last):2: from /Users/amit/.rvm/rubies/ruby-2.5.1/bin/irb:11:in `&lt;main&gt;' 1: from (irb):2 NoMethodError (undefined method`filter' for 1..100:Range)</code></pre><h4>Ruby 2.6.0-preview2</h4><pre><code class="language-ruby">irb&gt; (1..100).select { |num| num % 5 == 0 }=&gt; [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]irb&gt; (1..100).filter { |num| num % 5 == 0 }=&gt; [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]</code></pre><p>Also note, along with <code>Enumerable#filter</code>, <code>Enumerable#filter!</code>,<code>Enumerable#select!</code> was also added as an alias.</p><p>Here is the relevant <a href="https://github.com/ruby/ruby/commit/b1a8c64483">commit</a>and <a href="https://bugs.ruby-lang.org/issues/13784">discussion</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds support for non-ASCII capital letter]]></title>
       <author><name>Rohan Pujari</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2.6-adds-support-for-non-ascii-capital-case-constant"/>
      <updated>2018-08-22T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2.6-adds-support-for-non-ascii-capital-case-constant</id>
      <content type="html"><![CDATA[<p>Before Ruby 2.6, constant must have a capital ASCII letter as the firstcharacter. It means class and module name cannot start with non-ASCII capitalcharacter.</p><p>Below code will raise <code>class/module name must be CONSTANT</code> exception.</p><pre><code class="language-ruby">  class   end</code></pre><p>We can use above non-ASCII character as a method name or variable name though.</p><p>Below code will run without any exception</p><pre><code class="language-ruby">  class NonAsciiMethodAndVariable    def        = &quot;BigBinary&quot;    end  end</code></pre><p>&quot;&quot; is treated as a variable name in above example, even though firstletter() is a capital non-ASCII character.</p><h4>Ruby 2.6</h4><p>Ruby 2.6 relaxes above mentioned limitation. We can now define constants inlanguages other than English. Languages having capital letters like Russian andGreek can be used to define constant name.</p><p>Below code will run without exception in any Ruby 2.6.</p><pre><code class="language-ruby">  class   end</code></pre><p>As capital non-Ascii characters are now treated as constant, below code willraise a warning in Ruby 2.6.</p><pre><code class="language-ruby">  irb(main):001:0&gt;  = &quot;BigBinary&quot;  =&gt; &quot;BigBinary&quot;  irb(main):002:0&gt;  = &quot;BigBinary&quot;  (irb):2: warning: already initialized constant   (irb):1: warning: previous definition of  was here</code></pre><p>Above code will run without any warnings on Ruby versions prior to 2.6</p><p>Here is relevant <a href="https://github.com/ruby/ruby/commit/f852af">commit</a> and<a href="https://bugs.ruby-lang.org/issues/13770">discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Setting up a high performance Geocoder]]></title>
       <author><name>Midhun Krishna</name></author>
      <link href="https://www.bigbinary.com/blog/setting-up-a-high-performance-geocoder"/>
      <updated>2018-08-21T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/setting-up-a-high-performance-geocoder</id>
      <content type="html"><![CDATA[<p>One of our applications uses geocoding extensively. When we started the project,we included the excellent<a href="https://github.com/alexreisner/geocoder">Geocoder gem</a>, and set<a href="https://developers.google.com/maps/documentation/geocoding/start">Google</a> asthe geocoding backend. As the application scaled, its geocoding requirementsgrew and soon we were looking at geocoding bills worth thousands of dollars.</p><h3>An alternative Geocoder</h3><p>Our search for an alternative geocoder landed us on Nominatim. Written in C,with a PHP web interface, Nominatim was performant enough for our requirements.Once set up, Nominatim required 8GB of RAM to run and this included RAM for thePostgreSQL (+ PostGIS) as well.</p><p>The rest of the blog discusses how to setup Nominatim and the tips and tricksthat we learned along the way and how it compares with the geocoding solutionoffered by Google.</p><h3>Setting up Nominatim</h3><p>We started off by looking for Amazon Machine Images with Nominatim setup andcould only find one which was hosted by<a href="https://www.openstreetmap.org/">OpenStreetMap</a> but the magnet link was dead.</p><p>Next, we went through the<a href="http://nominatim.org/release-docs/latest/admin/Installation/">official installation document</a>.We decided to give docker a shot and found that there are many Nominatim dockerbuilds. We used<a href="https://github.com/merlinnot/nominatim-docker">https://github.com/merlinnot/nominatim-docker</a>since it seemed to follow all the steps mentioned in the official installationguide.</p><h2>Issues faced during Setup</h2><h4>Out of Memory Errors</h4><p>The official documentation recommends using 32GB of RAM for initial import butwe needed to double the memory to 64GB to make it work.</p><p>Also any time docker build failed, due to the large amount of data that isgenerated on each run, we also ran out of disk space on subsequent docker buildssince docker caches layers across builds.</p><h4>Merging Multiple Regions</h4><p>We wanted to geocode locations from USA, Mexico, Canada and Sri Lanka. USA,Mexico and Canada are<a href="http://download.geofabrik.de/north-america.html#subregions">included by default in North America data extract</a>but we had to merge data for Sri Lanka with North America to get it in a formatrequired for initial import.</p><p>The following snippet pre-processes map data for North America and Sri Lankainto a single data.osm.pbf file that can be directly used by Nominatiminstaller.</p><pre><code class="language-bash">RUN curl -L 'http://download.geofabrik.de/north-america-latest.osm.pbf' \    --create-dirs -o /srv/nominatim/src/north-america-latest.osm.pbfRUN curl -L 'http://download.geofabrik.de/asia/sri-lanka-latest.osm.pbf' \    --create-dirs -o /srv/nominatim/src/sri-lanka-latest.osm.pbfRUN osmconvert /srv/nominatim/src/north-america-latest.osm.pbf \    -o=/srv/nominatim/src/north-america-latest.o5mRUN osmconvert /srv/nominatim/src/sri-lanka-latest.osm.pbf \    -o=/srv/nominatim/src/sri-lanka-latest.o5mRUN osmconvert /srv/nominatim/src/north-america-latest.o5m \    /srv/nominatim/src/sri-lanka-latest.o5m \    -o=/srv/nominatim/src/data.o5mRUN osmconvert /srv/nominatim/src/data.o5m \    -o=/srv/nominatim/src/data.osm.pbf</code></pre><h4>Slow Search times</h4><p>Once the installation was done, we tried running simple location<a href="https://nominatim.openstreetmap.org/search.php?q=New+York&amp;polygon_geojson=1&amp;viewbox=">searches like this one</a>,but the search timed out. Usually Nominatim can provide a lot of informationfrom its web-interface by appending <code>&amp;debug=true</code> to the search query.</p><pre><code class="language-bash"># fromhttps://nominatim.openstreetmap.org/search.php?q=New+York&amp;polygon_geojson=1&amp;viewbox=# tohttps://nominatim.openstreetmap.org/search.php?q=New+York&amp;polygon_geojson=1&amp;viewbox=&amp;debug=true</code></pre><p>We created an<a href="https://github.com/openstreetmap/Nominatim/issues/1023">issue in Nominatim repository</a>and got very prompt replies from Nominatim maintainers, especially from<a href="https://github.com/lonvia">Sarah Hoffman</a> .</p><pre><code class="language-sql"># runs analyze on the entire nominatim databasepsql -d nominatim -c 'ANALYZE VERBOSE'</code></pre><p>PostgreSQL query planner<a href="https://www.postgresql.org/docs/9.5/static/planner-stats.html">depends on statistics</a>collected by<a href="https://www.postgresql.org/docs/9.1/static/monitoring-stats.html">postgres statistics collector</a>while executing a query. In our case, query planner took an enormous amount oftime to plan queries as there were no stats collected since we had a freshinstallation.</p><h3>Comparing Nominatim and Google Geocoder</h3><p>We compared 2500 addresses and we found that Google geocoded 99% of thoseaddresses. In comparison Nominatim could only geocode 47% of the addresses.</p><p>It means we still need to geocode ~50% of addresses using Google geocoder. Wefound that we could increase geocoding efficiency by normalizing the addresseswe had.</p><h3>Address Normalization using libpostal</h3><p><a href="https://github.com/openvenues/libpostal">Libpostal</a> is an address normalizer,which uses<a href="https://en.wikipedia.org/wiki/Natural-language_processing#Statistical_natural-language_processing_(SNLP)">statistical natural-language processing</a>to normalize addresses. Libpostal also has<a href="https://github.com/openvenues/ruby_postal">ruby bindings</a> which made it quiteeasy to use it for our test purposes.</p><p>Once libpostal and its ruby-bindings were installed (installation isstraightforward and steps are available in<a href="https://github.com/openvenues/ruby_postal">ruby-postal's github page</a>), we gavelibpostal + Nominatim a go.</p><pre><code class="language-ruby">require 'geocoder'require 'ruby_postal/expand'require 'ruby_postal/parser'Geocoder.configure({lookup: :nominatim, nominatim: { host: &quot;nominatim_host:port&quot;}})full_address = [... address for normalization ...]expanded_addresses = Postal::Expand.expand_address(full_address)parsed_addresses = expanded_addresses.map do |address|  Postal::Parser.parse_address(address)endparsed_addresses.each do | address |  parsed_address = [:house_number, :road, :city, :state, :postcode, :country].inject([]) do |acc, key|    # address is of format    # [{label: 'postcode', value: 12345}, {label: 'city', value: 'NY'} .. ]    key_value = address.detect { |address| address[:label] == key }    if key_value        acc &lt;&lt; &quot;#{key_value_pair[:value]}&quot;.titleize    end    acc  end  coordinates = Geocoder.coordinates(parsed_address.join(&quot;, &quot;))  if (coordinates.is_a? Array) &amp;&amp; coordinates.present?    puts &quot;By Libpostal #{coordinates} =&gt; #{parsed_address.join(&quot;, &quot;)}&quot;    break  endend</code></pre><p>With this, we were able to improve our geocoding efficiency by 10% asNominatim + Libpostal combination could geocode ~ 59% of addresses.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds write_timeout to Net::HTTP]]></title>
       <author><name>Taha Husain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-adds-write-timeout-to-net-http"/>
      <updated>2018-08-14T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-adds-write-timeout-to-net-http</id>
      <content type="html"><![CDATA[<p>Before Ruby 2.6, if we created a large request with <code>Net::HTTP</code>, it would hangforever until request is interrupted. To fix this issue,<a href="https://docs.ruby-lang.org/en/trunk/Net/HTTP.html#attribute-i-write_timeout">write_timeout</a>attribute and<a href="https://docs.ruby-lang.org/en/trunk/Net/HTTP.html#method-i-write_timeout-3D">write_timeout=</a>method is added to <a href="https://docs.ruby-lang.org/en/2.6.0/">Net::HTTP</a> in Ruby2.6. Default value for <code>write_timeout</code> is 60 seconds and can be set to aninteger or a float value.</p><p>Similarly, <code>write_timeout</code> attribute and <code>write_timeout=</code> method is added to<code>Net::BufferedIO</code> class.</p><p>If any chunk of response is not written within number of seconds provided to<code>write_timeout</code>, <a href="https://docs.ruby-lang.org/en/2.6.0/">Net::WriteTimeout</a>exception is raised. <code>Net::WriteTimeout</code> exception is not raised on Windowssystems.</p><h6>Example</h6><pre><code class="language-ruby"># server.rbrequire 'socket'server = TCPServer.new('localhost', 2345)loop dosocket = server.acceptend</code></pre><h5>Ruby 2.5.1</h5><pre><code class="language-ruby"># client.rbrequire 'net/http'connection = Net::HTTP.new('localhost', 2345)connection.open_timeout = 1connection.read_timeout = 3connection.startpost = Net::HTTP::Post.new('/')body = (('a' _ 1023) + &quot;\n&quot;) _ 5_000post.body = bodyputs &quot;Sending #{body.bytesize} bytes&quot;connection.request(post)</code></pre><h6>Output</h6><pre><code class="language-ruby">\$ RBENV_VERSION=2.5.1 ruby client.rbSending 5120000 bytes</code></pre><p>Ruby 2.5.1 processes request endlessly unless above program is interrupted.</p><h5>Ruby 2.6.0-dev</h5><p>Add <code>write_timeout</code> attribute to <code>Net::HTTP</code> instance in client.rb program.</p><pre><code class="language-ruby"># client.rbrequire 'net/http'connection = Net::HTTP.new('localhost', 2345)connection.open_timeout = 1connection.read_timeout = 3# set write_timeout to 10 secondsconnection.write_timeout = 10connection.startpost = Net::HTTP::Post.new('/')body = (('a' _ 1023) + &quot;\n&quot;) _ 5_000post.body = bodyputs &quot;Sending #{body.bytesize} bytes&quot;connection.request(post)</code></pre><h6>Output</h6><pre><code class="language-ruby">\$ RBENV_VERSION=2.6.0-dev ruby client.rbSending 5120000 bytesTraceback (most recent call last):13: `from client.rb:17:in `&lt;main&gt;`` 12: `from /net/http.rb:1479:in `request``11: `from /net/http.rb:1506:in `transport_request`` 10: `from /net/http.rb:1506:in `catch``9: `from /net/http.rb:1507:in `block in transport_request`` 8: `from /net/http/generic_request.rb:123:in `exec``7: `from /net/http/generic_request.rb:189:in `send_request_with_body`` 6: `from /net/protocol.rb:221:in `write``5: `from /net/protocol.rb:239:in `writing`` 4: `from /net/protocol.rb:222:in `block in write``3: `from /net/protocol.rb:249:in `write0`` 2: `from /net/protocol.rb:249:in `each_with_index``1: `from /net/protocol.rb:249:in `each`` `/net/protocol.rb:270:in `block in write0`: Net::WriteTimeout (Net::WriteTimeout)`</code></pre><p>In Ruby 2.6.0, above program is terminated raising <code>Net::WriteTimeout</code> exceptionafter 10 seconds (value set to <code>write_timeout</code> attribute).</p><p>Here is relevant <a href="https://github.com/ruby/ruby/commit/bd7c46">commit</a> and<a href="https://bugs.ruby-lang.org/issues/13396">discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds Dir#each_child & Dir#children instance]]></title>
       <author><name>Tejaswini Chile</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-introduces-dir-each_child-and-dir-children-instance-methods"/>
      <updated>2018-08-07T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-introduces-dir-each_child-and-dir-children-instance-methods</id>
      <content type="html"><![CDATA[<p>Ruby 2.5 had introduced class level methods<a href="https://ruby-doc.org/core-2.5.1/Dir.html#method-c-each_child">Dir::each_child</a>and <a href="https://ruby-doc.org/core-2.5.1/Dir.html#method-c-children">Dir::children</a>.We wrote a<a href="https://blog.bigbinary.com/2017/11/21/ruby-2_5-introduces-dir-children-and-dir-each_child.html">detailed blog</a>about it.</p><p>In Ruby 2.6, same methods are added as instance methods on <code>Dir</code> class.Dir#children (Link is not available) returns array of all the filenames except<code>.</code> and <code>..</code> in the directory. Dir#each_child (Link is not available) yields allthe filenames and operates on it.</p><p>Let's have a look at examples to understand it better.</p><h5>Dir#children</h5><pre><code class="language-ruby">directory = Dir.new('/Users/tejaswinichile/workspace')directory.children=&gt; [&quot;panda.png&quot;, &quot;apple.png&quot;, &quot;banana.png&quot;, &quot;camera.jpg&quot;]</code></pre><p><code>Dir#each_child</code> iterates and calls block for each file entry in the givendirectory. It uses filename as a parameter to the block.</p><h5>Dir#each_child</h5><pre><code class="language-ruby">directory = Dir.new('/Users/tejaswinichile/workspace')directory.each_child { |filename| puts &quot;Currently reading: #{filename}&quot;}Currently reading: panda.pngCurrently reading: apple.pngCurrently reading: banana.pngCurrently reading: camera.jpg=&gt; #&lt;Dir:/Users/tejaswinichile/Desktop&gt;</code></pre><p>If we don't pass any block to <code>each_child</code>, it returns enumerator instead.</p><pre><code class="language-ruby">directory = Dir.new('/Users/tejaswinichile/workspace')directory.each_child=&gt; #&lt;Enumerator: #&lt;Dir:/Users/tejaswinichile/Desktop&gt;:each_child&gt;</code></pre><p>Here is relevant<a href="https://github.com/ruby/ruby/commit/6a3a7e9114c3ede47d15f0d2a73f392cfcdd1ea7">commit</a>and <a href="https://bugs.ruby-lang.org/issues/13969">discussion</a> for this change.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds exception parameters for Integer & Float methods]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-adds-option-to-not-raise-exception-for-integer-float-methods"/>
      <updated>2018-07-31T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-adds-option-to-not-raise-exception-for-integer-float-methods</id>
      <content type="html"><![CDATA[<p>We can use <code>Integer</code> and <code>Float</code> methods to convert values to integers andfloats respectively. Ruby also has <code>to_i</code> and <code>to_f</code> methods for same purpose.Let's see how it differs from the <code>Integer</code> method.</p><pre><code class="language-ruby">&gt; &gt; &quot;1one&quot;.to_i&gt; &gt; =&gt; 1&gt; &gt; Integer(&quot;1one&quot;)&gt; &gt; ArgumentError: invalid value for Integer(): &quot;1one&quot;    from (irb):2:in `Integer'    from (irb):2    from /Users/prathamesh/.rbenv/versions/2.4.0/bin/irb:11:in `&lt;main&gt;'&gt; &gt;</code></pre><p>The <code>to_i</code> method tries to convert the given input to integer as much aspossible whereas the <code>Integer</code> method throws an <code>ArgumentError</code> if it can'tcovert the input to integer. The <code>Integer</code> and <code>Float</code> methods parse morestrictly compared to <code>to_i</code> and <code>to_f</code> respectively.</p><p>Some times, we might need the strictness of <code>Integer</code> and <code>Float</code> but ability tonot raise an exception every time the input can't be parsed.</p><p>Before Ruby 2.6 it was possible to achieve it in following way.</p><pre><code class="language-ruby">&gt; &gt; Integer(&quot;msg&quot;) rescue nil&gt; &gt;</code></pre><p>In Ruby 2.6, the<a href="https://bugs.ruby-lang.org/issues/12732">Integer and Float methods accept a keyword argument exception</a>which can be either <code>true</code> or <code>false</code>. If it is <code>false</code> then no exception israised if the input can't be parsed and <code>nil</code> is returned.</p><pre><code class="language-ruby">&gt; &gt; Float(&quot;foo&quot;, exception: false)&gt; &gt; =&gt; nil&gt; &gt; Integer(&quot;foo&quot;, exception: false)&gt; &gt; =&gt; nil&gt; &gt;</code></pre><p>This is also faster than rescuing the exception and returning <code>nil</code>.</p><pre><code class="language-ruby">&gt; &gt; Benchmark.ips do |x|&gt; &gt; ?&gt; x.report(&quot;rescue&quot;) {&gt; &gt; ?&gt; Integer('foo') rescue nil&gt; &gt; }&gt; &gt; x.report(&quot;kwarg&quot;) {&gt; &gt; ?&gt; Integer('foo', exception: false)&gt; &gt; }&gt; &gt; x.compare!&gt; &gt; end&gt; &gt; Warming up --------------------------------------              rescue    41.896k i/100ms               kwarg    81.459k i/100msCalculating -------------------------------------rescue 488.006k ( 4.5%) i/s - 2.472M in 5.076848skwarg 1.024M (11.8%) i/s - 5.050M in 5.024937sComparison:kwarg: 1023555.3 i/srescue: 488006.0 i/s - 2.10x slower</code></pre><p>As we can see, rescuing the exception is twice slower than using the new keywordargument. We can still use the older technique if we want to return a differentvalue from <code>nil</code>.</p><pre><code class="language-ruby">&gt; &gt; Integer('foo') rescue 42&gt; &gt; =&gt; 42&gt; &gt;</code></pre><p>By default, the keyword argument <code>exception</code> is set to <code>true</code> for backwardcompatibility.</p><p>The Chinese version of this blog is available<a href="http://madao.me/yi-ruby-2-6-zeng-jia-liao-integer-he-float-fang-fa-de-yi-chang-can-shu/">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds Binding#source_location]]></title>
       <author><name>Taha Husain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-adds-binding-source-location"/>
      <updated>2018-07-24T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-adds-binding-source-location</id>
      <content type="html"><![CDATA[<p>Before Ruby 2.6, if we want to know file name with location and line number ofsource code, we would need to use Binding#eval (Link is not available) .</p><pre><code class="language-ruby">binding.eval('[__FILE__, __LINE__]')=&gt; [&quot;/Users/taha/blog/app/controllers/application_controller&quot;, 2]</code></pre><p>Ruby 2.6 adds more readable method Binding#source_location (Link is notavailable) to achieve similar result.</p><pre><code class="language-ruby">binding.source_location=&gt; [&quot;/Users/taha/blog/app/controllers/application_controller&quot;, 2]</code></pre><p>Here is relevant <a href="https://github.com/ruby/ruby/commit/571e48">commit</a> and<a href="https://bugs.ruby-lang.org/issues/14230">discussion</a> for this change.</p><p>The Chinese version of this blog is available<a href="http://madao.me/yi-ruby-2-6-binding-dui-xiang-zeng-jia-source_location-fang-fa/">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds String#split with block]]></title>
       <author><name>Taha Husain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-adds-split-with-block"/>
      <updated>2018-07-17T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-adds-split-with-block</id>
      <content type="html"><![CDATA[<p>Before Ruby 2.6,<a href="http://ruby-doc.org/core-2.5.1/String.html#method-i-split">String#split</a>returned array of split strings.</p><p>In Ruby 2.6, a block can be passed to String#split (Link is not available) whichyields each split string and operates on it. This avoids creating an array andthus is memory efficient.</p><p>We will add method <code>is_fruit?</code> to understand how to use <code>split</code> with a block.</p><pre><code class="language-ruby">def is_fruit?(value)%w(apple mango banana watermelon grapes guava lychee).include?(value)end</code></pre><p>Input is a comma separated string with vegetables and fruits names. Goal is tofetch names of fruits from input string and store it in an array.</p><h5>String#split</h5><pre><code class="language-ruby">input_str = &quot;apple, mango, potato, banana, cabbage, watermelon, grapes&quot;splitted_values = input_str.split(&quot;, &quot;)=&gt; [&quot;apple&quot;, &quot;mango&quot;, &quot;potato&quot;, &quot;banana&quot;, &quot;cabbage&quot;, &quot;watermelon&quot;, &quot;grapes&quot;]fruits = splitted_values.select { |value| is_fruit?(value) }=&gt; [&quot;apple&quot;, &quot;mango&quot;, &quot;banana&quot;, &quot;watermelon&quot;, &quot;grapes&quot;]</code></pre><p>Using <code>split</code> an intermediate array is created which contains both fruits andvegetables names.</p><h5>String#split with a block</h5><pre><code class="language-ruby">fruits = []input_str = &quot;apple, mango, potato, banana, cabbage, watermelon, grapes&quot;input_str.split(&quot;, &quot;) { |value| fruits &lt;&lt; value if is_fruit?(value) }=&gt; &quot;apple, mango, potato, banana, cabbage, watermelon, grapes&quot;fruits=&gt; [&quot;apple&quot;, &quot;mango&quot;, &quot;banana&quot;, &quot;watermelon&quot;, &quot;grapes&quot;]</code></pre><p>When a block is passed to <code>split</code>, it returns the string on which split wascalled and does not create an array. <code>String#split</code> yields block on each splitstring, which in our case was to push fruit names in a separate array.</p><h4>Update</h4><h5>Benchmark</h5><p>We created a large random string to benchmark performance of <code>split</code> and<code>split with block</code></p><pre><code class="language-ruby">require 'securerandom'test_string = ''100_000.times.each dotest_string += SecureRandom.alphanumeric(10)test_string += ' 'end</code></pre><pre><code class="language-ruby">require 'benchmark'Benchmark.bmbm do |bench|bench.report('split') doarr = test_string.split(' ')str_starts_with_a = arr.select { |str| str.start_with?('a') }endbench.report('split with block') dostr_starts_with_a = []test_string.split(' ') { |str| str_starts_with_a &lt;&lt; str if str.start_with?('a') }endend</code></pre><p>Results</p><pre><code class="language-plaintext">Rehearsal ----------------------------------------------------split              0.023764   0.000911   0.024675 (  0.024686)split with block   0.012892   0.000553   0.013445 (  0.013486)------------------------------------------- total: 0.038120sec                       user     system      total        realsplit              0.024107   0.000487   0.024594 (  0.024622)split with block   0.010613   0.000334   0.010947 (  0.010991)</code></pre><p>We did another iteration of benchmarking using<a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a>.</p><pre><code class="language-ruby">require 'benchmark/ips'Benchmark.ips do |bench|bench.report('split') dosplitted_arr = test_string.split(' ')str_starts_with_a = splitted_arr.select { |str| str.start_with?('a') }endbench.report('split with block') dostr_starts_with_a = []test_string.split(' ') { |str| str_starts_with_a &lt;&lt; str if str.start_with?('a') }endbench.compare!end</code></pre><p>Results</p><pre><code class="language-plaintext">Warming up --------------------------------------               split     4.000  i/100ms    split with block    10.000  i/100msCalculating -------------------------------------               split     46.906  ( 2.1%) i/s -    236.000  in   5.033343s    split with block    107.301  ( 1.9%) i/s -    540.000  in   5.033614sComparison:    split with block:      107.3 i/s               split:       46.9 i/s - 2.29x  slower</code></pre><p>This benchmark shows that <code>split with block</code> is about 2 times faster than<code>split</code>.</p><p>Here is relevant<a href="https://github.com/ruby/ruby/commit/2258a97fe2b21da9ec294ccedd00b3bbbc85cb07">commit</a>and <a href="https://bugs.ruby-lang.org/issues/4780">discussion</a> for this change.</p><p>The Chinese version of this blog is available<a href="http://madao.me/yi-ruby-2-6-stringde-split-fang-fa-zhi-chi-dai-ma-kuai-zhi-xing/">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 raises exception for else without rescue]]></title>
       <author><name>Rohan Pujari</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2.6-raise-exception-for-else-without-rescue"/>
      <updated>2018-07-10T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2.6-raise-exception-for-else-without-rescue</id>
      <content type="html"><![CDATA[<h4>Ruby 2.5</h4><p>If we use <code>else</code> without <code>rescue</code> inside <code>begin..end</code> block in Ruby 2.5, itgives a warning.</p><pre><code class="language-ruby">irb(main):001:0&gt; beginirb(main):002:1&gt; puts &quot;Inside begin block&quot;irb(main):003:1&gt; elseirb(main):004:1&gt; puts &quot;Inside else block&quot;irb(main):005:1&gt; end(irb):5: warning: else without rescue is useless</code></pre><p>This warning is present as code inside <code>else</code> block will never get executed</p><h4>Ruby 2.6</h4><p>In Ruby 2.6 it will raise an exception if we use <code>else</code> without <code>rescue</code> in<code>begin..end</code> block. This<a href="https://github.com/ruby/ruby/commit/140512d2225e6fd046ba1bdbcd1a27450f55c233#diff-ff4e2dc4962dc25a1512353299992c8d">commit</a>changed warning into exception in Ruby 2.6. Changes made in the commit areexperimental.</p><pre><code class="language-ruby">irb(main):001:0&gt; beginirb(main):002:1&gt; puts &quot;Inside begin block&quot;irb(main):003:1&gt; elseirb(main):004:1&gt; puts &quot;Inside else block&quot;irb(main):005:1&gt; endTraceback (most recent call last):1: from /usr/local/bin/irb:11:in `&lt;main&gt;'SyntaxError ((irb):3: else without rescue is useless)</code></pre><p>The Chinese version of this blog is available<a href="http://madao.me/yi-ruby-2-6-hui-zai-begin-end-dai-ma-kuai-zhong-yin-wei-bu-xie-rescue-zhi-xie-else-er-pao-chu-yi-chang-shi-yan-xing-feature">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 adds endless range]]></title>
       <author><name>Taha Husain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-adds-endless-range"/>
      <updated>2018-07-04T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-adds-endless-range</id>
      <content type="html"><![CDATA[<p>Before Ruby 2.6, if we want endless loop with index, we would need to use<a href="http://ruby-doc.org/core-2.5.1/Float.html#INFINITY">Float::INFINITY</a> with<a href="http://ruby-doc.org/core-2.5.1/Integer.html#method-i-upto">up to</a> or<a href="http://ruby-doc.org/core-2.5.1/Range.html">Range</a>, or use<a href="http://ruby-doc.org/core-2.5.1/Numeric.html#method-i-step">Numeric#step</a>.</p><h5>Ruby 2.5.0</h5><pre><code class="language-ruby">irb&gt; (1..Float::INFINITY).each do |n|irb\* # logic goes hereirb&gt; end</code></pre><p>OR</p><pre><code class="language-ruby">irb&gt; 1.step.each do |n|irb\* # logic goes hereirb&gt; end</code></pre><h4>Ruby 2.6.0</h4><p>Ruby 2.6 makes infinite loop more readable by changing mandatory second argumentin range to optional. Internally, Ruby changes second argument to <code>nil</code> ifsecond argument is not provided. So, both <code>(0..)</code> and <code>(0..nil)</code> are same inRuby 2.6.</p><h6>Using endless loop in Ruby 2.6</h6><pre><code class="language-ruby">irb&gt; (0..).each do |n|irb\* # logic goes hereirb&gt; end</code></pre><pre><code class="language-ruby">irb&gt; (0..nil).size=&gt; Infinityirb&gt; (0..).size=&gt; Infinity</code></pre><p>In Ruby 2.5, <code>nil</code> is not an acceptable argument and <code>(0..nil)</code> would throw<code>ArgumentError</code>.</p><pre><code class="language-ruby">irb&gt; (0..nil)ArgumentError (bad value for range)</code></pre><p>Here is the relevant<a href="https://github.com/ruby/ruby/commit/7f95eed19e22cb9a4867819355fe4ab99f85fd16">commit</a>and <a href="https://bugs.ruby-lang.org/issues/12912">discussion</a> for this change.</p><p>The Chinese version of this blog is available<a href="http://madao.me/yi-ruby-2-6-zeng-jia-wu-qiong-fan-wei/">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Using Concurrent Ruby in a Ruby on Rails Application]]></title>
       <author><name>Midhun Krishna</name></author>
      <link href="https://www.bigbinary.com/blog/using-concurrent-ruby-in-a-ruby-on-rails-application"/>
      <updated>2018-06-05T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/using-concurrent-ruby-in-a-ruby-on-rails-application</id>
      <content type="html"><![CDATA[<p><a href="https://github.com/ruby-concurrency/concurrent-ruby">Concurrent Ruby</a> is aconcurrency toolkit that builds on a lot of interesting ideas from manyfunctional languages and classic concurrency patterns. When it comes to writingthreaded code in Rails applications, look no further since concurrent ruby is<a href="https://github.com/rails/rails/blob/565ce0eaba233fcdd196c11715a8740bd571fd31/activesupport/activesupport.gemspec#L33">already included in Rails</a>via Active Support.</p><h3>Using Concurrent::Future</h3><p>In one of our applications, to improve performance we added threaded code using<a href="https://github.com/ruby-concurrency/concurrent-ruby">Concurrent::Future</a>. Itworked really well for us until one day it stopped working.</p><p>&quot;Why threads?&quot; one might ask. The code in question was a textbook threading usecase. It had a few API calls, some DB requests and finally an action that wasperformed on all the data that was aggregated.</p><p>Let us look at what this code looks like.</p><h4>Non threaded code</h4><pre><code class="language-ruby">selected_shipping_companies.each do | carrier |  # api calls  distance_in_miles = find_distance_from_origin_to_destination  historical_average_rate = historical_average_for_this_particular_carrier  # action performed  build_price_details_for_this_carrier(distance_in_miles,                                       historical_average_rate)end</code></pre><p>Converting the above code to use Concurrent::Future is trivial.</p><pre><code class="language-ruby">futures = selected_shipping_companies.map do |carrier|  Concurrent::Future.execute do    # api calls    distance_in_miles = find_distance_from_origin_to_destination    historical_average_rate = historical_average_for_this_particular_carrier    # action performed    build_price_details_for_this_carrier(distance_in_miles,                                         historical_average_rate)  endendfutures.map(&amp;:value)</code></pre><h3>A bit more about Concurrent::Future</h3><p>It is often intimidating to work with threads. They can bring in complexity andcan have unpredictable behaviors due to lack of thread-safety. Ruby, being alanguage of mutable references, we often find it difficult to write 100%thread-safe code.</p><p>Inspired by<a href="https://clojuredocs.org/clojure.core/future">Clojure's Future function</a>,Concurrent::Future is a primitive that guarantees thread safety. It takes ablock of work and performs the work asynchronously using Concurrent Ruby'sglobal thread-pool. Once a block of work is scheduled, Concurrent Ruby gives usa handle to this future work, on which when #value (or #deref) is called block'svalue is returned.</p><h3>The Bug</h3><p>Usually, when an exception occurs in the main thread, the interpreter stops andgathers the exception data. In the case of Ruby Threads, any unhandledexceptions are reported only when<a href="https://ruby-doc.org/core-2.2.0/Thread.html#method-i-join">Thread#join</a> iscalled. Setting <code>Thread#abort_on_exception</code> to <code>true</code>, is an better alternativewhich will cause all threads to exit when an exception is raised in any runningthread. We<a href="https://blog.bigbinary.com/2018/04/18/ruby-2-5-enables-thread-report_on_exception-by-default.html">published a blog</a>recently which talks about this in great detail.</p><h4>Exception handling in Concurrent Ruby</h4><pre><code class="language-ruby">future = Concurrent::Future.execute {            raise StandardError.new(&quot;Boom!&quot;)          }sleep(0.1) # giving arbitrary time for future to executefuture.value     #=&gt; nil</code></pre><p>Where did the exception go? This code fails silently and swallows theexceptions. How can we find out if the code executed successfully?</p><pre><code class="language-ruby">future = Concurrent::Future.execute {              raise StandardError.new(&quot;Boom!&quot;)          }sleep(0.1) # giving arbitrary time for future to executefuture.value     #=&gt; nilfuture.rejected? #=&gt; truefuture.reason    #=&gt; &quot;#&lt;StandardError: Boom!&gt;&quot;</code></pre><h3>How we fixed our issue</h3><p>We found places in our application where Concurrent::Future was used in a waythat would swallow exceptions. It is also a possibility that people mightoverlook the explicit need to manually report exception. We addressed theseconcerns with the following wrapper class.</p><pre><code class="language-ruby">module ConcurrentExecutor  class Error &lt; StandardError    def initialize(exceptions)      @exceptions = exceptions      super    end    def message      @exceptions.map { | e | e.message }.join &quot;\n&quot;    end    def backtrace      traces = @exceptions.map { |e| e.backtrace }      [&quot;ConcurrentExecutor::Error START&quot;, traces, &quot;END&quot;].flatten    end  end  class Future    def initialize(pool: nil)      @pool = pool || Concurrent::FixedThreadPool.new(20)      @exceptions = Concurrent::Array.new    end    # Sample Usage    # executor = ConcurrentExecutor::Future.new(pool: pool)    # executor.execute(carriers) do | carrier |    #   ...    # end    #    # values = executor.resolve    def execute array, &amp;block      @futures = array.map do | element |        Concurrent::Future.execute({ executor: @pool }) do          yield(element)        end.rescue do | exception |          @exceptions &lt;&lt; exception        end      end      self    end    def resolve      values = @futures.map(&amp;:value)      if @exceptions.length &gt; 0        raise ConcurrentExecutor::Error.new(@exceptions)      end      values    end  endend</code></pre><p>Please note that using Concurrent Ruby Futures caused segmentation fault whilerunning specs in Circle CI. As of this writing, we are using normal loopinginstead of Futures in Circle CI until the reason for the segfault is isolatedand fixed.</p><h3>Update</h3><p>Concurrent::Future also gives us another API which not only returns the value ofthe block but also posts/raises any exceptions that occur into the main thread.</p><pre><code class="language-ruby">thread_pool = Concurrent::FixedThreadPool.new(20)executors = [1, 2, 3, 4].map do |random_number|  Concurrent::Future.execute({ executor: thread_pool }) do    random_number / (random_number.even? ? 0 : 1)  endendexecutors.map(&amp;:value)=&gt; [1, nil, 3, nil]executors.map(&amp;:value!)&gt; ZeroDivisionError: divided by 0&gt; from (pry):4:in `/'</code></pre><p>We thank <a href="https://github.com/jrochkind">Jonathan Rochkind</a> for pointing us tothis undocumented api<a href="https://www.reddit.com/r/ruby/comments/8pedmm/using_concurrent_ruby_in_a_ruby_on_rails/">in his reddit post</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[RubyKaigi 2018 Day two]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/rubykaigi-2018-day-two"/>
      <updated>2018-06-01T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/rubykaigi-2018-day-two</id>
      <content type="html"><![CDATA[<p><a href="http://rubykaigi.org/2018">RubyKaigi</a> is happening at Sendai, Japan from 31stMay to 2nd June. It is perhaps the only conference where one can find almost allthe core Ruby team members in attendance.</p><p>This is <a href="https://twitter.com/_cha1tanya">Prathamesh</a>. I bring you live detailsabout what is happening at the Kaigi over the next two days. If you are at theconference please come and say &quot;Hi&quot; to me.</p><p>Check out<a href="https://blog.bigbinary.com/2018/05/31/rubykaigi-2018-day-one.html">what happened on day 1</a>.</p><h3>Faster Apps, No Memory Thrash: Get Your Memory Config Right by Noah Gibbs</h3><p><a href="https://twitter.com/codefolio">Noah</a> gave an awesome talk on techniques tomanage the memory used by Ruby applications. One of the main point while dealingwith GC is to make it run less, which means don't create too many objects. Healso mentioned that if application permits then destructive operations such as<code>gsub!</code> or <code>concat</code> should be used since they save CPU cycles and memory. Rubyallows setting up environment variables for managing the heap memory but it isreally hard to choose values for these environment variables blindly.</p><p>Noah has built a tool which uses <code>GC.stat</code> results from applications to estimatethe values of the memory related environment variables. Check out the<a href="https://github.com/noahgibbs/env_mem">EnvMem</a> gem.</p><p>In the end, he discussed some advanced debugging methods like checkingfragmentation percentage. The formula is prepared by<a href="https://twitter.com/nateberkopec/">Nate Berkopec</a>.</p><pre><code class="language-ruby">s = GC.statused_ratio = s[:heap_live_slots].to_f / (s[:heap_eden_pages] * 408)fragmentation = 1 - used_ratio</code></pre><p>We can also use <code>GC::Profiler</code> to profile the code in real time to see how GC isbehaving.</p><p>Benchmark used for this talk can be found<a href="https://github.com/noahgibbs/rails_ruby_bench">here</a>. Slides for this talk canbe found<a href="https://docs.google.com/presentation/d/1-WrYwz-QnSI9yeRZfCCgUno-KOMuggiGHlmOETXZy9c/edit?usp=sharing">here</a>.</p><h3>Guild prototype</h3><p>Next I attended talk by <a href="https://twitter.com/_ko1">Koichi Sasada</a> on Guildprototype. He discussed the proposed design spec for Guild with a demo ofFibonacci number program with 40 core CPU and 40 guilds. One of the interestingobservations is that performance drops as number of guilds increases because ofthe global locking.</p><p><img src="/blog_images/2018/rubykaigi-2018-day-two/guild.JPG" alt="Guild performance"></p><p>He discussed the concept of shareable and non-shareable objects. Shareableobjects can be shared across multiple Guilds whereas non-shareable objects canonly be used one Guild. This also means, you can't make thread unsafe programwith Guilds &quot;by design&quot;. He discussed about the challenges in specifying theshareable objects for Guilds.</p><p>Overall, there is still a lot of work left to be done for Guilds to become apart of Ruby. It includes defining protocols for shareable and non-shareableobjects, making sure GC runs properly in case of Guilds, synchronization betweendifferent Guilds.</p><p>The slides for this talk can be found<a href="http://www.atdot.net/~ko1/activities/2018_rubykaigi2018.pdf">here</a>.</p><h3>Ruby programming with type checking</h3><p><a href="https://twitter.com/soutaro">Soutaro</a> from SideCI gave a talk on<a href="https://github.com/soutaro/steep">Steep</a>, a gradual type checker for Ruby.</p><p>In the past, Matz has said that he doesn't like type definitions to be presentin the Ruby code. Steep requires type definitions to be present in separatefiles with extension <code>.rbi</code>. The Ruby source code needs little amount ofannotations. Steep also has a scaffold generator to generate the basic typedefinitions for existing code.</p><p><img src="/blog_images/2018/rubykaigi-2018-day-two/steep.JPG" alt="Steep v/s Sorbet"></p><p>As of now, Steep runs slower than <a href="https://sorbet.run">Sorbet</a> which wasdiscussed yesterday by Stripe team. Soutaro also discussed issues in typedefinitions due to meta programming in libraries such as Active Record. Thatlooks like a challenge for Steep as of now.</p><h3>Web console</h3><p>After the tea break, I attended talk by Genadi on how<a href="https://github.com/rails/web-console">web console</a> works.</p><p>He discussed the implementation of web-console in detail with references to Rubyinternals related to bindings. He compared the web-console interface with IRBand pry and explained the difference. As of now, web console has to monkey patchsome of the Rails internals. Genadi has added support for<a href="https://github.com/rails/rails/pull/23868">registering interceptors</a> which willprevent this monkey patching in Rails 6. He is also mentoring a Google summer ofcode student to work on Actionable errors project where the user can takeactions like running pending migrations via the webpage itself when the error isshown.</p><h3>Ruby committers v/s the World</h3><p><img src="/blog_images/2018/rubykaigi-2018-day-two/committers.JPG" alt="Ruby Committers v/s the World"></p><p>RubyKaigi offers this unique event where all the Ruby committers come on stageand face the questions from the audience. This year the format was slightlydifferent and it was run in the style of the Ruby core developer meeting. The<a href="https://docs.google.com/document/u/1/d/1Skh54Fq_nkpycZAS4_03tsafrtABDWxIx2-CKc-QIOY/pub">agenda</a>was predecided with some questions from the people and some tickets to discuss.The session started with discussion of<a href="https://www.ruby-lang.org/en/news/2018/05/31/ruby-2-6-0-preview2-released/">features coming up in Ruby 2.6</a>.</p><p>After that, the questions and the tickets in the agenda were discussed. It wasgood to see how the Ruby team takes decisions about features and suggestions.</p><p>Apart from this, there were<a href="http://rubykaigi.org/2018/schedule#jun01">talks on SciRuby, mRuby, linting, gem upgrades, c extensions and more</a>which I could not attend.</p><p>That's all for the day two. Looking forward to the day three already!</p><p>Oh and here is the world map of all the attendees from RubyKaigi.</p><p><img src="/blog_images/2018/rubykaigi-2018-day-two/world.JPG" alt="World map of all attendees"></p>]]></content>
    </entry><entry>
       <title><![CDATA[RubyKaigi 2018 Day one]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/rubykaigi-2018-day-one"/>
      <updated>2018-05-31T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/rubykaigi-2018-day-one</id>
      <content type="html"><![CDATA[<p><a href="http://rubykaigi.org/2018">RubyKaigi</a> is happening at Sendai, Japan from 31st May to2nd June. It is perhaps the only conference where one can find almost allthe core Ruby team members in attendance.</p><p>This is <a href="https://twitter.com/_cha1tanya">Prathamesh</a>.I bring you live details about what is happeningat the Kaigi over the next three days.If you are at the conference please come and say &quot;Hi&quot; to me.</p><h3>Matz's keynote</h3><p>RubyKaigi started with Matz's keynote. He used lot of proverbs applyingthem to the Ruby language and software development.</p><p>He talked about one of the hardest problems in programming - naming with an example of<code>yield_self</code>.Matz added alias <code>then</code> to the <code>yield_self</code> method <a href="https://github.com/ruby/ruby/commit/d53ee008911b5c3b22cff1566a9ef7e7d4cbe183">yesterday</a>. He also discussed about <code>googlability</code> of the names.Ironically, Ruby was named in 1993 which was before Google had started.</p><p>Matz also touched upon<a href="https://www.ruby-lang.org/en/news/2018/02/24/ruby-2-6-0-preview1-released/">JIT option being introduced in Ruby 2.6</a>and guild as the ways the language continues to improve inperformance and concurrency.There is a talk on Guild by Koichi Sasada on second day of RubyKaigi whichwill have further details about it.</p><p>Matz ended the keynote talking about the need of maintaining backward compatibilityand not running into the situation like Ruby 1.9 or Python 3 where the compatibility was notmaintained. He also stressed upon the community aspect of the Ruby language and its importancein the success of Ruby.</p><h3>ETL processing in Ruby using Kiba</h3><p><a href="https://twitter.com/thibaut_barrere">Thibaut Barrre</a>gave a talk on<a href="https://www.kiba-etl.org">Kiba</a> - a data processing ETL framework for Ruby.He discussed aboutthe design decisions that went into the version 1 and how it evolved to version 2 which was recently released.</p><p>Kiba provides programmatic API which can be used in the background jobs instead of shelling out. It alsohas support for multistep batch processing.</p><p>Thibaut also explained how it can be used for data migration,reusing the components and big rewrites. He observed that the performance has been gradually increasing with each Ruby release over the years.</p><p>The slides for this talk can be found <a href="https://speakerdeck.com/thbar/kiba-etl-v2-rubykaigi-2018">here</a>.</p><h3>Architecture of Hanami applications</h3><p>Next I attended talk from<a href="https://twitter.com/anton_davydov">Anton Davydov</a>on architecture patterns in Hanami apps.He discussed about the problems typical Rails applications faceandhow abstractions can address those issues.He explained how Hanami tries to achieve business logic isolation, avoid global state, sequential logic and test coverage.Functional callable objects, containers, dry-containers, dry-inject and event sourcing are some of the abstractions that can be used in Hanami apps that help inachieving this.</p><h3>Lightning talks</h3><p>The last session of the day was lightning talks.</p><p>The talk on<a href="https://github.com/godfat/rib">Rib</a>(wordplay on IRB) was an interesting one. Rib is yet another interactive Ruby shell but lightweight compared to IRB and pry. It has some nice features like auto indent, multiline history, filtering of callers. It can also <code>beep</code> when the console starts, so you know it is time to get back to work.</p><p>I liked another talk where<a href="https://github.com/Watson1978">Watson</a>had worked on improving the performance of JSON gem.He achieved this by using CRuby API wherever applicable and avoiding heavy calls like <code>rbfuncall</code>.Check these two<a href="https://github.com/flori/json/pull/346/">pull</a><a href="https://github.com/flori/json/pull/345">requests</a> for benchmark and more discussions.</p><p>Apart from these talks,there were lot of other talks as well which I could not attend.<a href="http://rubykaigi.org/2018/presentations/DarkDimius.html#may31">Stripe team</a>is building a<a href="https://sorbet.run">type checker for Ruby</a>which looks very interesting and is extremely fast.</p><p><a href="http://rubykaigi.org/2018/presentations/bbatsov.html#may31">Bozhidar Batsov</a>gave a talk on Rubocop project andhow it has evolved over the years.There was also a talk on Karafka - event driven architecture in Ruby.This talk was a good precursor to the Hanami talk where event driven architecture was mentioned again.</p><p><a href="http://rubykaigi.org/2018/schedule#may31">Other talks from day one</a>ranged from memory management, playing with Ruby syntax, code highlighter, deep learning, C extensions to Rubygems.</p><p>That's all for the day one. Looking forward to the day two already!</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 added lazy proc allocation for block parameters]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-added-lazy-proc-allocation-for-block-parameters"/>
      <updated>2018-05-22T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-added-lazy-proc-allocation-for-block-parameters</id>
      <content type="html"><![CDATA[<pre><code class="language-ruby">irb&gt; def greetirb&gt;   yieldirb&gt; end  =&gt; :greetirb&gt;irb&gt; def greet_with_welcome(&amp;block)irb&gt;   puts 'Welcome'irb&gt;   greet(&amp;block)irb&gt; end  =&gt; :greet_with_welcomeirb&gt; greet_with_welcome { p 'BigBinary' }Welcome&quot;BigBinary&quot;  =&gt; &quot;BigBinary&quot;</code></pre><p>In Ruby 2.4 when we pass a block to a method, which further passes to anothermethod, Ruby creates a new <code>Proc</code> object by the given block before passing thisproc to the another method.</p><p>This creates unnecessary objects even when the block parameter is not accessed.It also creates a chain of <code>Proc</code> objects when the block parameter is passedthrough various methods.</p><p>Proc creation is one a heavyweight operation because we need to store all localvariables (represented by Env objects in MRI internal) in the heap.</p><p>Ruby 2.5 introduced a lazy proc allocation. Ruby 2.5 will not create a Procobject when passing a block to another method. Instead, it will pass the blockinformation. If the block is accessed somewhere else, then it creates a <code>Proc</code>object by the given block.</p><p>This results in lesser memory allocation and faster execution.</p><h4>Ruby 2.4</h4><pre><code class="language-ruby">irb&gt; require 'benchmark'  =&gt; trueirb&gt; def greetirb&gt;   yieldirb&gt; end  =&gt; :greetirb&gt;irb&gt; def greet_with_welcome(&amp;block)irb&gt;   puts 'Welcome'irb&gt;   greet(&amp;block)irb&gt; end  =&gt; :greet_with_welcomeirb&gt;irb&gt; Benchmark.measure { 1000.times { greet_with_welcome { 'BigBinary' } } }WelcomeWelcome.........  =&gt; #&lt;Benchmark::Tms:0x007fe6ab929de0 @label=&quot;&quot;, @real=0.022295999999187188, @cstime=0.0, @cutime=0.0, @stime=0.01, @utime=0.0, @total=0.01&gt;</code></pre><h4>Ruby 2.5</h4><pre><code class="language-ruby">irb&gt; require 'benchmark'  =&gt; trueirb&gt; def greetirb&gt;   yieldirb&gt; end  =&gt; :greetirb&gt;irb&gt; def greet_with_welcome(&amp;block)irb&gt;   puts 'Welcome'irb&gt;   greet(&amp;block)irb&gt; end  =&gt; :greet_with_welcomeirb&gt;  irb&gt; Benchmark.measure { 1000.times { greet_with_welcome { 'BigBinary' } } }WelcomeWelcome.........  =&gt; #&lt;Benchmark::Tms:0x00007fa4400871b8 @label=&quot;&quot;, @real=0.004612999997334555, @cstime=0.0, @cutime=0.0, @stime=0.001524000000000001, @utime=0.0030690000000000023, @total=0.004593000000000003&gt;</code></pre><p>As we can see, there is considerable improvement in execution time when a blockparam is passed in Ruby 2.5.</p><p>Here is the relevant <a href="https://github.com/ruby/ruby/commit/5ee9513a71">commit</a>and <a href="https://bugs.ruby-lang.org/issues/14045">discussion</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Increase reliability using super_fetch of Sidekiq Pro]]></title>
       <author><name>Vishal Telangre</name></author>
      <link href="https://www.bigbinary.com/blog/increase-reliability-of-background-job-processing-using-super_fetch-of-sidekiq-pro"/>
      <updated>2018-05-08T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/increase-reliability-of-background-job-processing-using-super_fetch-of-sidekiq-pro</id>
      <content type="html"><![CDATA[<p><a href="https://github.com/mperham/sidekiq">Sidekiq</a>is a background job processing library for Ruby.Sidekiq offers three versions: OSS, Pro and Enterprise.</p><p>OSS is free and open source and has basic features.Pro and Enterprise versions are closed source and paid,thus comes with more advanced features.To compare the list of features offered by each of these versions,please visit <a href="https://sidekiq.org">Sidekiq website</a>.</p><p>Sidekiq Pro 3.4.0<a href="https://github.com/mperham/sidekiq/blob/6e79f2a860ae558f2ed52b8917d2fede846c0a50/Pro-Changes.md#340">introduced</a><code>super_fetch</code> strategyto reliably fetch jobs from the queue in Redis.</p><p>In this post, we will discuss the benefits of using <code>super_fetch</code> strategy.</p><h2>Problem</h2><p>Open source version of Sidekiq comes with <code>basic_fetch</code> strategy.Let's see an example to understand how it works.</p><p>Let's add Sidekiq to our <code>Gemfile</code> and run <code>bundle install</code> to install it.</p><pre><code class="language-ruby">gem 'sidekiq'</code></pre><p>Add following Sidekiq worker in <code>app/workers/sleep_worker.rb</code>.</p><pre><code class="language-ruby">class SleepWorker  include Sidekiq::Worker  def perform(name)    puts &quot;Started #{name}&quot;    sleep 30    puts &quot;Finished #{name}&quot;  endend</code></pre><p>This worker does nothing great but sleeps for 30 seconds.</p><p>Let's open Rails consoleand schedule this worker to run as a background job asynchronously.</p><pre><code class="language-ruby">&gt;&gt; require &quot;sidekiq/api&quot;=&gt; true&gt;&gt; Sidekiq::Queue.new.size=&gt; 0&gt;&gt; SleepWorker.perform_async(&quot;A&quot;)=&gt; &quot;5d8bf898c36a60a1096cf4d3&quot;&gt;&gt; Sidekiq::Queue.new.size=&gt; 1</code></pre><p>As we can see, queue now has 1 job scheduled to be processed.</p><p>Let's start Sidekiq in another terminal tab.</p><pre><code class="language-ruby">$ bundle exec sidekiq40510 TID-owu1swr1i INFO: Booting Sidekiq 5.1.3 with redis options {:id=&gt;&quot;Sidekiq-server-PID-40510&quot;, :url=&gt;nil}40510 TID-owu1swr1i INFO: Starting processing, hit Ctrl-C to stop40510 TID-owu1tr5my SleepWorker JID-5d8bf898c36a60a1096cf4d3 INFO: startStarted A</code></pre><p>As we can see, the job with ID <code>5d8bf898c36a60a1096cf4d3</code>was picked up by Sidekiqand it started processing the job.</p><p>If we check the Sidekiq queue size in the Rails console, it will be zero now.</p><pre><code class="language-ruby">&gt;&gt; Sidekiq::Queue.new.size=&gt; 0</code></pre><p>Let's shutdown the Sidekiq process gracefullywhile Sidekiq is still in the middle of processing our scheduled job.Press either <code>Ctrl-C</code> or run <code>kill -SIGINT &lt;PID&gt;</code> command.</p><pre><code class="language-ruby">$ kill -SIGINT 40510</code></pre><pre><code class="language-ruby">40510 TID-owu1swr1i INFO: Shutting down40510 TID-owu1swr1i INFO: Terminating quiet workers40510 TID-owu1x00rm INFO: Scheduler exiting...40510 TID-owu1swr1i INFO: Pausing to allow workers to finish...40510 TID-owu1swr1i WARN: Terminating 1 busy worker threads40510 TID-owu1swr1i WARN: Work still in progress [#&lt;struct Sidekiq::BasicFetch::UnitOfWork queue=&quot;queue:default&quot;, job=&quot;{\&quot;class\&quot;:\&quot;SleepWorker\&quot;,\&quot;args\&quot;:[\&quot;A\&quot;],\&quot;retry\&quot;:true,\&quot;queue\&quot;:\&quot;default\&quot;,\&quot;jid\&quot;:\&quot;5d8bf898c36a60a1096cf4d3\&quot;,\&quot;created_at\&quot;:1525427293.956314,\&quot;enqueued_at\&quot;:1525427293.957355}&quot;&gt;]40510 TID-owu1swr1i INFO: Pushed 1 jobs back to Redis40510 TID-owu1tr5my SleepWorker JID-5d8bf898c36a60a1096cf4d3 INFO: fail: 19.576 sec40510 TID-owu1swr1i INFO: Bye!</code></pre><p>As we can see, Sidekiq pushed back the unfinished job back to Redis queuewhen Sidekiq received a <code>SIGINT</code> signal.</p><p>Let's verify it.</p><pre><code class="language-ruby">&gt;&gt; Sidekiq::Queue.new.size=&gt; 1</code></pre><p>Before we move on, let's learn some basics about signals such as <code>SIGINT</code>.</p><h2>A crash course on POSIX signals</h2><p><code>SIGINT</code> is an interrupt signal.It is an alternative to hitting<code>Ctrl-C</code> from the keyboard.When a process is running in foreground,we can hit <code>Ctrl-C</code> to signal the process to shut down.When the process is running in background,we can use <code>kill</code> command to send a <code>SIGINT</code> signal to the process' PID.A process can optionally catch this signal and shutdown itself gracefully.If the process does not respect this signal and ignores it,then nothing really happens and the process keeps running.Both <code>INT</code> and <code>SIGINT</code> are identical signals.</p><p>Another useful signal is <code>SIGTERM</code>.It is called a termination signal.A process can either catch itand perform necessary cleanup or just ignore it.Similar to a <code>SIGINT</code> signal,if a process ignores this signal, then the process keeps running.Note that, if no signal is supplied to the <code>kill</code> command,<code>SIGTERM</code> is used by default.Both <code>TERM</code> and <code>SIGTERM</code> are identical signals.</p><p><code>SIGTSTP</code> or <code>TSTP</code> is called terminal stop signal.It is an alternative to hitting <code>Ctrl-Z</code> on the keyboard.This signal causes a process to suspend further execution.</p><p><code>SIGKILL</code> is known as kill signal.This signal is intended to kill the process immediately and forcefully.A process cannot catch this signal,therefore the process cannot perform cleanup or graceful shutdown.This signal is usedwhen a process does not respect and respondto both <code>SIGINT</code> and <code>SIGTERM</code> signals.<code>KILL</code>, <code>SIGKILL</code> and <code>9</code> are identical signals.</p><p>There are a lot of other signals besides these,but they are not relevant for this post.Please check them out <a href="https://en.wikipedia.org/wiki/Signal_(IPC)#POSIX_signals">here</a>.</p><p>A Sidekiq process pays respectto all of these signals and behaves as we expect.When Sidekiq receives a <code>TERM</code> or <code>SIGTERM</code> signal,Sidekiq terminates itself gracefully.</p><h2>Back to our example</h2><p>Coming back to our example from above,we had sent a <code>SIGINT</code> signal to the Sidekiq process.</p><pre><code class="language-ruby">$ kill -SIGINT 40510</code></pre><p>On receiving this <code>SIGINT</code> signal,Sidekiq process having PID 40510 terminated quiet workers,paused the queue and waited for a whileto let busy workers finish their jobs.Since our busy SleepWorker did not finish quickly,Sidekiq terminated that busy workerand pushed it back to the queue in Redis.After that, Sidekiq gracefully terminated itself with an exit code 0.Note that, the default timeout is 8 secondsuntil which Sidekiq can wait to let the busy workers finishotherwise it pushes the unfinished jobs back to the queue in Redis.This timeout can be changed with <code>-t</code> optiongiven at the startup of Sidekiq process.</p><p>Sidekiq <a href="https://github.com/mperham/sidekiq/wiki/Deployment#overview">recommends</a>to send a <code>TSTP</code> and a <code>TERM</code> togetherto ensure that the Sidekiq process shuts down safely and gracefully.On receiving a <code>TSTP</code> signal,Sidekiq stops pulling new workandfinishes the work which is in-progress.The idea is to first send a <code>TSTP</code> signal,wait as much as possible (by default for 8 seconds as discussed above)to ensure that busy workers finish their jobsand then send a <code>TERM</code> signalto shutdown the process.</p><p>Sidekiq pushes back the unprocessed job in Redis when terminated gracefully.It means that Sidekiq pulls the unfinished job and starts processing again whenwe restart the Sidekiq process.</p><pre><code class="language-ruby">$ bundle exec sidekiq45916 TID-ovfq8ll0k INFO: Booting Sidekiq 5.1.3 with redis options {:id=&gt;&quot;Sidekiq-server-PID-45916&quot;, :url=&gt;nil}45916 TID-ovfq8ll0k INFO: Starting processing, hit Ctrl-C to stop45916 TID-ovfqajol4 SleepWorker JID-5d8bf898c36a60a1096cf4d3 INFO: startStarted AFinished A45916 TID-ovfqajol4 SleepWorker JID-5d8bf898c36a60a1096cf4d3 INFO: done: 30.015 sec</code></pre><p>We can see that Sidekiq pulled the previously terminated jobwith ID <code>5d8bf898c36a60a1096cf4d3</code> and processed that job again.</p><p>So far so good.</p><p>This behavior is implemented using<a href="https://github.com/mperham/sidekiq/blob/6e79f2a860ae558f2ed52b8917d2fede846c0a50/lib/sidekiq/fetch.rb"><code>basic_fetch</code></a>strategy which is present in the open sourced version of Sidekiq.</p><p>Sidekiq uses <a href="https://redis.io/commands/brpop">BRPOP</a> Redis commandto fetch a scheduled job from the queue.When a job is fetched,that job gets removed from the queue andthat job no longer exists in Redis.If this fetched job is processed, then all is good.Also, if the Sidekiq process is terminated gracefully onreceiving either a <code>SIGINT</code> or a <code>SIGTERM</code> signal,Sidekiq will push back the unfinished jobs back to the queue in Redis.</p><p>But what if the Sidekiq process crashes in the middlewhile processing that fetched job?</p><p>A process is considered as crashedif the process does not shutdown gracefully.As we discussed before,when we send a <code>SIGKILL</code> signal to a process,the process cannot receive or catch this signal.Because the process cannot shutdown gracefully and nicely,it gets crashed.</p><p>When a Sidekiq process is crashed,the fetched jobs by that Sidekiq processwhich are not yet finished get lostforever.</p><p>Let's try to reproduce this scenario.</p><p>We will schedule another job.</p><pre><code class="language-ruby">&gt;&gt; SleepWorker.perform_async(&quot;B&quot;)=&gt; &quot;37a5ab4139796c4b9dc1ea6d&quot;&gt;&gt; Sidekiq::Queue.new.size=&gt; 1</code></pre><p>Now, let's start Sidekiq process and kill it using <code>SIGKILL</code> or <code>9</code> signal.</p><pre><code class="language-ruby">$ bundle exec sidekiq47395 TID-ow8q4nxzf INFO: Starting processing, hit Ctrl-C to stop47395 TID-ow8qba0x7 SleepWorker JID-37a5ab4139796c4b9dc1ea6d INFO: startStarted B[1]    47395 killed     bundle exec sidekiq</code></pre><pre><code class="language-ruby">$ kill -SIGKILL 47395</code></pre><p>Let's check if Sidekiq had pushed the busy (unprocessed) jobback to the queue in Redis before terminating.</p><pre><code class="language-ruby">&gt;&gt; Sidekiq::Queue.new.size=&gt; 0</code></pre><p>No. It does not.</p><p>Actually, the Sidekiq process did not get a chance to shutdown gracefullywhen it received the <code>SIGKILL</code> signal.</p><p>If we restart the Sidekiq process,it cannot fetch that unprocessed jobsince the job was not pushed back to the queue in Redis at all.</p><pre><code class="language-ruby">$ bundle exec sidekiq47733 TID-ox1lau26l INFO: Booting Sidekiq 5.1.3 with redis options {:id=&gt;&quot;Sidekiq-server-PID-47733&quot;, :url=&gt;nil}47733 TID-ox1lau26l INFO: Starting processing, hit Ctrl-C to stop</code></pre><p>Therefore,the job having name argument as <code>B</code> or ID as <code>37a5ab4139796c4b9dc1ea6d</code>is completely lost.There is no way to get that job back.</p><p>Losing job like this may not be a problem for some applicationsbut for some critical applications this could be a huge issue.</p><p>We faced a similar problem like this.One of our clients' application is deployed on a Kubernetes cluster.Our Sidekiq process runs in a Docker containerin the Kubernetes<a href="https://kubernetes.io/docs/concepts/workloads/pods/pod">pods</a>which we call <code>background</code> pods.</p><p>Here's our stripped down version of<a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">Kubernetes deployment</a>manifest which creates a Kubernetes deployment resource.Our Sidekiq process runs in the pods spawned by that deployment resource.</p><pre><code class="language-ruby">---apiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: backgroundspec:  replicas: 2  template:    spec:      terminationGracePeriodSeconds: 60      containers:      - name: background        image: &lt;%= ENV['IMAGE'] %&gt;        env:        - name: POD_TYPE          value: background        lifecycle:          preStop:            exec:              command:              - /bin/bash              - -l              - -c              - for pid in tmp/pids/sidekiq*.pid; do bin/bundle exec sidekiqctl stop $pid 60; done</code></pre><p>When we apply an updated version of this manifest,for say, changing the Docker image, the running pods are terminatedand new pods are created.</p><p>Before terminating the only container in the pod,Kubernetes executes <code>sidekiqctl stop $pid 60</code> commandwhich we have defined using the<a href="https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/">preStop</a>event handler.Note that, Kubernetes already sends <code>SIGTERM</code> signalto the container being terminated inside the podbefore invoking the <code>preStop</code> event handler.The default termination grace period is 30 seconds and it is configurable.If the container doesn't terminate within the termination grace period,a <code>SIGKILL</code> signal will be sent to forcefully terminate the container.</p><p>The <code>sidekiqctl stop $pid 60</code> command executed in the <code>preStop</code> handler doesthree things.</p><ol><li>Sends a <code>SIGTERM</code> signal to the Sidekiq process running in the container.</li><li>Waits for 60 seconds.</li><li>Sends a <code>SIGKILL</code> signal to kill the Sidekiq process forcefullyif the process has not terminated gracefully yet.</li></ol><p>This worked for us when the count of busy jobs was relatively small.</p><p>When the number of processing jobs is higher,Sidekiq does not get enough timeto quiet the busy workersand fails to push some of them back on the Redis queue.</p><p>We found that some of the jobs were getting lostwhen our <code>background</code> pod restarted.We had to restart our background pod forreasons such asupdating the Kubernetes deployment manifest,pod being automatically evicted by Kubernetesdue to host node encountering OOM (out of memory) issue, etc.</p><p>We tried increasing both<code>terminationGracePeriodSeconds</code> in the deployment manifestas well as the <code>sidekiqctl stop</code> command's timeout.Despite that,we still kept facing the same issueof losing jobs whenever pod restarts.</p><p>We even tried sending <code>TSTP</code> and then <code>TERM</code> after a timeoutrelatively longer than 60 seconds.But the pod was getting harshly terminatedwithout gracefully terminating Sidekiq process running inside it.Therefore we kept losing the busy jobswhich were running during the pod termination.</p><h2>Sidekiq Pro's super_fetch</h2><p>We were looking for a way to stop losing our Sidekiq jobsor a way to recover them reliably when our <code>background</code> Kubernetes pod restarts.</p><p>We realized that the commercial version of Sidekiq,Sidekiq Pro offers an additional fetch strategy,<a href="https://github.com/mperham/sidekiq/wiki/Reliability#using-super_fetch"><code>super_fetch</code></a>,which seemed more efficient and reliablecompared to <code>basic_fetch</code> strategy.</p><p>Let's see what difference <code>super_fetch</code> strategymakes over <code>basic_fetch</code>.</p><p>We will need to use <code>sidekiq-pro</code> gem which needs to be purchased.Since Sidekiq Pro gem is close sourced, we cannot fetch itfrom the default public gem registry,<a href="https://rubygems.org">https://rubygems.org</a>.Instead, we will have to fetch it from a private gem registrywhich we get after purchasing it.We add following code to our <code>Gemfile</code> and run <code>bundle install</code>.</p><pre><code class="language-ruby">source ENV['SIDEKIQ_PRO_GEM_URL'] do  gem 'sidekiq-pro'end</code></pre><p>To enable <code>super_fetch</code>,we need to add following codein an initializer <code>config/initializers/sidekiq.rb</code>.</p><pre><code class="language-ruby">Sidekiq.configure_server do |config|  config.super_fetch!end</code></pre><p>Well, that's it.Sidekiq will use <code>super_fetch</code> instead of <code>basic_fetch</code> now.</p><pre><code class="language-ruby">$ bundle exec sidekiq75595 TID-owsytgvqj INFO: Sidekiq Pro 4.0.2, commercially licensed.  Thanks for your support!75595 TID-owsytgvqj INFO: Booting Sidekiq 5.1.3 with redis options {:id=&gt;&quot;Sidekiq-server-PID-75595&quot;, :url=&gt;nil}75595 TID-owsytgvqj INFO: Starting processing, hit Ctrl-C to stop75595 TID-owsys5imz INFO: SuperFetch activated</code></pre><p>When <code>super_fetch</code> is activated, Sidekiq process' graceful shutdown behavioris similar to that of <code>basic_fetch</code>.</p><pre><code class="language-ruby">&gt;&gt; SleepWorker.perform_async(&quot;C&quot;)=&gt; &quot;f002a41393f9a79a4366d2b5&quot;&gt;&gt; Sidekiq::Queue.new.size=&gt; 1</code></pre><pre><code class="language-ruby">$ bundle exec sidekiq76021 TID-ow6kdcca5 INFO: Sidekiq Pro 4.0.2, commercially licensed.  Thanks for your support!76021 TID-ow6kdcca5 INFO: Booting Sidekiq 5.1.3 with redis options {:id=&gt;&quot;Sidekiq-server-PID-76021&quot;, :url=&gt;nil}76021 TID-ow6kdcca5 INFO: Starting processing, hit Ctrl-C to stop76021 TID-ow6klq2cx INFO: SuperFetch activated76021 TID-ow6kiesnp SleepWorker JID-f002a41393f9a79a4366d2b5 INFO: startStarted C</code></pre><pre><code class="language-ruby">&gt;&gt; Sidekiq::Queue.new.size=&gt; 0</code></pre><pre><code class="language-ruby">$ kill -SIGTERM 76021</code></pre><pre><code class="language-ruby">76021 TID-ow6kdcca5 INFO: Shutting down76021 TID-ow6kdcca5 INFO: Terminating quiet workers76021 TID-ow6kieuwh INFO: Scheduler exiting...76021 TID-ow6kdcca5 INFO: Pausing to allow workers to finish...76021 TID-ow6kdcca5 WARN: Terminating 1 busy worker threads76021 TID-ow6kdcca5 WARN: Work still in progress [#&lt;struct Sidekiq::Pro::SuperFetch::Retriever::UnitOfWork queue=&quot;queue:default&quot;, job=&quot;{\&quot;class\&quot;:\&quot;SleepWorker\&quot;,\&quot;args\&quot;:[\&quot;C\&quot;],\&quot;retry\&quot;:true,\&quot;queue\&quot;:\&quot;default\&quot;,\&quot;jid\&quot;:\&quot;f002a41393f9a79a4366d2b5\&quot;,\&quot;created_at\&quot;:1525500653.404454,\&quot;enqueued_at\&quot;:1525500653.404501}&quot;, local_queue=&quot;queue:sq|vishal.local:76021:3e64c4b08393|default&quot;&gt;]76021 TID-ow6kdcca5 INFO: SuperFetch: Moving job from queue:sq|vishal.local:76021:3e64c4b08393|default back to queue:default76021 TID-ow6kiesnp SleepWorker JID-f002a41393f9a79a4366d2b5 INFO: fail: 13.758 sec76021 TID-ow6kdcca5 INFO: Bye!</code></pre><pre><code class="language-ruby">&gt;&gt; Sidekiq::Queue.new.size=&gt; 1</code></pre><p>That looks good.As we can see, Sidekiq moved busy job back from a private queueto the queue in Rediswhen Sidekiq received a <code>SIGTERM</code> signal.</p><p>Now, let's try to kill Sidekiq process forcefullywithout allowing a graceful shutdownby sending a <code>SIGKILL</code> signal.</p><p>Since Sidekiq was gracefully shutdown before,if we restart Sidekiq again,it will re-process the pushed back job having ID <code>f002a41393f9a79a4366d2b5</code>.</p><pre><code class="language-ruby">$ bundle exec sidekiq76890 TID-oxecurbtu INFO: Sidekiq Pro 4.0.2, commercially licensed.  Thanks for your support!76890 TID-oxecurbtu INFO: Booting Sidekiq 5.1.3 with redis options {:id=&gt;&quot;Sidekiq-server-PID-76890&quot;, :url=&gt;nil}76890 TID-oxecurbtu INFO: Starting processing, hit Ctrl-C to stop76890 TID-oxecyhftq INFO: SuperFetch activated76890 TID-oxecyotvm SleepWorker JID-f002a41393f9a79a4366d2b5 INFO: startStarted C[1]    76890 killed     bundle exec sidekiq</code></pre><pre><code class="language-ruby">$ kill -SIGKILL 76890</code></pre><pre><code class="language-ruby">&gt;&gt; Sidekiq::Queue.new.size=&gt; 0</code></pre><p>It appears that Sidekiq didn't get any chanceto push the busy job back to the queue in Redison receiving a <code>SIGKILL</code> signal.</p><p>So, where is the magic of <code>super_fetch</code>?</p><p>Did we lose our job again?</p><p>Let's restart Sidekiq and see it ourself.</p><pre><code class="language-ruby">$ bundle exec sidekiq77496 TID-oum04ghgw INFO: Sidekiq Pro 4.0.2, commercially licensed.  Thanks for your support!77496 TID-oum04ghgw INFO: Booting Sidekiq 5.1.3 with redis options {:id=&gt;&quot;Sidekiq-server-PID-77496&quot;, :url=&gt;nil}77496 TID-oum04ghgw INFO: Starting processing, hit Ctrl-C to stop77496 TID-oum086w9s INFO: SuperFetch activated77496 TID-oum086w9s WARN: SuperFetch: recovered 1 jobs77496 TID-oum08eu3o SleepWorker JID-f002a41393f9a79a4366d2b5 INFO: startStarted CFinished C77496 TID-oum08eu3o SleepWorker JID-f002a41393f9a79a4366d2b5 INFO: done: 30.011 sec</code></pre><p>Whoa, isn't that cool?</p><p>See that line where it says <code>SuperFetch: recovered 1 jobs</code>.</p><p>Although the job wasn't pushed back to the queue in Redis,Sidekiq somehow recovered our lost job having ID <code>f002a41393f9a79a4366d2b5</code>and reprocessed that job again!</p><p>Interested to learn about how Sidekiq did that? Keep on reading.</p><p>Note that, since Sidekiq Pro is a close sourced and commercial software,we cannot explain <code>super_fetch</code>'s exact implementation details.</p><p>As we discussed in-depth before,Sidekiq's <code>basic_fetch</code> strategy uses <code>BRPOP</code> Redis commandto fetch a job from the queue in Redis.It works great to some extent,but it is prone to losing jobif Sidekiq crashes or does not shutdown gracefully.</p><p>On the other hand, Sidekiq Pro offers <code>super_fetch</code> strategy which uses<a href="http://redis.io/commands/rpoplpush">RPOPLPUSH</a> Redis command to fetch a job.</p><p><code>RPOPLPUSH</code> Redis command providesa unique approach towards implementing a reliable queue.<code>RPOPLPUSH</code> command accepts two listsnamely a source list and a destination list.This command atomicallyreturns and removes the last element from the source list,and pushes that element as the first element in the destination list.Atomically means that both pop and push operationsare performed as a single operation at the same time;i.e. both should succeed, otherwise both are treated as failed.</p><p><code>super_fetch</code> registers a private queue in Redisfor each Sidekiq process on start-up.<code>super_fetch</code> atomically fetches a scheduled jobfrom the public queue in Redisand pushes that job into the private queue (or working queue)using <code>RPOPLPUSH</code> Redis command.Once the job is finished processing,Sidekiq removes that job from the private queue.During a graceful shutdown,Sidekiq moves back the unfinished jobsfrom the private queue to the public queue.If shutdown of Sidekiq process is not graceful,the unfinished jobs of that Sidekiq processremain there in the private queue which are called as orphaned jobs.On restarting or starting another Sidekiq process,<code>super_fetch</code> looks for such orphaned jobs in the private queues.If Sidekiq finds orphaned jobs, Sidekiq re-enqueue them and processes again.</p><p>It may happen thatwe have multiple Sidekiq processes running at the same time.If a process dies among them, its unfinished jobs become orphans.<a href="https://github.com/mperham/sidekiq/wiki/Reliability#recovering-jobs">This Sidekiq wiki</a>describes in detail the criteria which <code>super_fetch</code> relies uponfor identifying which jobs are orphaned and which jobs are not orphaned.If we don't restart or start another process,<code>super_fetch</code> may take 5 minutes or 3 hours to recover such orphaned jobs.The recommended approach is to restart or start another Sidekiq processto signal <code>super_fetch</code> to look for orphans.</p><p>Interestingly, in the older versions of Sidekiq Pro,<code>super_fetch</code> performed checks for orphaned jobs and queues<a href="https://github.com/mperham/sidekiq/issues/3273">every 24 hours</a>at the Sidekiq process startup.Due to this, when the Sidekiq process crashes,the orphaned jobs of that process remain unpicked for up to 24 hoursuntil the next restart.This orphan delay check windowhad been later lowered to 1 hour in Sidekiq Pro 3.4.1.</p><p>Another fun thing to know is that,there existed two fetch strategies namely<a href="https://github.com/mperham/sidekiq/wiki/Reliability/_compare/71312b1f3880bcee9ff47f59c7516c15657553d8...15776fd781848a36a0ddb24c3f2315202696e30c"><code>reliable_fetch</code></a>and <code>timed_fetch</code>in the older versions of Sidekiq Pro.Apparently, <code>reliable_fetch</code><a href="https://github.com/mperham/sidekiq/wiki/Pro-Reliability-Server#reliable_fetch">did not work with Docker</a>and <code>timed_fetch</code> had asymptotic computational complexity <code>O(log N)</code>,comparatively<a href="https://github.com/mperham/sidekiq/wiki/Pro-Reliability-Server#timed_fetch">less efficient</a>than <code>super_fetch</code>,which has asymptotic computational complexity <code>O(1)</code>.Both of these strategies had been deprecatedin Sidekiq Pro 3.4.0 in favor of <code>super_fetch</code>.Later, both of these strategies had been<a href="https://github.com/mperham/sidekiq/blob/6e79f2a860ae558f2ed52b8917d2fede846c0a50/Pro-4.0-Upgrade.md#whats-new">removed</a>in Sidekiq Pro 4.0and <a href="https://github.com/mperham/sidekiq/wiki/Reliability#notes">are not documented anywhere</a>.</p><h2>Final result</h2><p>We have enabled <code>super_fetch</code> in our application andit seemed to be working without any major issues so far.Our Kubernetes <code>background</code> pods does not seem tobe loosing any jobs when these pods are restarted.</p><p>Update : Mike Pheram, author of Sidekiq, posted following<a href="https://www.reddit.com/r/ruby/comments/8htnpe/increase_reliability_of_background_job_processing">comment</a>.</p><blockquote><p>Faktory provides all of the beanstalkd functionality, including the same reliability, with a nicer Web UI. It's free and OSS.https://github.com/contribsys/faktory http://contribsys.com/faktory/</p></blockquote>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.6 added option to raise exception in Kernel#system]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-6-added-option-to-raise-exception-in-kernel-system"/>
      <updated>2018-04-25T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-6-added-option-to-raise-exception-in-kernel-system</id>
      <content type="html"><![CDATA[<p>We write scripts to automate setup and deployment of Rails applications. Inthose scripts, in many places, we need to run system commands like<code>bundle install</code>, <code>rake db:create</code>, <code>rake db:migrate</code> and many more.</p><p>Let's suppose we need to run migrations using <code>rake db:migrate</code> in a Railsproject setup script. We can use the <code>Kernel#system</code> method.</p><pre><code class="language-ruby">irb&gt; system('rake db:migrate')</code></pre><h4>Ruby 2.5.0</h4><p>Executing <code>system</code> returns <code>true</code> or <code>false</code>. Another feature of <code>system</code> isthat it eats up the exceptions.</p><p>Let's suppose our migrations can run successfully. In this case the <code>system</code>command for running migrations will return true.</p><pre><code class="language-ruby">irb&gt; system('rake db:migrate') =&gt; true</code></pre><p>Let's suppose we have a migration that is trying to add a column to a tablewhich does not exist. In this case, the <code>system</code> command for running migrationswill return false.</p><pre><code class="language-ruby">irb&gt; system('rake db:migrate')== 20180311211836 AddFirstNameToAdmins: migrating =============================-- add_column(:admins, :first_name, :string)rake aborted!StandardError: An error has occurred, this and all later migrations canceled:PG::UndefinedTable: ERROR:  relation &quot;admins&quot; does not exist: ALTER TABLE &quot;admins&quot; ADD &quot;first_name&quot; character varying...Tasks: TOP =&gt; db:migrate(See full trace by running task with --trace) =&gt; false</code></pre><p>As we can see, even when there is a failure in executing system commands, thereturn value is false. Ruby does not raise an exception in those cases.</p><p>However, we can use <code>raise</code> explicitly to raise an exception and halt the setupscript execution.</p><pre><code class="language-ruby">irb&gt; system('rake db:migrate') || raise('Failed to run migrations')== 20180311211836 AddFirstNameToAdmins: migrating =============================-- add_column(:admins, :first_name, :string)rake aborted!StandardError: An error has occurred, this and all later migrations canceled:PG::UndefinedTable: ERROR:  relation &quot;admins&quot; does not exist: ALTER TABLE &quot;admins&quot; ADD &quot;first_name&quot; character varying...Tasks: TOP =&gt; db:migrate(See full trace by running task with --trace)Traceback (most recent call last):        2: from /Users/amit/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `&lt;main&gt;'        1: from (irb):4RuntimeError (Failed to run migrations)</code></pre><h4>Ruby 2.6.0-preview1</h4><p>Ruby 2.6 make our lives easier by providing an option <code>exception: true</code> so thatwe do not need to use <code>raise</code> explicitly to halt script execution.</p><pre><code class="language-ruby">irb&gt; system('rake db:migrate', exception: true)== 20180311211836 AddFirstNameToAdmins: migrating =============================-- add_column(:admins, :first_name, :string)rake aborted!StandardError: An error has occurred, this and all later migrations canceled:PG::UndefinedTable: ERROR:  relation &quot;admins&quot; does not exist: ALTER TABLE &quot;admins&quot; ADD &quot;first_name&quot; character varying...Tasks: TOP =&gt; db:migrate(See full trace by running task with --trace)Traceback (most recent call last):        3: from /Users/amit/.rvm/rubies/ruby-2.6.0-preview1/bin/irb:11:in `&lt;main&gt;'        2: from (irb):2        1: from (irb):2:in `system'RuntimeError (Command failed with exit 1: rake)</code></pre><p>Ruby 2.6 works the same way as previous Ruby versions when used without the<code>exception</code> option or used with <code>exception</code> set as false.</p><pre><code class="language-ruby">irb&gt; system('rake db:migrate', exception: false)== 20180311211836 AddFirstNameToAdmins: migrating =============================-- add_column(:admins, :first_name, :string)rake aborted!StandardError: An error has occurred, this and all later migrations canceled:PG::UndefinedTable: ERROR:  relation &quot;admins&quot; does not exist: ALTER TABLE &quot;admins&quot; ADD &quot;first_name&quot; character varying...Tasks: TOP =&gt; db:migrate(See full trace by running task with --trace) =&gt; false</code></pre><p>Here is the relevant <a href="https://github.com/ruby/ruby/commit/fb29cffab0">commit</a>and <a href="https://bugs.ruby-lang.org/issues/14386">discussion</a> for this change.</p><p><code>system</code> is not the only way to execute scripts like these. We wrote<a href="https://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html">a blog</a>6 years ago which discusses the differences between running commands using<code>backtick</code>, <code>exec</code>, <code>sh</code>, <code>popen3</code>, <code>popen2e</code> and <code>Process.spawn</code>.</p><p>The Chinese version of this blog is available<a href="http://madao.me/yi-ruby-2-6-kernel-de-system-fang-fa-zeng-jia-shi-fou-pao-chu-yi-chang-can-shu/">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 adds Thread.report_on_exception by default]]></title>
       <author><name>Vishal Telangre</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-enables-thread-report_on_exception-by-default"/>
      <updated>2018-04-18T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-enables-thread-report_on_exception-by-default</id>
      <content type="html"><![CDATA[<p>Let's see what happens when an exception is raised inside a thread.</p><pre><code class="language-ruby">division_thread = Thread.new do  puts &quot;Calculating 4/0 in division_thread&quot;  puts &quot;Result is: #{4/0}&quot;  puts &quot;Exiting from division_thread&quot;endsleep 1puts &quot;In the main thread&quot;</code></pre><p>Execution of it looks like this.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby thread_example_1.rbCalculating 4/0 in division_threadIn the main thread</code></pre><p>Note that the last two lines from the block were not printed. Also notice thatafter failing in the thread the program continued to run in main thread. That'swhy we got the message &quot;In the main thread&quot;.</p><p>This is because the default behavior of Ruby is to silently ignore exceptions inthreads and then to continue to execute in the main thread.</p><h2>Enabling abort_on_exception to stop on failure</h2><p>If we want an exception in a thread to stop further processing both in thethread and in the main thread then we can enable <code>Thread[.#]abort_on_exception</code>on that thread to achieve that.</p><p>Notice that in the below code we are using <code>Thread.current</code>.</p><pre><code class="language-ruby">division_thread = Thread.new do  Thread.current.abort_on_exception = true  puts &quot;Calculating 4/0 in division_thread&quot;  puts &quot;Result is: #{4/0}&quot;  puts &quot;Exiting from division_thread&quot;endsleep 1puts &quot;In the main thread&quot;</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby thread_example_2.rbCalculating 4/0 in division_threadthread_example_2.rb:5:in `/': divided by 0 (ZeroDivisionError)  from thread_example_2.rb:5:in `block in &lt;main&gt;'</code></pre><p>As we can see once an exception was encountered in the thread then processingstopped on both in the thread and in the main thread.</p><p>Note that <code>Thread.current.abort_on_exception = true</code> activates this behavioronly for the current thread.</p><p>If we want this behavior globally for all the threads then we need to use<code>Thread.abort_on_exception = true</code>.</p><h2>Running program with debug flag to stop on failure</h2><p>Let's run the original code with <code>--debug</code> option.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby --debug thread_example_1.rbthread_example_1.rb:1: warning: assigned but unused variable - division_threadCalculating 4/0 in division_threadException `ZeroDivisionError' at thread_example_1.rb:3 - divided by 0Exception `ZeroDivisionError' at thread_example_1.rb:7 - divided by 0thread_example_1.rb:3:in `/': divided by 0 (ZeroDivisionError)  from thread_example_1.rb:3:in `block in &lt;main&gt;'</code></pre><p>In this case the exception is printed in detail and the code in main thread wasnot executed.</p><p>Usually when we execute a program with <code>--debug</code> option then the behavior of theprogram does not change. We expect the program to print more stuff but we do notexpect behavior to change. However in this case the <code>--debug</code> option changes thebehavior of the program.</p><h2>Running program with join on thread to stop on failure</h2><p>If a thread raises an exception and <code>abort_on_exception</code> and <code>$DEBUG</code> flags arenot set then that exception will be processed at the time of joining of thethread.</p><pre><code class="language-ruby">division_thread = Thread.new do  puts &quot;Calculating 4/0 in division_thread&quot;  puts &quot;Result is: #{4/0}&quot;  puts &quot;Exiting from division_thread&quot;enddivision_thread.joinputs &quot;In the main thread&quot;</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby thread_example_3.rbCalculating 4/0 in division_threadthread_example_3.rb:3:in `/': divided by 0 (ZeroDivisionError)  from thread_example_3.rb:3:in `block in &lt;main&gt;'</code></pre><p>Both <code>Thread#join</code> and <code>Thread#value</code> will stop processing in the thread and inthe main thread once an exception is encountered.</p><h2>Introduction of report_on_exception in Ruby 2.4</h2><p>Almost 6 years ago, <a href="https://github.com/headius">Charles Nutter (headius)</a> hadproposed that the exceptions raised in threads should be automatically loggedand reported, by default. To make his point, he explained issues similar to whatwe discussed above about the Ruby's behavior of silently ignoring exceptions inthreads. <a href="https://bugs.ruby-lang.org/issues/6647">Here</a> is the relevantdiscussion on his proposal.</p><p>Following are some of the notable points discussed.</p><ul><li>Enabling <code>Thread[.#]abort_on_exception</code>, by default, is not always a goodidea.</li><li>There should be a flag which, if enabled, would print the thread-killingexception info.</li><li>In many cases, people spawn one-off threads which are not hard-referencedusing <code>Thread#join</code> or <code>Thread#value</code>. Such threads gets garbage collected.Should it report the thread-killing exception at the time of garbagecollection if such a flag is enabled?</li><li>Should it warn using<a href="https://ruby-doc.org/core-2.4.0/Warning.html#method-i-warn"><code>Warning#warn</code></a>or redirect to STDERR device while reporting?</li></ul><p>Charles Nutter suggested that a configurable global flag<code>Thread.report_on_exception</code> and instance-level flag<code>Thread#report_on_exception</code> should be implemented having its default value as<code>true</code>. When set to <code>true</code>, it should report print exception information.</p><p>Matz and other core members approved that <code>Thread[.#]report_on_exception</code> can beimplemented having its default value set to <code>false</code>.</p><p>Charles Nutter, Benoit Daloze and other people demanded that it should be <code>true</code>by default so that programmers can be aware of the silently disappearing threadsbecause of exceptions.</p><p>Shyouhei Urabe <a href="https://bugs.ruby-lang.org/issues/6647#note-41">advised</a> thatdue to some technical challenges, the default value should be set to <code>false</code> soas this feature could land in Ruby. Once this feature is in then the defaultvalue can be changed in a later release.</p><p><a href="https://github.com/nobu">Nobuyoshi Nakada (nobu)</a> pushed an<a href="https://github.com/ruby/ruby/commit/2e71c752787e0c7659bd5e89b6c5d433eddfe13a">implementation</a>for <code>Thread[.#]report_on_exception</code> with a default value set to <code>false</code>. It wasreleased in Ruby 2.4.0.</p><p>Let's try enabling <code>report_on_exception</code> globally using<code>Thread.report_on_exception</code>.</p><pre><code class="language-ruby">Thread.report_on_exception = truedivision_thread = Thread.new do  puts &quot;Calculating 4/0 in division_thread&quot;  puts &quot;Result is: #{4/0}&quot;  puts &quot;Exiting from division_thread&quot;endaddition_thread = Thread.new do  puts &quot;Calculating nil+4 in addition_thread&quot;  puts &quot;Result is: #{nil+4}&quot;  puts &quot;Exiting from addition_thread&quot;endsleep 1puts &quot;In the main thread&quot;</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby thread_example_4.rbCalculating 4/0 in division_thread#&lt;Thread:0x007fb10f018200@thread_example_4.rb:3 run&gt; terminated with exception:thread_example_4.rb:5:in `/': divided by 0 (ZeroDivisionError)  from thread_example_4.rb:5:in `block in &lt;main&gt;'Calculating nil+4 in addition_thread#&lt;Thread:0x007fb10f01aca8@thread_example_4.rb:9 run&gt; terminated with exception:thread_example_4.rb:11:in `block in &lt;main&gt;': undefined method `+' for nil:NilClass (NoMethodError)In the main thread</code></pre><p>It now reports the exceptions in all threads. It prints that the<code>Thread:0x007fb10f018200</code> was<code>terminated with exception: divided by 0 (ZeroDivisionError)</code>. Similarly,another thread <code>Thread:0x007fb10f01aca8</code> was<code>terminated with exception: undefined method '+' for nil:NilClass (NoMethodError)</code>.</p><p>Instead of enabling it globally for all threads, we can enable it for aparticular thread using instance-level <code>Thread#report_on_exception</code>.</p><pre><code class="language-ruby">division_thread = Thread.new do  puts &quot;Calculating 4/0 in division_thread&quot;  puts &quot;Result is: #{4/0}&quot;  puts &quot;Exiting from division_thread&quot;endaddition_thread = Thread.new do  Thread.current.report_on_exception = true  puts &quot;Calculating nil+4 in addition_thread&quot;  puts &quot;Result is: #{nil+4}&quot;  puts &quot;Exiting from addition_thread&quot;endsleep 1puts &quot;In the main thread&quot;</code></pre><p>In the above case we have enabled <code>report_on_exception</code> flag just for<code>addition_thread</code>.</p><p>Let's execute it.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby thread_example_5.rbCalculating 4/0 in division_threadCalculating nil+4 in addition_thread#&lt;Thread:0x007f8e6b007f70@thread_example_5.rb:7 run&gt; terminated with exception:thread_example_5.rb:11:in `block in &lt;main&gt;': undefined method `+' for nil:NilClass (NoMethodError)In the main thread</code></pre><p>Notice how it didn't report the exception which killed thread <code>division_thread</code>.As expected, it reported the exception that killed thread <code>addition_thread</code>.</p><p>With the above changes ruby reports the exception as soon as it encounters.However if these threads are joined then they will still raise exception.</p><pre><code class="language-ruby">division_thread = Thread.new do  Thread.current.report_on_exception = true  puts &quot;Calculating 4/0 in division_thread&quot;  puts &quot;Result is: #{4/0}&quot;  puts &quot;Exiting from division_thread&quot;endbegin  division_thread.joinrescue =&gt; exception  puts &quot;Explicitly caught - #{exception.class}: #{exception.message}&quot;endputs &quot;In the main thread&quot;</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby thread_example_6.rbCalculating 4/0 in division_thread#&lt;Thread:0x007f969d00d828@thread_example_6.rb:1 run&gt; terminated with exception:thread_example_6.rb:5:in `/': divided by 0 (ZeroDivisionError)  from thread_example_6.rb:5:in `block in &lt;main&gt;'Explicitly caught - ZeroDivisionError: divided by 0In the main thread</code></pre><p>See how we were still be able to handle the exception raised in<code>division_thread</code> above after joining it despite it reported it before due to<code>Thread#report_on_exception</code> flag.</p><h2>report_on_exception defaults to true in Ruby 2.5</h2><p><a href="https://github.com/eregon">Benoit Daloze (eregon)</a> strongly advocated that boththe <code>Thread.report_on_exception</code> and <code>Thread#report_on_exception</code> should havedefault value as <code>true</code>. <a href="https://bugs.ruby-lang.org/issues/14143">Here</a> is therelevant feature request.</p><p>After <a href="https://bugs.ruby-lang.org/issues/14143#note-9">approval from Matz</a>,Benoit Daloze pushed the<a href="https://github.com/ruby/ruby/search?utf8=%E2%9C%93&amp;q=Feature+%5C%2314143&amp;type=Commits">implementation</a>by fixing the failing tests and silencing the unnecessary verbose warnings.</p><p>It was released as part of Ruby 2.5.</p><p>Now in ruby 2.5 we can simply write like this.</p><pre><code class="language-ruby">division_thread = Thread.new do  puts &quot;Calculating 4/0 in division_thread&quot;  puts &quot;Result is: #{4/0}&quot;  puts &quot;Exiting from division_thread&quot;endaddition_thread = Thread.new do  puts &quot;Calculating nil+4 in addition_thread&quot;  puts &quot;Result is: #{nil+4}&quot;  puts &quot;Exiting from addition_thread&quot;endsleep 1puts &quot;In the main thread&quot;</code></pre><p>Let's execute it with Ruby 2.5.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby thread_example_7.rbCalculating 4/0 in division_thread#&lt;Thread:0x00007f827689a238@thread_example_7.rb:1 run&gt; terminated with exception (report_on_exception is true):Traceback (most recent call last):  1: from thread_example_7.rb:3:in `block in &lt;main&gt;'thread_example_7.rb:3:in `/': divided by 0 (ZeroDivisionError)Calculating nil+4 in addition_thread#&lt;Thread:0x00007f8276899b58@thread_example_7.rb:7 run&gt; terminated with exception (report_on_exception is true):Traceback (most recent call last):thread_example_7.rb:9:in `block in &lt;main&gt;': undefined method `+' for nil:NilClass (NoMethodError)In the main thread</code></pre><p>We can disable the thread exception reporting globally using<code>Thread.report_on_exception = false</code> or for a particular thread using<code>Thread.current.report_on_exception = false</code>.</p><h2>Future Possibilities</h2><p>In addition to this feature, Charles Nutter also<a href="https://bugs.ruby-lang.org/issues/14143#note-4">suggested</a> that it will be goodif there exists a callback handler which can accept a block to be executed whena thread dies due to an exception. The callback handler can be at global levelor it can be for a specific thread.</p><pre><code class="language-ruby">Thread.on_exception do  # some stuffend</code></pre><p>In the absence of such handler libraries need to resort to custom code to handleexceptions.<a href="https://github.com/mperham/sidekiq/blob/a60a91d3dd857592a532965f0701d285f13f28f1/lib/sidekiq/util.rb#L15-L27">Here is how</a>Sidekiq handles exceptions raised in threads.</p><p>Important thing to note is that <code>report_on_exception</code> does not change behaviorof the code. It does more reporting when a thread dies and when it comes tothread dies more reporting is a good thing.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 supports measuring branch and method coverages]]></title>
       <author><name>Vishal Telangre</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-supports-measuring-branch-and-method-coverages"/>
      <updated>2018-04-11T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-supports-measuring-branch-and-method-coverages</id>
      <content type="html"><![CDATA[<p>Ruby comes with<a href="https://ruby-doc.org/stdlib-2.5.0/libdoc/coverage/rdoc/Coverage.html">Coverage</a>,a simple standard library for test coverage measurement for a long time.</p><h2>Before Ruby 2.5</h2><p>Before Ruby 2.5, we could measure just the line coverage using <code>Coverage</code>.</p><p>Line coverage tells us whether a line is executed or not. If executed, then howmany times that line was executed.</p><p>We have a file called <code>score.rb</code>.</p><pre><code class="language-ruby">score = 33if score &gt;= 40  p :PASSEDelse  p :FAILEDend</code></pre><p>Now create another file <code>score_coverage.rb</code>.</p><pre><code class="language-ruby">require &quot;coverage&quot;Coverage.startload &quot;score.rb&quot;p Coverage.result</code></pre><p>We used <code>Coverage#start</code> method to measure the coverage of <code>score.rb</code> file.<code>Coverage#result</code> returns the coverage result.</p><p>Let's run it with Ruby 2.4.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby score_coverage.rb:FAILED{ &quot;score.rb&quot;=&gt; [1, nil, 1, 0, nil, 1, nil] }</code></pre><p>Let's look at the output. Each value in the array <code>[1, nil, 1, 0, nil, 1, nil]</code>denotes the count of line executions by the interpreter for each line in<code>score.rb</code> file.</p><p>This array is also called the &quot;line coverage&quot; of <code>score.rb</code> file.</p><p>A <code>nil</code> value in line coverage array means coverage is disabled for thatparticular line number or it is not a relevant line. Lines like <code>else</code>, <code>end</code>and blank lines have line coverage disabled.</p><p>Here's how we can read above line coverage result.</p><ul><li>Line number 1 (i.e. 0th index in the above result array) was executed once.</li><li>Coverage was disabled for line number 2 (i.e. index 1) as it is blank.</li><li>Line number 3 (i.e. index 2) was executed once.</li><li>Line number 4 did not execute.</li><li>Coverage was disabled for line number 5 as it contains only <code>else</code> clause.</li><li>Line number 6 was executed once.</li><li>Coverage was disabled for line number 7 as it contains just <code>end</code> keyword.</li></ul><h2>After Ruby 2.5</h2><p>There was a <a href="https://github.com/ruby/ruby/pull/511">pull request</a> opened in 2014to add method coverage and decision coverage metrics in Ruby. It was<a href="https://github.com/ruby/ruby/pull/511#issuecomment-328753499">rejected</a> by<a href="https://github.com/mame">Yusuke Endoh</a> as he saw some issues with it andmentioned that he was also working on a similar implementation.</p><p>In Ruby 2.5, Yusuke Endoh<a href="https://bugs.ruby-lang.org/issues/13901">added branch coverage and method coverage feature</a>to the <code>Coverage</code> library.</p><p>Let's see what's changed in <code>Coverage</code> library in Ruby 2.5.</p><h3>Line Coverage</h3><p>If we execute above example using Ruby 2.5, we will see no change in the result.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby score_coverage.rb:FAILED{ &quot;score.rb&quot; =&gt; [1, nil, 1, 0, nil, 1, nil] }</code></pre><p>This behavior is maintained to ensure that the <code>Coverage#start</code> API stays 100%backward compatible.</p><p>If we explicitly enable <code>lines</code> option on <code>Coverage#start</code> method in the above<code>score_coverage.rb</code> file, the coverage result will be different now.</p><pre><code class="language-ruby">require &quot;coverage&quot;Coverage.start(lines: true)load &quot;score.rb&quot;p Coverage.result</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby score_coverage.rb:FAILED{ &quot;score.rb&quot; =&gt; {    :lines =&gt; [1, nil, 1, 0, nil, 1, nil]  }}</code></pre><p>We can see that the coverage result is now a hash which reads that the<code>score.rb</code> file has <code>lines</code> coverage as <code>[1, nil, 1, 0, nil, 1, nil]</code>.</p><h3>Branch Coverage</h3><p>Branch coverage helps us identify which branches are executed and which ones arenot executed.</p><p>Let's see how to get branch coverage.</p><p>We will update the <code>score_coverage.rb</code> by enabling <code>branches</code> option.</p><pre><code class="language-ruby">require &quot;coverage&quot;Coverage.start(branches: true)load &quot;score.rb&quot;p Coverage.result</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby score_coverage.rb:FAILED{ &quot;score.rb&quot; =&gt;  { :branches =&gt; {      [:if, 0, 3, 0, 7, 3] =&gt; {        [:then, 1, 4, 2, 4, 15] =&gt; 0,        [:else, 2, 6, 2, 6, 15] =&gt; 1      }    }  }}</code></pre><p>Here is how to read the data in array.</p><pre><code class="language-ruby">[  BRANCH_TYPE,  UNIQUE_ID,  START_LINE_NUMBER,  START_COLUMN_NUMBER,  END_LINE_NUMBER,  END_COLUMN_NUMBER]</code></pre><p>Please note that column numbers start from 0 and line numbers start from 1.</p><p>Let's try to read above printed branch coverage result.</p><p><code>[:if, 0, 3, 0, 7, 3]</code> reads that <code>if</code> statement starts at line 3 &amp; column 0 andends at line 7 &amp; column 3.</p><p><code>[:then, 1, 4, 2, 4, 15]</code> reads that <code>then</code> clause starts at line 4 &amp; column 2and ends at line 4 &amp; column 15.</p><p>Similarly, <code>[:else, 2, 6, 2, 6, 15]</code> reads that <code>else</code> clause starts at line 6 &amp;column 2 and ends at line 6 &amp; column 15.</p><p>Most importantly as per the branch coverage format, we can see that the branchfrom <code>if</code> to <code>then</code> was never executed since <code>COUNTER</code> is <code>0</code>. The anotherbranch from <code>if</code> to <code>else</code> was executed once since <code>COUNTER</code> is <code>1</code>.</p><h3>Method Coverage</h3><p>Measuring method coverage helps us identify which methods were invoked and whichwere not.</p><p>We have a file <code>grade_calculator.rb</code>.</p><pre><code class="language-ruby">students_scores = { &quot;Sam&quot; =&gt; [53, 91, 72],                    &quot;Anna&quot; =&gt; [91, 97, 95],                    &quot;Bob&quot; =&gt; [33, 69, 63] }def average(scores)  scores.reduce(&amp;:+)/scores.sizeenddef grade(average_score)  case average_score  when 90.0..100.0 then :A  when 80.0..90.0 then :B  when 70.0..80.0 then :C  when 60.0..70.0 then :D  else :F  endenddef greet  puts &quot;Congratulations!&quot;enddef warn  puts &quot;Try hard next time!&quot;endstudents_scores.each do |student_name, scores|  achieved_grade = grade(average(scores))  puts &quot;#{student_name}, you've got '#{achieved_grade}' grade.&quot;  if achieved_grade == :A    greet  elsif achieved_grade == :F    warn  end  putsend</code></pre><p>To measure method coverage of above file, let's create<code>grade_calculator_coverage.rb</code> by enabling <code>methods</code> option on <code>Coverage#start</code>method.</p><pre><code class="language-ruby">require &quot;coverage&quot;Coverage.start(methods: true)load &quot;grade_calculator.rb&quot;p Coverage.result</code></pre><p>Let's run it using Ruby 2.5.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby grade_calculator_coverage.rbSam, you've got 'C' grade.Anna, you've got 'A' grade.Congratulations!Bob, you've got 'F' grade.Try hard next time!{ &quot;grade_calculator.rb&quot; =&gt; {    :methods =&gt; {      [Object, :warn, 23, 0, 25, 3] =&gt; 1,      [Object, :greet, 19, 0, 21, 3] =&gt; 1,      [Object, :grade, 9, 0, 17, 3] =&gt; 3,      [Object, :average, 5, 0, 7, 3] =&gt; 3    }  }}</code></pre><p>The format of method coverage result is defined as shown below.</p><pre><code class="language-ruby">[ CLASS_NAME,  METHOD_NAME,  START_LINE_NUMBER,  START_COLUMN_NUMBER,  END_LINE_NUMBER,  END_COLUMN_NUMBER ]</code></pre><p>Therefore, <code>[Object, :grade, 9, 0, 17, 3] =&gt; 3</code> reads that the <code>Object#grade</code>method which starts from line 9 &amp; column 0 to line 17 &amp; column 3 was invoked 3times.</p><h2>Conclusion</h2><p>We can measure all coverages at once also.</p><pre><code class="language-ruby">Coverage.start(lines: true, branches: true, methods: true)</code></pre><p>What's the use of these different types of coverages anyway?</p><p>Well, one use case is to integrate this in a test suite and to determine whichlines, branches and methods are executed and which ones are not executed by thetest. Further, we can sum up these and evaluate total coverage of a test suite.</p><p>Author of this feature, Yusuke Endoh has released<a href="https://github.com/mame/coverage-helpers">coverage-helpers</a> gem which allowsfurther advanced manipulation and processing of coverage results obtained using<code>Coverage#result</code>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 adds Exception#full_message method]]></title>
       <author><name>Vishal Telangre</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-adds-exception-full_message-method"/>
      <updated>2018-03-13T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-adds-exception-full_message-method</id>
      <content type="html"><![CDATA[<p>Before Ruby 2.5, if we want to log a caught exception, we would need to formatit ourselves.</p><pre><code class="language-ruby">class AverageService  attr_reader :numbers, :coerced_numbers  def initialize(numbers)    @numbers = numbers    @coerced_numbers = coerce_numbers  end  def average    sum / count  end  private  def coerce_numbers    numbers.map do |number|      begin        Float(number)      rescue Exception =&gt; exception        puts &quot;#{exception.message} (#{exception.class})\n\t#{exception.backtrace.join(&quot;\n\t&quot;)}&quot;        puts &quot;Coercing '#{number}' as 0.0\n\n&quot;        0.0      end    end  end  def sum    coerced_numbers.map(&amp;:to_f).sum  end  def count    coerced_numbers.size.to_f  endendaverage = AverageService.new(ARGV).averageputs &quot;Average is: #{average}&quot;</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby average_service.rb 5 4f 7 1s0invalid value for Float(): &quot;4f&quot; (ArgumentError)average_service.rb:18:in `Float'average_service.rb:18:in `block in coerce_numbers'average_service.rb:16:in `map'average_service.rb:16:in `coerce_numbers'average_service.rb:6:in `initialize'average_service.rb:37:in `new'average_service.rb:37:in `&lt;main&gt;'Coercing '4f' as 0.0invalid value for Float(): &quot;1s0&quot; (ArgumentError)average_service.rb:18:in `Float'average_service.rb:18:in `block in coerce_numbers'average_service.rb:16:in `map'average_service.rb:16:in `coerce_numbers'average_service.rb:6:in `initialize'average_service.rb:37:in `new'average_service.rb:37:in `&lt;main&gt;'Coercing '1s0' as 0.0Average of [5.0, 0.0, 7.0, 0.0] is: 3.0</code></pre><p>It was <a href="https://bugs.ruby-lang.org/issues/14141">proposed</a> that there should bea simple method to print the caught exception using the same format that rubyuses while printing an uncaught exception.</p><p>Some of the proposed method names were <code>display</code>, <code>formatted</code>, <code>to_formatted_s</code>,<code>long_message</code>, and <code>full_message</code>.</p><p>Matz <a href="https://bugs.ruby-lang.org/issues/14141#note-15">approved</a> the<code>Exception#full_message</code> method name.</p><p>In Ruby 2.5, we can re-write above example as follows.</p><pre><code class="language-ruby">class AverageService  attr_reader :numbers, :coerced_numbers  def initialize(numbers)    @numbers = numbers    @coerced_numbers = coerce_numbers  end  def average    sum / count  end  private  def coerce_numbers    numbers.map do |number|      begin        Float(number)      rescue Exception =&gt; exception        puts exception.full_message        puts &quot;Coercing '#{number}' as 0.0\n\n&quot;        0.0      end    end  end  def sum    coerced_numbers.map(&amp;:to_f).sum  end  def count    coerced_numbers.size.to_f  endendaverage = AverageService.new(ARGV).averageputs &quot;Average is: #{average}&quot;</code></pre><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby average_service.rb 5 4f 7 1s0Traceback (most recent call last):6: from average_service.rb:37:in `&lt;main&gt;'5: from average_service.rb:37:in `new'4: from average_service.rb:6:in `initialize'3: from average_service.rb:16:in `coerce_numbers'2: from average_service.rb:16:in `map'1: from average_service.rb:18:in `block in coerce_numbers'average_service.rb:18:in `Float': invalid value for Float(): &quot;4f&quot; (ArgumentError)Coercing '4f' as 0.0Traceback (most recent call last):6: from average_service.rb:37:in `&lt;main&gt;'5: from average_service.rb:37:in `new'4: from average_service.rb:6:in `initialize'3: from average_service.rb:16:in `coerce_numbers'2: from average_service.rb:16:in `map'1: from average_service.rb:18:in `block in coerce_numbers'average_service.rb:18:in `Float': invalid value for Float(): &quot;1s0&quot; (ArgumentError)Coercing '1s0' as 0.0Average of [5.0, 0.0, 7.0, 0.0] is: 3.0</code></pre><p>Note that, Ruby 2.5 prints exception backtrace in reverse order if STDERR isunchanged and is a TTY as discussed<a href="https://blog.bigbinary.com/2018/03/07/ruby-2-5-prints-backstrace-and-error-message-in-reverse-order.html">in our previous blog post</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 prints backtrace & error message in reverse]]></title>
       <author><name>Vishal Telangre</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-prints-backstrace-and-error-message-in-reverse-order"/>
      <updated>2018-03-07T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-prints-backstrace-and-error-message-in-reverse-order</id>
      <content type="html"><![CDATA[<p>Stack trace or backtrace is a sequential representation of the stack of methodcalls in a program which gets printed when an exception is raised. It is oftenused to find out the exact location in a program from where the exception wasraised.</p><h2>Before Ruby 2.5</h2><p>Before Ruby 2.5, the printed backtrace contained the exception class and theerror message at the top. Next line contained where in the program the exceptionwas raised. Next we got more lines which contained cascaded method calls.</p><p>Consider a simple Ruby program.</p><pre><code class="language-ruby">class DivisionService  attr_reader :a, :b  def initialize(a, b)    @a, @b = a.to_i, b.to_i  end  def divide    puts a / b  endendDivisionService.new(ARGV[0], ARGV[1]).divide</code></pre><p>Let's execute it using Ruby 2.4.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.4.0 ruby division_service.rb 5 0division_service.rb:9:in `/': divided by 0 (ZeroDivisionError)from division_service.rb:9:in `divide'from division_service.rb:13:in `&lt;main&gt;'</code></pre><p>In the printed backtrace above, the first line shows the location, error messageand the exception class name; whereas the subsequent lines shows the callermethod names and their locations. Each line in the backtrace above is oftenconsidered as a stack frame placed on the call stack.</p><p>Most of the times, a backtrace has so many lines that it makes it very difficultto fit the whole backtrace in the visible viewport of the terminal.</p><p>Since the backtrace is printed in top to bottom order the meaningful informationlike error message, exception class and the exact location where the exceptionwas raised is displayed at top of the backtrace. It means developers often needto scroll to the top in the terminal window to find out what went wrong.</p><h2>After Ruby 2.5</h2><p>Over 4 years ago an <a href="https://bugs.ruby-lang.org/issues/8661">issue</a> was createdto make printing of backtrace in reverse order configurable.</p><p>After much discussion Nobuyoshi Nakada made the commit to print backtrace anderror message<a href="https://github.com/ruby/ruby/commit/5318154fe1ac6f8dff014988488b9e063988a105">in reverse order</a>only when the error output device (<code>STDERR</code>) is a TTY (i.e. a terminal). Messagewill not be printed in reverse order if the original <code>STDERR</code> is attached tosomething like a <code>File</code> object.</p><p><a href="https://github.com/ruby/ruby/blob/5318154fe1ac6f8dff014988488b9e063988a105/eval_error.c#L187-L195">Look at the code here</a>where the check happens if <code>STDERR</code> is a TTY and is unchanged.</p><p>Let's execute the same program using Ruby 2.5.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby division_service.rb 5 0Traceback (most recent call last):2: from division_service.rb:13:in `&lt;main&gt;'1: from division_service.rb:9:in `divide'division_service.rb:9:in `/': divided by 0 (ZeroDivisionError)$</code></pre><p>We can notice two new changes in the above backtrace.</p><ol><li>The error message and exception class is printed last (i.e. at the bottom).</li><li>The stack also<a href="https://github.com/ruby/ruby/commit/87023a1dcc548f0eb7ccfacd64d795093d1c7e17">adds frame number</a>when printing in reverse order.</li></ol><p>This feature makes the debugging convenient when the backtrace size is a quitebig and cannot fit in the terminal window. We can easily see the error messagewithout scrolling up now.</p><p>Note that, the <code>Exception#backtrace</code> attribute still holds an array of stackframes like before in the top to bottom order.</p><p>So if we rescue the caught exception and print the backtrace manually</p><pre><code class="language-ruby">class DivisionService  attr_reader :a, :b  def initialize(a, b)    @a, @b = a.to_i, b.to_i  end  def divide    puts a / b  endendbegin  DivisionService.new(ARGV[0], ARGV[1]).dividerescue Exception =&gt; e  puts &quot;#{e.class}: #{e.message}&quot;  puts e.backtrace.join(&quot;\n&quot;)end</code></pre><p>we will get the old behavior.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby division_service.rb 5 0ZeroDivisionError: divided by 0division_service.rb:9:in `/'division_service.rb:9:in `divide'division_service.rb:16:in `&lt;main&gt;'$</code></pre><p>Also, note that if we assign <code>STDERR</code> with a <code>File</code> object, thus making it anon-TTY</p><pre><code class="language-ruby">puts &quot;STDERR is a TTY? [before]: #{$stderr.tty?}&quot;$stderr = File.new(&quot;stderr.log&quot;, &quot;w&quot;)$stderr.sync = trueputs &quot;STDERR is a TTY? [after]: #{$stderr.tty?}&quot;class DivisionService  attr_reader :a, :b  def initialize(a, b)    @a, @b = a.to_i, b.to_i  end  def divide    puts a / b  endendDivisionService.new(ARGV[0], ARGV[1]).divide</code></pre><p>we can get the old behavior but the backtrace would be written to the specifiedfile and not to <code>STDERR</code>.</p><pre><code class="language-ruby">$ RBENV_VERSION=2.5.0 ruby division_service.rb 5 0STDERR is a TTY? [before]: trueSTDERR is a TTY? [after]: false$ cat stderr.logdivision_service.rb:14:in `/': divided by 0 (ZeroDivisionError)from division_service.rb:14:in `divide'from division_service.rb:18:in `&lt;main&gt;'$</code></pre><p>This feature has been tagged as<a href="https://github.com/ruby/ruby/commit/5b58d8e6d8d187f37750540535f741cf6c2b661a">experimental feature</a>.What it means is that Ruby team is<a href="https://bugs.ruby-lang.org/issues/8661#journal-64903-notes">gathering feedback</a>on this feature.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 added Hash#slice method]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-added-hash-slice-method"/>
      <updated>2018-02-06T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-added-hash-slice-method</id>
      <content type="html"><![CDATA[<h4>Ruby 2.4</h4><p>Let's say we have a hash<code>{ id: 1, name: 'Ruby 2.5', description: 'BigBinary Blog' }</code> and we want toselect key value pairs having the keys <code>name</code> and <code>description</code>.</p><p>We can use the<a href="https://ruby-doc.org/core-2.4.2/Hash.html#method-i-select">Hash#select</a> method.</p><pre><code class="language-ruby">irb&gt; blog = { id: 1, name: 'Ruby 2.5', description: 'BigBinary Blog' }  =&gt; {:id=&gt;1, :name=&gt;&quot;Ruby 2.5&quot;, :description=&gt;&quot;BigBinary Blog&quot;}irb&gt; blog.select { |key, value| [:name, :description].include?(key) }  =&gt; {:name=&gt;&quot;Ruby 2.5&quot;, :description=&gt;&quot;BigBinary Blog&quot;}</code></pre><p><a href="https://bugs.ruby-lang.org/users/5184">Matzbara Masanao</a> proposed a simplemethod to take care of this problem.</p><p>Some of the names proposed were <code>choice</code> and <code>pick</code>.</p><p><a href="https://twitter.com/yukihiro_matz">Matz</a> suggested the name <code>slice</code> since thismethod is ActiveSupport compatible.</p><h4>Ruby 2.5.0</h4><pre><code class="language-ruby">irb&gt; blog = { id: 1, name: 'Ruby 2.5', description: 'BigBinary Blog' }  =&gt; {:id=&gt;1, :name=&gt;&quot;Ruby 2.5&quot;, :description=&gt;&quot;BigBinary Blog&quot;}irb&gt; blog.slice(:name, :description)  =&gt; {:name=&gt;&quot;Ruby 2.5&quot;, :description=&gt;&quot;BigBinary Blog&quot;}</code></pre><p>So, now we can use a simple method <code>slice</code> to select key value pairs from a hashwith specified keys.</p><p>Here is the relevant <a href="https://github.com/ruby/ruby/commit/6c50bdda0b">commit</a>and <a href="https://bugs.ruby-lang.org/issues/13563">discussion</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 allows creating structs with keyword arguments]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-allows-creating-structs-with-keyword-arguments"/>
      <updated>2018-01-16T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-allows-creating-structs-with-keyword-arguments</id>
      <content type="html"><![CDATA[<p>In Ruby, structs can be created using positional arguments.</p><pre><code class="language-ruby">Customer = Struct.new(:name, :email)Customer.new(&quot;John&quot;, &quot;john@example.com&quot;)</code></pre><p>This approach works when the arguments list is short. When arguments listincreases then it gets harder to track which position maps to which value.</p><p>Here if we pass keyword argument then we won't get any error. But the values arenot what we wanted.</p><pre><code class="language-ruby">Customer.new(name: &quot;John&quot;, email: &quot;john@example.com&quot;)=&gt; #&lt;struct Customer name={:name=&gt;&quot;John&quot;, :email=&gt;&quot;john@example.com&quot;}, email=nil&gt;</code></pre><p>Ruby 2.5 introduced<a href="https://bugs.ruby-lang.org/issues/11925">creating structs using keyword arguments</a>.Relevant pull request is <a href="https://github.com/ruby/ruby/pull/1771/files">here</a>.</p><p>However this introduces a problem. How do we indicate to <code>Struct</code> if we want topass arguments using position or keywords.</p><p>Takashi Kokubun<a href="https://bugs.ruby-lang.org/issues/11925#journal-68208-private_notes">suggested</a>to use <code>keyword_argument</code> as an identifier.</p><pre><code class="language-ruby">Customer = Struct.new(:name, :email, keyword_argument: true)Customer.create(name: &quot;John&quot;, email: &quot;john@example.com&quot;)</code></pre><p>Matz<a href="https://bugs.ruby-lang.org/issues/11925#journal-68295-private_notes">suggested</a>to change the name to <code>keyword_init</code>.</p><p>So in Ruby 2.5 we can create structs using keywords as long as we are passing<code>keyword_init</code>.</p><pre><code class="language-ruby">Customer = Struct.new(:name, :email, keyword_init: true)Customer.new(name: &quot;John&quot;, email: &quot;john@example.com&quot;)=&gt; #&lt;struct Customer name=&quot;John&quot;, email=&quot;john@example.com&quot;&gt;</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 adds Hash#transform_keys method]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-adds-hash-transform_keys-method"/>
      <updated>2018-01-09T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-adds-hash-transform_keys-method</id>
      <content type="html"><![CDATA[<p>Ruby 2.4 added<a href="https://bigbinary.com/blog/ruby-2-4-added-hash-transform-values-and-its-destructive-version-from-active-support">Hash#transform_values</a>method to transform values of the hash.</p><p>In Ruby 2.5, a similar method<a href="https://bugs.ruby-lang.org/issues/13583">Hash#transform_keys</a> is added fortransforming keys of the hash.</p><pre><code class="language-ruby">&gt;&gt; h = { name: &quot;John&quot;, email: &quot;john@example.com&quot; }=&gt; {:name=&gt;&quot;John&quot;, :email=&gt;&quot;john@example.com&quot;}&gt;&gt; h.transform_keys { |k| k.to_s }=&gt; {&quot;name&quot;=&gt;&quot;John&quot;, &quot;email&quot;=&gt;&quot;john@example.com&quot;}</code></pre><p>The bang sibling of this method, <code>Hash#transform_keys!</code> is also added whichchanges the hash in place.</p><p>These two methods are already present in<a href="http://guides.rubyonrails.org/active_support_core_extensions.html#transform-keys-and-transform-keys-bang">Active Support from Rails</a>and are natively supported in Ruby now.</p><p>Rails master is already supporting<a href="https://github.com/rails/rails/commit/f213e926892">using the native methods</a> ifsupported by the Ruby version.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 enumerable predicates accept pattern argument]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-enumerable-predicates-accept-pattern-argument"/>
      <updated>2018-01-02T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-enumerable-predicates-accept-pattern-argument</id>
      <content type="html"><![CDATA[<p>Ruby 2.5.0 was recently<a href="https://www.ruby-lang.org/en/news/2017/12/25/ruby-2-5-0-released/">released</a>.</p><p>Ruby has sequence predicates such as <code>all?</code>, <code>none?</code>, <code>one?</code> and <code>any?</code> whichtake a block and evaluate that by passing every element of the sequence to it.</p><pre><code class="language-ruby">if queries.any? { |sql| /LEFT OUTER JOIN/i =~ sql }logger.log &quot;Left outer join detected&quot;end</code></pre><p>Ruby 2.5 allows using a shorthand for this by<a href="https://bugs.ruby-lang.org/issues/11286">passing a pattern argument</a>.Internally <code>case equality operator(===)</code> is used against every element of thesequence and the pattern argument.</p><pre><code class="language-ruby">if queries.any?(/LEFT OUTER JOIN/i)logger.log &quot;Left outer join detected&quot;end# Translates to:queries.any? { |sql| /LEFT OUTER JOIN/i === sql }</code></pre><p>This allows us to write concise and shorthand expressions where block is onlyused for comparisons. This feature is applicable to <code>all?</code>, <code>none?</code>, <code>one?</code> and<code>any?</code> methods.</p><h3>Similarities with Enumerable#grep</h3><p>This feature is based on how <code>Enumerable#grep</code> works. <code>grep</code> returns an array ofevery element in the sequence for which the <code>case equality operator(===)</code>returns true by applying the pattern. In this case, the <code>all?</code> and friendsreturn true or false.</p><p>There is a <a href="https://bugs.ruby-lang.org/issues/14197">proposal</a> to add it for<code>select</code> and <code>reject</code> as well.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 requires pp by default]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-requires-pp-by-default"/>
      <updated>2017-12-20T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-requires-pp-by-default</id>
      <content type="html"><![CDATA[<p>Ruby 2.5.0-preview1 was recently<a href="https://www.ruby-lang.org/en/news/2017/10/10/ruby-2-5-0-preview1-released/">released</a>.</p><p>Ruby allows pretty printing of objects using<a href="http://ruby-doc.org/stdlib-2.4.0/libdoc/pp/rdoc/PP.html">pp method</a>.</p><p>Before Ruby 2.5, we had to require PP explicitly before using it. Even theofficial documentation states that &quot;All examples assume you have loaded the PPclass with require 'pp'&quot;.</p><pre><code class="language-ruby">&gt;&gt; months = %w(January February March)=&gt; [&quot;January&quot;, &quot;February&quot;, &quot;March&quot;]&gt;&gt; pp monthsNoMethodError: undefined method `pp' for main:ObjectDid you mean?  pfrom (irb):5from /Users/prathamesh/.rbenv/versions/2.4.1/bin/irb:11:&gt;&gt; require 'pp'=&gt; true&gt;&gt; pp months[&quot;January&quot;, &quot;February&quot;, &quot;March&quot;]=&gt; [&quot;January&quot;, &quot;February&quot;, &quot;March&quot;]</code></pre><p>In Ruby 2.5, we don't need to require pp. It<a href="https://bugs.ruby-lang.org/issues/14123">gets required by default</a>. We can useit directly.</p><pre><code class="language-ruby">&gt;&gt; months = %w(January February March)=&gt; [&quot;January&quot;, &quot;February&quot;, &quot;March&quot;]&gt;&gt; pp months[&quot;January&quot;, &quot;February&quot;, &quot;March&quot;]=&gt; [&quot;January&quot;, &quot;February&quot;, &quot;March&quot;]</code></pre><p>This feature was added after Ruby 2.5.0 preview 1 was released, so it's notpresent in the preview. It's present in<a href="https://github.com/ruby/ruby">Ruby trunk</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Array#prepend and Array#append in Ruby 2.5]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/array-prepend-and-array-append-in-ruby-2-5"/>
      <updated>2017-12-19T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/array-prepend-and-array-append-in-ruby-2-5</id>
      <content type="html"><![CDATA[<p>Ruby has <code>Array#unshift</code> to prepend an element to the start of an array and<code>Array#push</code> to append an element to the end of an array.</p><p>The names of these methods are not very intuitive. Active Support from Railsalready has aliases for<a href="https://github.com/rails/rails/blob/e48704db8e6021b690b1fe2b362c7cb2e624e173/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb">the unshift and push methods</a>, namely <code>prepend</code> and <code>append</code>.</p><p>In Ruby 2.5, these methods<a href="https://bugs.ruby-lang.org/issues/12746">are added in the Ruby language itself</a>.</p><pre><code class="language-ruby">&gt;&gt; a = [&quot;hello&quot;]=&gt; [&quot;hello&quot;]&gt;&gt; a.append &quot;world&quot;=&gt; [&quot;hello&quot;, &quot;world&quot;]&gt;&gt; a.prepend &quot;Hey&quot;=&gt; [&quot;Hey&quot;, &quot;hello&quot;, &quot;world&quot;]&gt;&gt;</code></pre><p>They are implemented as aliases to the original <code>unshift</code> and <code>push</code> methods sothere is no change in the behavior.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 added yield_self]]></title>
       <author><name>Vijay Kumar Agrawal</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-added-yield_self"/>
      <updated>2017-12-12T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-added-yield_self</id>
      <content type="html"><![CDATA[<p>Ruby 2.5 added a new method named<a href="https://bugs.ruby-lang.org/issues/6721">yield_self</a>. It yields the receiver tothe given block and returns output of the last statement in the block.</p><pre><code class="language-ruby">irb&gt; &quot;Hello&quot;.yield_self { |str| str + &quot; World&quot; }  =&gt; &quot;Hello World&quot;</code></pre><h4>How is it different from <code>try</code> in Rails ?</h4><p>Without a method argument <a href="https://apidock.com/rails/v4.2.7/Object/try">try</a>behaves similar to <code>yield_self</code>. It would yield to the given block unless thereceiver is nil and returns the output of the last statement in the block.</p><pre><code class="language-ruby">irb&gt; &quot;Hello&quot;.try { |str| str + &quot; World&quot; }  =&gt; &quot;Hello World&quot;</code></pre><p>Couple of differences to note are, <code>try</code> is not part of <code>Ruby</code> but <code>Rails</code>. Also<code>try</code>'s main purpose is protection against <code>nil</code> hence it doesn't execute theblock if receiver is <code>nil</code>.</p><pre><code class="language-ruby">irb&gt; nil.yield_self { |obj| &quot;Hello World&quot; }  =&gt; &quot;Hello World&quot;irb&gt; nil.try { |obj| &quot;Hello World&quot; }  =&gt; nil</code></pre><h4>What about <code>tap</code>?</h4><p><code>tap</code> also is similar to <code>yield_self</code>. It's part of Ruby itself. The onlydifference is the value that is returned. <code>tap</code> returns the receiver itselfwhile <code>yield_self</code> returns the output of the block.</p><pre><code class="language-ruby">irb&gt; &quot;Hello&quot;.yield_self { |str| str + &quot; World&quot; }  =&gt; &quot;Hello World&quot;irb&gt; &quot;Hello&quot;.tap { |str| str + &quot; World&quot; }  =&gt; &quot;Hello&quot;</code></pre><p>Overall, <code>yield_self</code> improves readability of the code by promoting chainingover nested function calls. Here is an example of both the styles.</p><pre><code class="language-ruby">irb&gt; add_greeting = -&gt; (str) { &quot;HELLO &quot; + str }irb&gt; to_upper = -&gt; (str) { str.upcase }# with new `yield_self`irb&gt; &quot;world&quot;.yield_self(&amp;to_upper)            .yield_self(&amp;add_greeting)  =&gt; &quot;HELLO WORLD&quot;# nested function callsirb&gt; add_greeting.call(to_upper.call(&quot;world&quot;))  =&gt; &quot;HELLO WORLD&quot;</code></pre><p><code>yield_self</code> is part of <code>Kernel</code> and hence it's available to all the objects.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 added delete_prefix and delete_suffix methods]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-5-added-delete_prefix-and-delete_suffix-methods"/>
      <updated>2017-11-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-5-added-delete_prefix-and-delete_suffix-methods</id>
      <content type="html"><![CDATA[<h4>Ruby 2.4</h4><p>Let's say that we have a string <code>Projects::CategoriesController</code> and we want toremove <code>Controller</code>. We can use<a href="https://ruby-doc.org/core-2.4.2/String.html#method-i-chomp">chomp</a> method.</p><pre><code class="language-ruby">irb&gt; &quot;Projects::CategoriesController&quot;.chomp(&quot;Controller&quot;)=&gt; &quot;Projects::Categories&quot;</code></pre><p>However if we want to remove <code>Projects::</code> from the string then there is nocorresponding method of <code>chomp</code>. We need to resort to<a href="https://ruby-doc.org/core-2.4.2/String.html#sub-method">sub</a>.</p><pre><code class="language-ruby">irb&gt; &quot;Projects::CategoriesController&quot;.sub(/Projects::/, '')=&gt; &quot;CategoriesController&quot;</code></pre><p><a href="https://bugs.ruby-lang.org/users/6938">Naotoshi Seo</a> did not like using regularexpression for such a simple task. He proposed that Ruby should have a methodfor taking care of such tasks.</p><p>Some of the names proposed were <code>remove_prefix</code>, <code>deprefix</code>, <code>lchomp</code>,<code>remove_prefix</code> and <code>head_chomp</code>.</p><p><a href="https://twitter.com/yukihiro_matz">Matz</a> suggested the name <code>delete_prefix</code> andthis method was born.</p><h4>Ruby 2.5.0-preview1</h4><pre><code class="language-ruby">irb&gt; &quot;Projects::CategoriesController&quot;.delete_prefix(&quot;Projects::&quot;)=&gt; &quot;CategoriesController&quot;</code></pre><p>Now in order to delete prefix we can use <code>delete_prefix</code> and to delete suffix wecould use <code>chomp</code>. This did not feel right. So for symmetry <code>delete_suffix</code> wasadded.</p><pre><code class="language-ruby">irb&gt; &quot;Projects::CategoriesController&quot;.delete_suffix(&quot;Controller&quot;)=&gt; &quot;Projects::Categories&quot;</code></pre><p>Read up on <a href="https://bugs.ruby-lang.org/issues/12694">this discussion</a> to learnmore about how elixir, go, python, and PHP deal with similar requirements.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 introduces Dir.children and Dir.each_child]]></title>
       <author><name>Mohit Natoo</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2_5-introduces-dir-children-and-dir-each_child"/>
      <updated>2017-11-21T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2_5-introduces-dir-children-and-dir-each_child</id>
      <content type="html"><![CDATA[<p><a href="https://ruby-doc.org/core-2.4.2/Dir.html#entries-method">Dir.entries</a> is amethod present in Ruby 2.4. It returns the output of shell command <code>ls -a</code> in anarray.</p><pre><code class="language-ruby">&gt; Dir.entries(&quot;/Users/john/Desktop/test&quot;)&gt; =&gt; [&quot;.&quot;, &quot;..&quot;, &quot;.config&quot;, &quot;program.rb&quot;, &quot;group.txt&quot;]&gt;</code></pre><p>We also have method<a href="https://ruby-doc.org/core-2.4.2/Dir.html#foreach-method">Dir.foreach</a> whichiterates and yields each value from the output of <code>ls -a</code> command to the block.</p><pre><code class="language-ruby">&gt; Dir.foreach(&quot;/Users/john/Desktop/test&quot;) { |child| puts child }&gt; .&gt; ..&gt; .config&gt; program.rb&gt; group.txt&gt; test2&gt;</code></pre><p>We can see that the output includes the directives for current directory andparent directory which are <code>&quot;.&quot;</code> and <code>&quot;..&quot;</code>.</p><p>When we want to have access only to the children files and directories, we donot need the <code>[&quot;.&quot;, &quot;..&quot;]</code> subarray.</p><p>This is a very common use case and we'll probably have to do something like<code>Dir.entries(path) - [&quot;.&quot;, &quot;..&quot;]</code> to achieve the desired output.</p><p>To overcome such issues,<a href="https://bugs.ruby-lang.org/issues/11302">Ruby 2.5 introduced Dir.children</a>. Itreturns the output of <code>ls -a</code> command without the directives for current andparent directories.</p><pre><code class="language-ruby">&gt; Dir.children(&quot;/Users/mohitnatoo/Desktop/test&quot;)&gt; =&gt; [&quot;.config&quot;, &quot;program.rb&quot;, &quot;group.txt&quot;]&gt;</code></pre><p>Additionally, we can use <code>Dir.each_child</code> method to avoid yielding current andparent directory directives while iterating,</p><pre><code class="language-ruby">&gt; Dir.each_child(&quot;/Users/mohitnatoo/Desktop/test&quot;) { |child| puts child }&gt; .config&gt; program.rb&gt; group.txt&gt; test2&gt;</code></pre><p>As noted in the <a href="https://bugs.ruby-lang.org/issues/11302">discussion</a> the nameswere chosen to match with existing methods<a href="https://ruby-doc.org/stdlib-2.4.2/libdoc/pathname/rdoc/Pathname.html#method-i-children">Pathname#children</a>and<a href="https://ruby-doc.org/core-2.4.2/Dir.html#foreach-method">Pathname#each_child</a>.</p><p>These additions seem like simple features. Well the issue was posted more thantwo years ago.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 allows rescue/else/ensure inside do/end blocks]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2.5-allows-rescue-inside-do-end-blocks"/>
      <updated>2017-10-24T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2.5-allows-rescue-inside-do-end-blocks</id>
      <content type="html"><![CDATA[<h4>Ruby 2.4</h4><pre><code class="language-ruby">irb&gt; array_from_user = [4, 2, 0, 1]  =&gt; [4, 2, 0, 1]irb&gt; array_from_user.each do |number|irb&gt;   p 10 / numberirb&gt; rescue ZeroDivisionError =&gt; exceptionirb&gt;   p exceptionirb&gt;   nextirb&gt; endSyntaxError: (irb):4: syntax error, unexpected keyword_rescue,expecting keyword_endrescue ZeroDivisionError =&gt; exception      ^</code></pre><p>Ruby 2.4 throws an error when we try to use rescue/else/ensure inside do/endblocks.</p><h4>Ruby 2.5.0-preview1</h4><pre><code class="language-ruby">irb&gt; array_from_user = [4, 2, 0, 1]  =&gt; [4, 2, 0, 1]irb&gt; array_from_user.each do |number|irb&gt;   p 10 / numberirb&gt; rescue ZeroDivisionError =&gt; exceptionirb&gt;   p exceptionirb&gt;   nextirb&gt; end25#&lt;ZeroDivisionError: divided by 0&gt;10 =&gt; [4, 2, 0, 1]</code></pre><p>Ruby 2.5 supports rescue/else/ensure inside do/end blocks.</p><p>Here is relevant <a href="https://github.com/ruby/ruby/commit/0ec889d7ed">commit</a> and<a href="https://bugs.ruby-lang.org/issues/12906">discussion</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.5 has removed top level constant lookup]]></title>
       <author><name>Amit Choudhary</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2.5-has-removed-top-level-constant-lookup"/>
      <updated>2017-10-18T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2.5-has-removed-top-level-constant-lookup</id>
      <content type="html"><![CDATA[<h4>Ruby 2.4</h4><pre><code class="language-ruby">irb&gt; class Projectirb&gt; end=&gt; nilirb&gt; class Categoryirb&gt; end=&gt; nilirb&gt; Project::Category(irb):5: warning: toplevel constant Category referenced by Project::Category =&gt; Category</code></pre><p>Ruby 2.4 returns the top level constant with a warning if it is unable to find aconstant in the specified scope.</p><p>This does not work well in cases where we need constants to be defined with samename at top level and also in the same scope.</p><h4>Ruby 2.5.0-preview1</h4><pre><code class="language-ruby">irb&gt; class Projectirb&gt; end=&gt; nilirb&gt; class Categoryirb&gt; end=&gt; nilirb&gt; Project::CategoryNameError: uninitialized constant Project::CategoryDid you mean?  Categoryfrom (irb):5</code></pre><p>Ruby 2.5 throws an error if it is unable to find a constant in the specifiedscope.</p><p>Here is the relevant <a href="https://github.com/ruby/ruby/commit/44a2576f79">commit</a>and <a href="https://bugs.ruby-lang.org/issues/11547">discussion</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 has optimized enumerable min max methods]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-0-has-optimized-enumerable-min-max-methods"/>
      <updated>2017-09-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-0-has-optimized-enumerable-min-max-methods</id>
      <content type="html"><![CDATA[<p>Enumerables in Ruby have <code>min</code>, <code>max</code> and <code>minmax</code> comparison methods which arequite convenient to use.</p><pre><code class="language-ruby">(1..99).min #=&gt; 1(1..99).max #=&gt; 99(1..99).minmax #=&gt; [1, 99]</code></pre><p>In Ruby 2.4, <code>Enumurable#min</code>, <code>Enumurable#max</code><a href="https://github.com/ruby/ruby/commit/3dcd4b2a98e">methods</a> and<code>Enumurable#minmax</code> <a href="https://github.com/ruby/ruby/commit/9f44b77a18d">method</a>are now more optimized.</p><p>We would run the following benchmark snippet for both Ruby 2.3 and Ruby 2.4 andobserve the results</p><pre><code class="language-ruby">require 'benchmark/ips'Benchmark.ips do |bench|NUM1 = 1_000_000.times.map { rand }ENUM_MIN = Enumerable.instance_method(:min).bind(NUM1)ENUM_MAX = Enumerable.instance_method(:max).bind(NUM1)ENUM_MINMAX = Enumerable.instance_method(:minmax).bind(NUM1)bench.report('Enumerable#min') doENUM_MIN.callendbench.report('Enumerable#max') doENUM_MAX.callendbench.report('Enumerable#minmax') doENUM_MINMAX.callendend</code></pre><h4>Results for Ruby 2.3</h4><pre><code class="language-ruby">Warming up --------------------------------------Enumerable#min 1.000 i/100msEnumerable#max 1.000 i/100msEnumerable#minmax 1.000 i/100msCalculating -------------------------------------Enumerable#min 14.810 (13.5%) i/s - 73.000 in 5.072666sEnumerable#max 16.131 ( 6.2%) i/s - 81.000 in 5.052324sEnumerable#minmax 11.758 ( 0.0%) i/s - 59.000 in 5.026007s</code></pre><h4>Ruby 2.4</h4><pre><code class="language-ruby">Warming up --------------------------------------Enumerable#min 1.000 i/100msEnumerable#max 1.000 i/100msEnumerable#minmax 1.000 i/100msCalculating -------------------------------------Enumerable#min 18.091 ( 5.5%) i/s - 91.000 in 5.042064sEnumerable#max 17.539 ( 5.7%) i/s - 88.000 in 5.030514sEnumerable#minmax 13.086 ( 7.6%) i/s - 66.000 in 5.052537s</code></pre><p>From the above benchmark results, it can be seen that there has been animprovement in the run times for the methods.</p><p>Internally Ruby has changed the logic by which objects are compared, whichresults in these methods being optimized. You can have a look at the commits<a href="https://github.com/ruby/ruby/commit/9f44b77a18d">here</a> and<a href="https://github.com/ruby/ruby/commit/3dcd4b2a98e">here</a>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[CSV::Row#each etc. return enumerator when no block given]]></title>
       <author><name>Sushant Mittal</name></author>
      <link href="https://www.bigbinary.com/blog/csv-row-each-and-delete-if-return-enumerator-when-no-block-given"/>
      <updated>2017-09-25T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/csv-row-each-and-delete-if-return-enumerator-when-no-block-given</id>
      <content type="html"><![CDATA[<p>In Ruby 2.3, These methods do not return enumerator when no block is given.</p><h3>Ruby 2.3</h3><pre><code class="language-ruby">CSV::Row.new(%w(banana mango), [1,2]).each #=&gt; #&lt;CSV::Row &quot;banana&quot;:1 &quot;mango&quot;:2&gt;CSV::Row.new(%w(banana mango), [1,2]).delete_if #=&gt; #&lt;CSV::Row &quot;banana&quot;:1 &quot;mango&quot;:2&gt;</code></pre><p>Some methods raise exception because of this behavior.</p><pre><code class="language-ruby">&gt; ruby -rcsv -e 'CSV::Table.new([CSV::Row.new(%w{banana mango}, [1, 2])]).by_col.each' #=&gt; /Users/sushant/.rbenv/versions/2.3.0/lib/ruby/2.3.0/csv.rb:850:in `block in each': undefined method `[]' for nil:NilClass (NoMethodError)  from /Users/sushant/.rbenv/versions/2.3.0/lib/ruby/2.3.0/csv.rb:850:in `each'  from /Users/sushant/.rbenv/versions/2.3.0/lib/ruby/2.3.0/csv.rb:850:in `each'  from -e:1:in `&lt;main&gt;'</code></pre><p>Ruby 2.4<a href="https://github.com/ruby/ruby/commit/b425d4f19ad9efaefcb1a767a6ea26e6d40e3985">fixed this issue</a>.</p><h3>Ruby 2.4</h3><pre><code class="language-ruby">CSV::Row.new(%w(banana mango), [1,2]).each #=&gt; #&lt;Enumerator: #&lt;CSV::Row &quot;banana&quot;:1 &quot;mango&quot;:2&gt;:each&gt;CSV::Row.new(%w(banana mango), [1,2]).delete_if #=&gt; #&lt;Enumerator: #&lt;CSV::Row &quot;banana&quot;:1 &quot;mango&quot;:2&gt;:delete_if&gt;</code></pre><p>As we can see, these methods now return an enumerator when no block is given.</p><p>In Ruby 2.4 following code will not raise any exception.</p><pre><code class="language-ruby">&gt; ruby -rcsv -e 'CSV::Table.new([CSV::Row.new(%w{banana mango}, [1, 2])]).by_col.each'</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 DateTime#to_time & Time#to_time keeps info]]></title>
       <author><name>Sushant Mittal</name></author>
      <link href="https://www.bigbinary.com/blog/to-time-preserves-time-zone-info-in-ruby-2-4"/>
      <updated>2017-09-19T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/to-time-preserves-time-zone-info-in-ruby-2-4</id>
      <content type="html"><![CDATA[<p>In Ruby, <code>DateTime#to_time</code> and <code>Time#to_time</code> methods can be used to return aTime object.</p><p>In Ruby 2.3, these methods convert time into system timezone offset instead ofpreserving timezone offset of the receiver.</p><h3>Ruby 2.3</h3><pre><code class="language-ruby">&gt; datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') #=&gt; #&lt;DateTime: 2017-05-16T10:15:30+09:00 ((2457890j,4530s,0n),+32400s,2299161j)&gt;&gt; datetime.to_time #=&gt; 2017-05-16 06:45:30 +0530&gt; time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') #=&gt; 2017-05-16 10:15:30 +0900&gt; time.to_time #=&gt; 2017-05-16 06:45:30 +0530</code></pre><p>As you can see, <code>DateTime#to_time</code> and <code>Time#to_time</code> methods return time insystem timezone offset <code>+0530</code>.</p><p>Ruby 2.4 fixed<a href="https://github.com/ruby/ruby/commit/5f11a6eb6cca740b08384d1e4a68df643d98398c">DateTime#to_time</a>and<a href="https://github.com/ruby/ruby/commit/456523e2ede3073767fd8cb73cc4b159c3608890">Time#to_time</a>.</p><p>Now, <code>DateTime#to_time</code> and <code>Time#to_time</code> preserve receiver's timezone offsetinfo.</p><h3>Ruby 2.4</h3><pre><code class="language-ruby">&gt; datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') #=&gt; #&lt;DateTime: 2017-05-16T10:15:30+09:00 ((2457890j,4530s,0n),+32400s,2299161j)&gt;&gt; datetime.to_time #=&gt; 2017-05-16 10:15:30 +0900&gt; time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') #=&gt; 2017-05-16 10:15:30 +0900&gt; time.to_time #=&gt; 2017-05-16 10:15:30 +0900</code></pre><p>Since this is a breaking change for Rails application upgrading to ruby 2.4,Rails 4.2.8 built a compatibility layer by adding a<a href="https://github.com/rails/rails/commit/c9c5788a527b70d7f983e2b4b47e3afd863d9f48">config option</a>.<code>ActiveSupport.to_time_preserves_timezone</code> was added to control how <code>to_time</code>handles timezone offsets.</p><p>Here is an example of how application behaves when <code>to_time_preserves_timezone</code>is set to <code>false</code>.</p><pre><code class="language-ruby">&gt; ActiveSupport.to_time_preserves_timezone = false&gt; datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') #=&gt; Tue, 16 May 2017 10:15:30 +0900&gt; datetime.to_time #=&gt; 2017-05-16 06:45:30 +0530&gt; time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') #=&gt; 2017-05-16 10:15:30 +0900&gt; time.to_time #=&gt; 2017-05-16 06:45:30 +0530</code></pre><p>Here is an example of how application behaves when <code>to_time_preserves_timezone</code>is set to <code>true</code>.</p><pre><code class="language-ruby">&gt; ActiveSupport.to_time_preserves_timezone = true&gt; datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') #=&gt; Tue, 16 May 2017 10:15:30 +0900&gt; datetime.to_time #=&gt; 2017-05-16 10:15:30 +0900&gt; time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') #=&gt; 2017-05-16 10:15:30 +0900&gt; time.to_time #=&gt; 2017-05-16 10:15:30 +0900</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Avoid exception for dup on Integer]]></title>
       <author><name>Rohit Arolkar</name></author>
      <link href="https://www.bigbinary.com/blog/avoid-exceptions-for-dup-on-interger-and-similar-cases"/>
      <updated>2017-08-01T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/avoid-exceptions-for-dup-on-interger-and-similar-cases</id>
      <content type="html"><![CDATA[<p>Prior to Ruby 2.4, if we were to <code>dup</code> an <code>Integer</code>, it would fail with a<code>TypeError</code>.</p><pre><code class="language-ruby">&gt; 1.dupTypeError: can't dup Fixnumfrom (irb):1:in `dup'from (irb):1</code></pre><p>This was confusing because <code>Integer#dup</code> is actually implemented.</p><pre><code class="language-ruby">&gt; Integer.respond_to? :dup=&gt; true</code></pre><p>However, if we were to freeze an <code>Integer</code> it would fail silently.</p><pre><code class="language-ruby">&gt; 1.freeze=&gt; 1</code></pre><p>Ruby 2.4 has now included dup-ability for <code>Integer</code> as well.</p><pre><code class="language-ruby">&gt; 1.dup=&gt; 1</code></pre><p>In Ruby, some object types are immediate variables and therefore cannot beduped/cloned. Yet, there was no graceful way of averting the error thrown by thesanity check when we attempt to dup/clone them.</p><p>So now <code>Integer#dup</code> functions exactly the way <code>freeze</code> does -- fail silentlyand return the object itself. It makes sense because nothing about these objectscan be changed in the first place.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 no exception for objects converted to IPAddr]]></title>
       <author><name>Sushant Mittal</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-ip-addr-methods-do-not-throw-exception-for-objects-that-cant-be-converted-to-ipaddr"/>
      <updated>2017-06-21T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-ip-addr-methods-do-not-throw-exception-for-objects-that-cant-be-converted-to-ipaddr</id>
      <content type="html"><![CDATA[<p>In Ruby,<a href="https://docs.ruby-lang.org/en/2.4.0/IPAddr.html#method-i-3D-3D"><code>IPAddr#==</code></a>method is used to check whether two IP addresses are equal or not. Ruby also has<a href="https://docs.ruby-lang.org/en/2.4.0/IPAddr.html#method-i-3C-3D-3E"><code>IPAddr#&lt;=&gt;</code></a>method which is used to compare two IP addresses.</p><p>In Ruby 2.3, behavior of these methods was inconsistent. Let's see an example.</p><pre><code class="language-ruby"># Ruby 2.3&gt;&gt; IPAddr.new(&quot;1.2.1.3&quot;) == &quot;Some ip address&quot;=&gt; IPAddr::InvalidAddressError: invalid address</code></pre><p>But if the first argument is invalid IP address and second is valid IP address,then it would return <code>false</code>.</p><pre><code class="language-ruby"># Ruby 2.3&gt;&gt; &quot;Some ip address&quot; == IPAddr.new(&quot;1.2.1.3&quot;)=&gt; false</code></pre><p>The <code>&lt;=&gt;</code> method would raise exception in both the cases.</p><pre><code class="language-ruby"># Ruby 2.3&gt;&gt; &quot;Some ip address&quot; &lt;=&gt; IPAddr.new(&quot;1.2.1.3&quot;)=&gt; IPAddr::InvalidAddressError: invalid address&gt;&gt; IPAddr.new(&quot;1.2.1.3&quot;) &lt;=&gt; &quot;Some ip address&quot;=&gt; IPAddr::InvalidAddressError: invalid address</code></pre><p>In Ruby 2.4, <a href="https://bugs.ruby-lang.org/issues/12799">this issue</a> is<a href="https://github.com/ruby/ruby/pull/1435/files#diff-3504e08cf251c76a597c727011315dd1">fixed</a>for both the methods to return the result without raising exception, if theobjects being compared can't be converted to an IPAddr object.</p><pre><code class="language-ruby"># Ruby 2.4&gt;&gt; IPAddr.new(&quot;1.2.1.3&quot;) == &quot;Some ip address&quot;=&gt; false&gt;&gt; &quot;Some ip address&quot; == IPAddr.new(&quot;1.2.1.3&quot;)=&gt; false&gt;&gt; IPAddr.new(&quot;1.2.1.3&quot;) &lt;=&gt; &quot;Some ip address&quot;=&gt; nil&gt;&gt; &quot;Some ip address&quot; &lt;=&gt; IPAddr.new(&quot;1.2.1.3&quot;)=&gt; nil</code></pre><p>This might cause some backward compatibility if our code is expecting theexception which is no longer raised in Ruby 2.4.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 deprecated constants TRUE, FALSE & NIL]]></title>
       <author><name>Akshay Vishnoi</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-has-depecated-constants-true-false-and-nil"/>
      <updated>2017-06-19T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-has-depecated-constants-true-false-and-nil</id>
      <content type="html"><![CDATA[<p>Ruby has top level constants like <code>TRUE</code>, <code>FALSE</code> and <code>NIL</code>. These constants arejust synonyms for <code>true</code>, <code>false</code> and <code>nil</code> respectively.</p><p>In Ruby 2.4, these constants are<a href="https://bugs.ruby-lang.org/issues/12574">deprecated</a> and will be removed infuture version.</p><pre><code class="language-ruby"># Ruby 2.32.3.1 :001 &gt; TRUE =&gt; true2.3.1 :002 &gt; FALSE =&gt; false2.3.1 :003 &gt; NIL =&gt; nil</code></pre><pre><code class="language-ruby"># Ruby 2.42.4.0 :001 &gt; TRUE(irb):1: warning: constant ::TRUE is deprecated =&gt; true2.4.0 :002 &gt; FALSE(irb):2: warning: constant ::FALSE is deprecated =&gt; false2.4.0 :003 &gt; NIL(irb):3: warning: constant ::NIL is deprecated =&gt; nil</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 allows custom suffix of rotated log files]]></title>
       <author><name>Sushant Mittal</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-allows-to-customize-suffix-of-the-rotated-log-files"/>
      <updated>2017-06-15T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-allows-to-customize-suffix-of-the-rotated-log-files</id>
      <content type="html"><![CDATA[<p>In Ruby, The<a href="http://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html#method-c-new">Logger</a>class can be used for rotating log files daily, weekly or monthly.</p><pre><code class="language-ruby">daily_logger = Logger.new('foo.log', 'daily')weekly_logger = Logger.new('foo.log', 'weekly')monthly_logger = Logger.new('foo.log', 'monthly')</code></pre><p>At the end of the specified period, Ruby will change the file extension of thelog file as follows:</p><pre><code class="language-ruby">foo.log.20170615</code></pre><p>The format of the suffix for the rotated log file is <code>%Y%m%d</code>. In Ruby 2.3,there was no way to customize this suffix format.</p><p>Ruby 2.4<a href="https://github.com/ruby/ruby/commit/2c6f15b1ad90af37d7e0eefff7b3f5262e0a4c0b">added the ability</a>to customize the suffix format by passing an extra argument<code>shift_period_suffix</code>.</p><pre><code class="language-ruby"># Ruby 2.4logger = Logger.new('foo.log', 'weekly', shift_period_suffix: '%d-%m-%Y')</code></pre><p>Now, suffix of the rotated log file will use the custom date format which wepassed.</p><pre><code class="language-ruby">foo.log.15-06-2017</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 Hash#transform_values & destructive version]]></title>
       <author><name>Sushant Mittal</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-added-hash-transform-values-and-its-destructive-version-from-active-support"/>
      <updated>2017-06-14T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-added-hash-transform-values-and-its-destructive-version-from-active-support</id>
      <content type="html"><![CDATA[<p>It is a common use case to transform the values of a hash.</p><pre><code class="language-ruby">{ a: 1, b: 2, c: 3 } =&gt; { a: 2, b: 4, c: 6 }{ a: &quot;B&quot;, c: &quot;D&quot;, e: &quot;F&quot; } =&gt; { a: &quot;b&quot;, c: &quot;d&quot;, e: &quot;f&quot; }</code></pre><p>We can transform the values of a hash destructively (i.e. modify the originalhash with new values) or non-destructively (i.e. return a new hash instead ofmodifying the original hash).</p><p>Prior to Ruby 2.4, we need to use following code to transform the values of ahash.</p><pre><code class="language-ruby"># Ruby 2.3 Non-destructive version&gt; hash = { a: 1, b: 2, c: 3 } #=&gt; {:a=&gt;1, :b=&gt;2, :c=&gt;3}&gt; hash.inject({}) { |h, (k, v)| h[k] = v * 2; h } #=&gt; {:a=&gt;2, :b=&gt;4, :c=&gt;6}&gt; hash #=&gt; {:a=&gt;1, :b=&gt;2, :c=&gt;3}&gt; hash = { a: &quot;B&quot;, c: &quot;D&quot;, e: &quot;F&quot; } #=&gt; {:a=&gt;&quot;B&quot;, :c=&gt;&quot;D&quot;, :e=&gt;&quot;F&quot;}&gt; hash.inject({}) { |h, (k, v)| h[k] = v.downcase; h } #=&gt; {:a=&gt;&quot;b&quot;, :c=&gt;&quot;d&quot;, :e=&gt;&quot;f&quot;}&gt; hash #=&gt; {:a=&gt;&quot;B&quot;, :c=&gt;&quot;D&quot;, :e=&gt;&quot;F&quot;}</code></pre><pre><code class="language-ruby"># Ruby 2.3 Destructive version&gt; hash = { a: 1, b: 2, c: 3 } #=&gt; {:a=&gt;1, :b=&gt;2, :c=&gt;3}&gt; hash.each { |k, v| hash[k] = v * 2 } #=&gt; {:a=&gt;2, :b=&gt;4, :c=&gt;6}&gt; hash #=&gt; {:a=&gt;2, :b=&gt;4, :c=&gt;6}&gt; hash = { a: &quot;B&quot;, c: &quot;D&quot;, e: &quot;F&quot; } #=&gt; {:a=&gt;&quot;B&quot;, :c=&gt;&quot;D&quot;, :e=&gt;&quot;F&quot;}&gt; hash.each { |k, v| hash[k] = v.downcase } #=&gt; {:a=&gt;&quot;b&quot;, :c=&gt;&quot;d&quot;, :e=&gt;&quot;f&quot;}&gt; hash #=&gt; {:a=&gt;&quot;b&quot;, :c=&gt;&quot;d&quot;, :e=&gt;&quot;f&quot;}</code></pre><h2>transform_values and transform_values! from Active Support</h2><p>Active Support has already implemented handy methods<a href="https://github.com/rails/rails/commit/b2cf8b251aac39c1e3ce71bc1de34a2ce5ef52b1">Hash#transform_values and Hash#transform_values!</a>to transform hash values.</p><p>Now, Ruby 2.4 has also implemented<a href="https://github.com/ruby/ruby/commit/ea5184b939ec3dbdcbd7013da350b8dcb6ca6107">Hash#map_v and Hash#map_v!</a>and then renamed to<a href="https://github.com/ruby/ruby/commit/eaa0a27f6149a9afa2b29729307ff9cc7b0bc95f">Hash#transform_values and Hash#transform_values!</a>for the same purpose.</p><pre><code class="language-ruby"># Ruby 2.4 Non-destructive version&gt; hash = { a: 1, b: 2, c: 3 } #=&gt; {:a=&gt;1, :b=&gt;2, :c=&gt;3}&gt; hash.transform_values { |v| v * 2 } #=&gt; {:a=&gt;2, :b=&gt;4, :c=&gt;6}&gt; hash #=&gt; {:a=&gt;1, :b=&gt;2, :c=&gt;3}&gt; hash = { a: &quot;B&quot;, c: &quot;D&quot;, e: &quot;F&quot; } #=&gt; {:a=&gt;&quot;B&quot;, :c=&gt;&quot;D&quot;, :e=&gt;&quot;F&quot;}&gt; hash.transform_values(&amp;:downcase) #=&gt; {:a=&gt;&quot;b&quot;, :c=&gt;&quot;d&quot;, :e=&gt;&quot;f&quot;}&gt; hash #=&gt; {:a=&gt;&quot;B&quot;, :c=&gt;&quot;D&quot;, :e=&gt;&quot;F&quot;}</code></pre><pre><code class="language-ruby"># Ruby 2.4 Destructive version&gt; hash = { a: 1, b: 2, c: 3 } #=&gt; {:a=&gt;1, :b=&gt;2, :c=&gt;3}&gt; hash.transform_values! { |v| v * 2 } #=&gt; {:a=&gt;2, :b=&gt;4, :c=&gt;6}&gt; hash #=&gt; {:a=&gt;2, :b=&gt;4, :c=&gt;6}&gt; hash = { a: &quot;B&quot;, c: &quot;D&quot;, e: &quot;F&quot; } #=&gt; {:a=&gt;&quot;B&quot;, :c=&gt;&quot;D&quot;, :e=&gt;&quot;F&quot;}&gt; hash.transform_values!(&amp;:downcase) #=&gt; {:a=&gt;&quot;b&quot;, :c=&gt;&quot;d&quot;, :e=&gt;&quot;f&quot;}&gt; hash #=&gt; {:a=&gt;&quot;b&quot;, :c=&gt;&quot;d&quot;, :e=&gt;&quot;f&quot;}</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Binding irb - Runtime Invocation for IRB]]></title>
       <author><name>Rohit Arolkar</name></author>
      <link href="https://www.bigbinary.com/blog/binding-irb"/>
      <updated>2017-04-18T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/binding-irb</id>
      <content type="html"><![CDATA[<p>It's very common to see a ruby programmer write a few <code>puts</code> or <code>p</code> statements,either for debugging or for knowing the value of variables.</p><p><a href="https://github.com/pry/pry">pry</a> did make our lives easier with the usage of<code>binding.pry</code>. However, it was still a bit of an inconvenience to have itinstalled at runtime, while working with the <code>irb</code>.</p><p>Ruby 2.4 has now introduced <code>binding.irb</code>. By simply adding <code>binding.irb</code> to ourcode we can open an IRB session.</p><pre><code class="language-ruby">class ConvolutedProcessdef do_something@variable = 10    binding.irb    # opens a REPL hereendendirb(main):029:0\* ConvolutedProcess.new.do_somethingirb(#&lt;ConvolutedProcess:0x007fc55c827f48&gt;):001:0&gt; @variable=&gt; 10</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 has added additional parameters for Logger#new]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-has-added-additional-parameters-for-logger-new"/>
      <updated>2017-04-10T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-has-added-additional-parameters-for-logger-new</id>
      <content type="html"><![CDATA[<p>The<a href="http://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html#method-c-new">Logger</a>class in Ruby provides a simple but sophisticated logging utility.</p><p>After creating the logger object we need to set its level.</p><h3>Ruby 2.3</h3><pre><code class="language-ruby">require 'logger'logger = Logger.new(STDOUT)logger.level = Logger::INFO</code></pre><p>If we are working with <code>ActiveRecord::Base.logger</code>, then same code would looksomething like this.</p><pre><code class="language-ruby">require 'logger'ActiveRecord::Base.logger = Logger.new(STDOUT)ActiveRecord::Base.logger.level = Logger::INFO</code></pre><p>As we can see in the both the cases we need to set the level separately afterinstantiating the object.</p><h3>Ruby 2.4</h3><p>In Ruby 2.4, <code>level</code> can now be specified in the constructor.</p><pre><code class="language-ruby">#ruby 2.4require 'logger'logger = Logger.new(STDOUT, level: Logger::INFO)# let's verify itlogger.level      #=&gt; 1</code></pre><p>Similarly, other options such as <code>progname</code>, <code>formatter</code> and <code>datetime_format</code>,which prior to Ruby 2.4 had to be explicitly set, can now be set during theinstantiation.</p><pre><code class="language-ruby">#ruby 2.3require 'logger'logger = Logger.new(STDOUT)logger.level = Logger::INFOlogger.progname = 'bigbinary'logger.datetime_format = '%Y-%m-%d %H:%M:%S'logger.formatter = proc do |severity, datetime, progname, msg|  &quot;#{severity} #{datetime} ==&gt; App: #{progname}, Message: #{msg}\n&quot;endlogger.info(&quot;Program started...&quot;)#=&gt; INFO 2017-03-16 18:43:58 +0530 ==&gt; App: bigbinary, Message: Program started...</code></pre><p>Here is same stuff in Ruby 2.4.</p><pre><code class="language-ruby">#ruby 2.4require 'logger'logger = Logger.new(STDOUT,  level: Logger::INFO,  progname: 'bigbinary',  datetime_format: '%Y-%m-%d %H:%M:%S',  formatter: proc do |severity, datetime, progname, msg|    &quot;#{severity} #{datetime} ==&gt; App: #{progname}, Message: #{msg}\n&quot;  end)logger.info(&quot;Program started...&quot;)#=&gt; INFO 2017-03-16 18:47:39 +0530 ==&gt; App: bigbinary, Message: Program started...</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 has default basename for Tempfile#create]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-has-default-basename-for-tempfile-create"/>
      <updated>2017-04-04T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-has-default-basename-for-tempfile-create</id>
      <content type="html"><![CDATA[<h3>Tempfile class</h3><p><a href="http://ruby-doc.org/stdlib-2.4.0/libdoc/tempfile/rdoc/Tempfile.html">Tempfile</a>is used for managing temporary files in Ruby. A Tempfile object creates atemporary file with a unique filename. It behaves just like a File object, andtherefore we can perform all the usual file operations on it.</p><h3>Why Tempfile when we can use File</h3><p>These days it is common to store file on services like S3. Let's say that wehave a <code>users.csv</code> file on S3. Working with this file remotely is problematic.In such cases it is desirable to download the file on local machine formanipulation. After the work is done then file should be deleted. Tempfile isideal for such cases.</p><h3>Basename for tempfile</h3><p>If we want to create a temporary file then we needed to pass parameter to itprior to Ruby 2.3.</p><pre><code class="language-ruby">require 'tempfile'file = Tempfile.new('bigbinary')#=&gt; #&lt;Tempfile:/var/folders/jv/fxkfk9_10nb_964rvrszs2540000gn/T/bigbinary-20170304-10828-1w02mqi&gt;</code></pre><p>As we can see above the generated file name begins with &quot;bigbinary&quot; word.</p><p>Since Tempfile ensures that the generate filename will always be unique thepoint of passing the argument is meaningless. Ruby doc calls this passing&quot;basename&quot;.</p><p>So in Ruby 2.3.0 it was <a href="https://github.com/ruby/ruby/pull/523">decided</a> thatthe basename parameter was meaningless for <code>Tempfile#new</code> and an empty stringwill be the default value.</p><pre><code class="language-ruby">require 'tempfile'file = Tempfile.new#=&gt; #&lt;Tempfile:/var/folders/jv/fxkfk9_10nb_964rvrszs2540000gn/T/20170304-10828-1v855bf&gt;</code></pre><p>But the same was not implemented for <code>Tempfile#create</code>.</p><pre><code class="language-ruby"># Ruby 2.3.0require 'tempfile'Tempfile.create do |f|  f.write &quot;hello&quot;endArgumentError: wrong number of arguments (given 0, expected 1..2)</code></pre><p>This was <a href="https://bugs.ruby-lang.org/issues/11965">fixed</a> in Ruby 2.4. So nowthe basename parameter for <code>Tempfile.create</code> is set to empty string by default,to keep it consistent with the <code>Tempfile#new</code> method.</p><pre><code class="language-ruby"># Ruby 2.4require 'tempfile'Tempfile.create do |f|  f.write &quot;hello&quot;end=&gt; 5</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[New arguments support for float & integer modifiers]]></title>
       <author><name>Abhishek Jain</name></author>
      <link href="https://www.bigbinary.com/blog/new-ndigits-arguments-supported-for-float-modifiers-in-ruby-2-4"/>
      <updated>2017-03-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/new-ndigits-arguments-supported-for-float-modifiers-in-ruby-2-4</id>
      <content type="html"><![CDATA[<p>In Ruby, there are many methods available which help us to modify a float orinteger value.</p><h3>Ruby 2.3.x</h3><p>In the previous versions of Ruby, we could use methods such as <code>floor</code>, <code>ceil</code>and <code>truncate</code> in following ways.</p><pre><code class="language-ruby">5.54.floor          #=&gt; 55.54.ceil           #=&gt; 65.54.truncate       #=&gt; 5</code></pre><p>Providing an argument to these methods would result in <code>ArgumentError</code>exception.</p><h3>Ruby 2.4</h3><p>Ruby community decided to come up with an option to<a href="https://bugs.ruby-lang.org/issues/12245">add precision argument</a> .</p><p>The precision argument, which can be negative, helps us to get result to therequired precision to either side of the decimal point.</p><p>The default value for the precision argument is 0.</p><pre><code class="language-ruby">876.543.floor(-2)       #=&gt; 800876.543.floor(-1)       #=&gt; 870876.543.floor           #=&gt; 876876.543.floor(1)        #=&gt; 876.5876.543.floor(2)        #=&gt; 876.54876.543.ceil(-2)        #=&gt; 900876.543.ceil(-1)        #=&gt; 880876.543.ceil            #=&gt; 877876.543.ceil(1)         #=&gt; 876.6876.543.ceil(2)         #=&gt; 876.55876.543.truncate(-2)    #=&gt; 800876.543.truncate(-1)    #=&gt; 870876.543.truncate        #=&gt; 876876.543.truncate(1)     #=&gt; 876.5876.543.truncate(2)     #=&gt; 876.54</code></pre><p>These methods all work the same on Integer as well.</p><pre><code class="language-ruby">5.floor(2)              #=&gt; 5.05.ceil(2)               #=&gt; 5.05.truncate(2)           #=&gt; 5.0</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 adds Enumerable#uniq & Enumerable::Lazy#uniq]]></title>
       <author><name>Mohit Natoo</name></author>
      <link href="https://www.bigbinary.com/blog/enumerable-uniq-and-enumerable-lazy-uniq-part-of-ruby-2-4"/>
      <updated>2017-03-21T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/enumerable-uniq-and-enumerable-lazy-uniq-part-of-ruby-2-4</id>
      <content type="html"><![CDATA[<p>In Ruby, we commonly use <code>uniq</code> method on an array to fetch the collection ofall unique elements. But there may be cases where we might need elements in ahash by virtue of uniqueness of its values.</p><p>Let's consider an example of countries that have hosted the Olympics. We onlywant to know when was the first time a country hosted it.</p><pre><code class="language-ruby"># given object{ 1896 =&gt; 'Athens',  1900 =&gt; 'Paris',  1904 =&gt; 'Chicago',  1906 =&gt; 'Athens',  1908 =&gt; 'Rome' }# expected outcome{ 1896 =&gt; 'Athens',  1900 =&gt; 'Paris',  1904 =&gt; 'Chicago',  1908 =&gt; 'Rome' }</code></pre><p>One way to achieve this is to have a collection of unique country names and thencheck if that value is already taken while building the result.</p><pre><code class="language-ruby">olympics ={ 1896 =&gt; 'Athens',  1900 =&gt; 'Paris',  1904 =&gt; 'Chicago',  1906 =&gt; 'Athens',  1908 =&gt; 'Rome' }unique_nations = olympics.values.uniqolympics.select{ |year, country| !unique_nations.delete(country).nil? }#=&gt; {1896=&gt;&quot;Athens&quot;, 1900=&gt;&quot;Paris&quot;, 1904=&gt;&quot;Chicago&quot;, 1908=&gt;&quot;Rome&quot;}</code></pre><p>As we can see, the above code requires constructing an additional array<code>unique_nations</code>.</p><p>In processing larger data, loading an array of considerably big size in memoryand then carrying out further processing on it, may result in performance andmemory issues.</p><p>In Ruby 2.4, <code>Enumerable</code> class introduces <code>uniq</code><a href="https://bugs.ruby-lang.org/issues/11090">method</a> that collects unique elementswhile iterating over the enumerable object.</p><p>The usage is similar to that of Array#uniq. Uniqueness can be determined by theelements themselves or by a value yielded by the block passed to the <code>uniq</code>method.</p><pre><code class="language-ruby">olympics = {1896 =&gt; 'Athens', 1900 =&gt; 'Paris', 1904 =&gt; 'Chicago', 1906 =&gt; 'Athens', 1908 =&gt; 'Rome'}olympics.uniq { |year, country| country }.to_h#=&gt; {1896=&gt;&quot;Athens&quot;, 1900=&gt;&quot;Paris&quot;, 1904=&gt;&quot;Chicago&quot;, 1908=&gt;&quot;Rome&quot;}</code></pre><p>Similar method is also implemented in <code>Enumerable::Lazy</code> class. Hence we can nowcall <code>uniq</code> on lazy enumerables.</p><pre><code class="language-ruby">(1..Float::INFINITY).lazy.uniq { |x| (x**2) % 10 }.first(6)#=&gt; [1, 2, 3, 4, 5, 10]</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 optimized lstrip & strip for ASCII strings]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-has-optimized-lstrip-and-strip-methods"/>
      <updated>2017-03-14T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-has-optimized-lstrip-and-strip-methods</id>
      <content type="html"><![CDATA[<p>Ruby has <code>lstrip</code> and <code>rstrip</code> methods which can be used to remove leading andtrailing whitespaces respectively from a string.</p><p>Ruby also has <code>strip</code> method which is a combination of lstrip and rstrip and canbe used to remove both, leading and trailing whitespaces, from a string.</p><pre><code class="language-ruby">&quot;    Hello World    &quot;.lstrip    #=&gt; &quot;Hello World    &quot;&quot;    Hello World    &quot;.rstrip    #=&gt; &quot;    Hello World&quot;&quot;    Hello World    &quot;.strip     #=&gt; &quot;Hello World&quot;</code></pre><p>Prior to Ruby 2.4, the <code>rstrip</code> method was optimized for performance, but the<code>lstrip</code> and <code>strip</code> were somehow missed. In Ruby 2.4, <code>String#lstrip</code> and<code>String#strip</code> methods too have been<a href="https://bugs.ruby-lang.org/issues/12788">optimized</a> to get the performancebenefit of <code>String#rstrip</code> .</p><p>Let's run following snippet in Ruby 2.3 and Ruby 2.4 to benchmark and comparethe performance improvement.</p><pre><code class="language-ruby">require 'benchmark/ips'Benchmark.ips do |bench|  str1 = &quot; &quot; * 10_000_000 + &quot;hello world&quot; + &quot; &quot; * 10_000_000  str2 = str1.dup  str3 = str1.dup  bench.report('String#lstrip') do    str1.lstrip  end  bench.report('String#rstrip') do    str2.rstrip  end  bench.report('String#strip') do    str3.strip  endend</code></pre><h4>Result for Ruby 2.3</h4><pre><code class="language-ruby">Warming up --------------------------------------       String#lstrip     1.000  i/100ms       String#rstrip     8.000  i/100ms        String#strip     1.000  i/100msCalculating -------------------------------------       String#lstrip     10.989  ( 0.0%) i/s -     55.000  in   5.010903s       String#rstrip     92.514  ( 5.4%) i/s -    464.000  in   5.032208s        String#strip     10.170  ( 0.0%) i/s -     51.000  in   5.022118s</code></pre><h4>Result for Ruby 2.4</h4><pre><code class="language-ruby">Warming up --------------------------------------       String#lstrip    14.000  i/100ms       String#rstrip     8.000  i/100ms        String#strip     6.000  i/100msCalculating -------------------------------------       String#lstrip    143.424  ( 4.2%) i/s -    728.000  in   5.085311s       String#rstrip     89.150  ( 5.6%) i/s -    448.000  in   5.041301s        String#strip     67.834  ( 4.4%) i/s -    342.000  in   5.051584s</code></pre><p>From the above results, we can see that in Ruby 2.4, <code>String#lstrip</code> is around14x faster while <code>String#strip</code> is around 6x faster. <code>String#rstrip</code> asexpected, has nearly the same performance as it was already optimized inprevious versions.</p><h3>Performance remains same for multi-byte strings</h3><p>Strings can have single byte or multi-byte characters.</p><p>For example <code>L Hello World</code> is a multi-byte string because of the presence of<code></code> which is a multi-byte character.</p><pre><code class="language-ruby">'e'.bytesize        #=&gt; 1''.bytesize        #=&gt; 2</code></pre><p>Let's do performance benchmarking with string <code>L hello world</code> instead of<code>hello world</code>.</p><h4>Result for Ruby 2.3</h4><pre><code class="language-ruby">Warming up --------------------------------------       String#lstrip     1.000  i/100ms       String#rstrip     1.000  i/100ms        String#strip     1.000  i/100msCalculating -------------------------------------       String#lstrip     11.147  ( 9.0%) i/s -     56.000  in   5.034363s       String#rstrip      8.693  ( 0.0%) i/s -     44.000  in   5.075011s        String#strip      5.020  ( 0.0%) i/s -     26.000  in   5.183517s</code></pre><h4>Result for Ruby 2.4</h4><pre><code class="language-ruby">Warming up --------------------------------------       String#lstrip     1.000  i/100ms       String#rstrip     1.000  i/100ms        String#strip     1.000  i/100msCalculating -------------------------------------       String#lstrip     10.691  ( 0.0%) i/s -     54.000  in   5.055101s       String#rstrip      9.524  ( 0.0%) i/s -     48.000  in   5.052678s        String#strip      4.860  ( 0.0%) i/s -     25.000  in   5.152804s</code></pre><p>As we can see, the performance for multi-byte strings is almost the same acrossRuby 2.3 and Ruby 2.4.</p><h4>Explanation</h4><p>The optimization introduced is related to how the strings are parsed to detectfor whitespaces. Checking for whitespaces in multi-byte string requires anadditional overhead. So the <a href="https://bugs.ruby-lang.org/issues/12788">patch</a>adds an initial condition to check if the string is a single byte string, and ifso, processes it separately.</p><p>In most of the cases, the strings are single byte so the performance improvementwould be visible and helpful.</p>]]></content>
    </entry><entry>
       <title><![CDATA[IO#readlines now accepts chomp flag as an argument]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/io-readlines-now-accepts-chomp-flag-as-an-argument"/>
      <updated>2017-03-07T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/io-readlines-now-accepts-chomp-flag-as-an-argument</id>
      <content type="html"><![CDATA[<p>Consider the following file which needs to be read in Ruby. We can use the<code>IO#readlines</code> method to get the lines in an array.</p><pre><code class="language-plaintext"># lotr.txtThree Rings for the Elven-kings under the sky,Seven for the Dwarf-lords in their halls of stone,Nine for Mortal Men doomed to die,One for the Dark Lord on his dark throneIn the Land of Mordor where the Shadows lie.</code></pre><h3>Ruby 2.3</h3><pre><code class="language-ruby">IO.readlines('lotr.txt')#=&gt; [&quot;Three Rings for the Elven-kings under the sky,\n&quot;, &quot;Seven for the Dwarf-lords in their halls of stone,\n&quot;, &quot;Nine for Mortal Men doomed to die,\n&quot;, &quot;One for the Dark Lord on his dark throne\n&quot;, &quot;In the Land of Mordor where the Shadows lie.&quot;]</code></pre><p>As we can see, the lines in the array have a <code>\n</code>, newline character, which isnot skipped while reading the lines. The newline character needs to be choppedin most of the cases. Prior to Ruby 2.4, it could be done in the following way.</p><pre><code class="language-ruby">IO.readlines('lotr.txt').map(&amp;:chomp)#=&gt; [&quot;Three Rings for the Elven-kings under the sky,&quot;, &quot;Seven for the Dwarf-lords in their halls of stone,&quot;, &quot;Nine for Mortal Men doomed to die,&quot;, &quot;One for the Dark Lord on his dark throne&quot;, &quot;In the Land of Mordor where the Shadows lie.&quot;]</code></pre><h3>Ruby 2.4</h3><p>Since it was a common requirement, Ruby team decided to<a href="https://bugs.ruby-lang.org/issues/12553">add</a> an optional parameter to the<code>readlines</code> method. So the same can now be achieved in Ruby 2.4 in the followingway.</p><pre><code class="language-ruby">IO.readlines('lotr.txt', chomp: true)#=&gt; [&quot;Three Rings for the Elven-kings under the sky,&quot;, &quot;Seven for the Dwarf-lords in their halls of stone,&quot;, &quot;Nine for Mortal Men doomed to die,&quot;, &quot;One for the Dark Lord on his dark throne&quot;, &quot;In the Land of Mordor where the Shadows lie.&quot;]</code></pre><p>Additionally, <code>IO#gets</code>, <code>IO#readline</code>, <code>IO#each_line</code>, <code>IO#foreach</code> methodsalso have been modified to accept an optional chomp flag.</p>]]></content>
    </entry><entry>
       <title><![CDATA[open-uri in Ruby 2.4 allows http to https redirection]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/open-uri-in-ruby-2-4-allows-http-to-https-redirection"/>
      <updated>2017-03-02T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/open-uri-in-ruby-2-4-allows-http-to-https-redirection</id>
      <content type="html"><![CDATA[<p>In Ruby 2.3, if the argument to <code>open-uri</code> is http and the host redirects tohttps , then <code>open-uri</code> would throw an error.</p><pre><code class="language-ruby">&gt; require 'open-uri'&gt; open('http://www.google.com/gmail')RuntimeError: redirection forbidden: http://www.google.com/gmail -&gt; https://www.google.com/gmail/</code></pre><p>To get around this issue, we could use<a href="https://github.com/open-uri-redirections/open_uri_redirections">open_uri_redirections</a>gem.</p><pre><code class="language-ruby">&gt; require 'open-uri'&gt; require 'open_uri_redirections'&gt; open('http://www.google.com/gmail/', :allow_redirections =&gt; :safe)=&gt; #&lt;Tempfile:/var/folders/jv/fxkfk9_10nb_964rvrszs2540000gn/T/open-uri20170228-41042-2fffoa&gt;</code></pre><h3>Ruby 2.4</h3><p>In Ruby 2.4, this issue is <a href="https://bugs.ruby-lang.org/issues/859">fixed</a>. Sonow http to https redirection is possible using open-uri.</p><pre><code class="language-ruby">&gt; require 'open-uri'&gt; open('http://www.google.com/gmail')=&gt; #&lt;Tempfile:/var/folders/jv/fxkfk9_10nb_964rvrszs2540000gn/T/open-uri20170228-41077-1bkm1dv&gt;</code></pre><p>Note that redirection from https to http will raise an error, like it did inprevious versions, since that has possible security concerns.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 now has Dir.empty? and File.empty? methods]]></title>
       <author><name>Ratnadeep Deshmane</name></author>
      <link href="https://www.bigbinary.com/blog/dir-emtpy-included-in-ruby-2-4"/>
      <updated>2017-02-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/dir-emtpy-included-in-ruby-2-4</id>
      <content type="html"><![CDATA[<p>In Ruby, to check if a given directory is empty or not, we check it as</p><pre><code class="language-ruby">Dir.entries(&quot;/usr/lib&quot;).size == 2       #=&gt; falseDir.entries(&quot;/home&quot;).size == 2          #=&gt; true</code></pre><p>Every directory in Unix filesystem contains at least two entries. These are<code>.</code>(current directory) and <code>..</code>(parent directory).</p><p>Hence, the code above checks if there are only two entries and if so, consider adirectory empty.</p><p>Again, this code only works for UNIX filesystems and fails on Windows machines,as Windows directories don't have <code>.</code> or <code>..</code>.</p><h2>Dir.empty?</h2><p>Considering all this, Ruby has finally<a href="https://bugs.ruby-lang.org/issues/10121">included</a> a new method <code>Dir.empty?</code>that takes directory path as argument and returns boolean as an answer.</p><p>Here is an example.</p><pre><code class="language-ruby">Dir.empty?('/Users/rtdp/Documents/posts')   #=&gt; true</code></pre><p>Most importantly this method works correctly in all platforms.</p><h2>File.empty?</h2><p>To check if a file is empty, Ruby has <code>File.zero?</code> method. This checks if thefile exists and has zero size.</p><pre><code class="language-ruby">File.zero?('/Users/rtdp/Documents/todo.txt')    #=&gt; true</code></pre><p>After introducing <code>Dir.empty?</code> it makes sense to<a href="https://bugs.ruby-lang.org/issues/9969">add</a> <code>File.empty?</code> as an alias to<code>File.zero?</code></p><pre><code class="language-ruby">File.empty?('/Users/rtdp/Documents/todo.txt')    #=&gt; true</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 Integer#digits extract digits in place-value]]></title>
       <author><name>Rohit Kumar</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-implements-integer-digits-for-extracting-digits-in-place-value-notation"/>
      <updated>2017-02-23T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-implements-integer-digits-for-extracting-digits-in-place-value-notation</id>
      <content type="html"><![CDATA[<p>If we want to extract all the digits of an integer<a href="https://en.wikipedia.org/wiki/Positional_notation">from right to left</a>, thenewly added <a href="https://bugs.ruby-lang.org/issues/12447">Integer#digits</a> methodwill come in handy.</p><pre><code class="language-ruby">567321.digits#=&gt; [1, 2, 3, 7, 6, 5]567321.digits[3]#=&gt; 7</code></pre><p>We can also supply a different base as an argument.</p><pre><code class="language-ruby">0123.digits(8)#=&gt; [3, 2, 1]0xabcdef.digits(16)#=&gt; [15, 14, 13, 12, 11, 10]</code></pre><h4>Use case of digits</h4><p>We can use <code>Integer#digits</code> to sum all the digits in an integer.</p><pre><code class="language-ruby">123.to_s.chars.map(&amp;:to_i).sum#=&gt; 6123.digits.sum#=&gt; 6</code></pre><p>Also while calculating checksums like<a href="https://en.wikipedia.org/wiki/Luhn_algorithm">Luhn</a> and<a href="https://en.wikipedia.org/wiki/Verhoeff_algorithm">Verhoeff</a>, <code>Integer#digits</code>will help in reducing string allocation.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 adds compare by identity functionality]]></title>
       <author><name>Chirag Shah</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-adds-compare-by-identity-functionality-for-sets"/>
      <updated>2016-12-29T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-adds-compare-by-identity-functionality-for-sets</id>
      <content type="html"><![CDATA[<p>In Ruby, <code>Object#equal?</code> method is used to compare two objects by theiridentity, that is, the two objects are exactly the same or not. Ruby also has<code>Object#eql?</code> method which returns true if two objects have the same value.</p><p>For example:</p><pre><code class="language-ruby">str1 = &quot;Sample string&quot;str2 = str1.dupstr1.eql?(str2) #=&gt; truestr1.equal?(str2) #=&gt; false</code></pre><p>We can see that object ids of the objects are not same.</p><pre><code class="language-ruby">str1.object_id #=&gt; 70334175057920str2.object_id #=&gt; 70334195702480</code></pre><p>In ruby, <a href="http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html">Set</a> doesnot allow duplicate items in its collection. To determine if two items are equalor not in a <code>Set</code> ruby uses <code>Object#eql?</code> and not <code>Object#equal?</code>.</p><p>So if we want to add two different objects with the same values in a set, thatwould not have been possible prior to Ruby 2.4 .</p><h3>Ruby 2.3</h3><pre><code class="language-ruby">require 'set'set = Set.new #=&gt; #&lt;Set: {}&gt;str1 = &quot;Sample string&quot; #=&gt; &quot;Sample string&quot;str2 = str1.dup #=&gt; &quot;Sample string&quot;set.add(str1) #=&gt; #&lt;Set: {&quot;Sample string&quot;}&gt;set.add(str2) #=&gt; #&lt;Set: {&quot;Sample string&quot;}&gt;</code></pre><p>But with the new<a href="http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html#method-i-compare_by_identity">Set#compare_by_identity method introduced in Ruby 2.4</a>,sets can now compare its values using <code>Object#equal?</code> and check for the exactsame objects.</p><h3>Ruby 2.4</h3><pre><code class="language-ruby">require 'set'set = Set.new.compare_by_identity #=&gt; #&lt;Set: {}&gt;str1 = &quot;Sample string&quot; #=&gt; &quot;Sample string&quot;str2 = str1.dup #=&gt; &quot;Sample string&quot;set.add(str1) #=&gt; #&lt;Set: {&quot;Sample string&quot;}&gt;set.add(str2) #=&gt; #&lt;Set: {&quot;Sample string&quot;, &quot;Sample string&quot;}&gt;</code></pre><h2>Set#compare_by_identity?</h2><p>Ruby 2.4 also provides the<a href="http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html#method-i-compare_by_identity-3F">compare_by_identity? method</a>to know if the set will compare its elements by their identity.</p><pre><code class="language-ruby">require 'set'set1= Set.new #=&gt; #&lt;Set: {}&gt;set2= Set.new.compare_by_identity #=&gt; #&lt;Set: {}&gt;set1.compare_by_identity? #=&gt; falseset2.compare_by_identity? #=&gt; true</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 MatchData#values_at]]></title>
       <author><name>Rohit Kumar</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2.4-adds-matchdata-values-at-for-extracting-named-and-positional-capture-groups"/>
      <updated>2016-12-21T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2.4-adds-matchdata-values-at-for-extracting-named-and-positional-capture-groups</id>
      <content type="html"><![CDATA[<h3>Ruby 2.3</h3><p>We can use <code>MatchData#[]</code> to extract named capture and positional capturegroups.</p><pre><code class="language-ruby">pattern=/(?&lt;number&gt;\d+) (?&lt;word&gt;\w+)/pattern.match('100 thousand')[:number]#=&gt; &quot;100&quot;pattern=/(\d+) (\w+)/pattern.match('100 thousand')[2]#=&gt; &quot;thousand&quot;</code></pre><p>Positional capture groups could also be extracted using <code>MatchData#values_at</code>.</p><pre><code class="language-ruby">pattern=/(\d+) (\w+)/pattern.match('100 thousand').values_at(2)#=&gt; [&quot;thousand&quot;]</code></pre><h3>Changes in Ruby 2.4</h3><p>In Ruby 2.4, we can pass string or symbol to extract named capture groups tomethod <code>#values_at</code>.</p><pre><code class="language-ruby">pattern=/(?&lt;number&gt;\d+) (?&lt;word&gt;\w+)/pattern.match('100 thousand').values_at(:number)#=&gt; [&quot;100&quot;]</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 adds infinite? and finite? methods to Numeric]]></title>
       <author><name>Abhishek Jain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-adds-infinite-method-to-numeric"/>
      <updated>2016-12-19T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-adds-infinite-method-to-numeric</id>
      <content type="html"><![CDATA[<h3>Prior to Ruby 2.4</h3><p>Prior to Ruby 2.4, Float and BigDecimal responded to methods <code>infinite?</code> and<code>finite?</code>, whereas Fixnum and Bignum did not.</p><h4>Ruby 2.3</h4><pre><code class="language-ruby">#infinite?5.0.infinite?=&gt; nilFloat::INFINITY.infinite?=&gt; 15.infinite?NoMethodError: undefined method `infinite?' for 5:Fixnum</code></pre><pre><code class="language-ruby">#finite?5.0.finite?=&gt; true5.finite?NoMethodError: undefined method `finite?' for 5:Fixnum</code></pre><h4>Ruby 2.4</h4><p>To make behavior for all the numeric values to be consistent,<a href="https://bugs.ruby-lang.org/issues/12039">infinite? and finite? were added to Fixnum and Bignum</a>even though they would always return nil.</p><p>This gives us ability to call these methods irrespective of whether they aresimple numbers or floating numbers.</p><pre><code class="language-ruby">#infinite?5.0.infinite?=&gt; nilFloat::INFINITY.infinite?=&gt; 15.infinite?=&gt; nil</code></pre><pre><code class="language-ruby">#finite?5.0.finite?=&gt; true5.finite?=&gt; true</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 adds Comparable#clamp method]]></title>
       <author><name>Abhishek Jain</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-adds-comparable-clamp-method"/>
      <updated>2016-12-13T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-adds-comparable-clamp-method</id>
      <content type="html"><![CDATA[<p>In Ruby 2.4,<a href="https://bugs.ruby-lang.org/issues/10594">clamp method is added to the Comparable module</a>.This method can be used to clamp an object within a specific range of values.</p><p><code>clamp</code> method takes min and max as two arguments to define the range of valuesin which the given argument should be clamped.</p><h4>Clamping numbers</h4><p><code>clamp</code> can be used to keep a number within the range of min, max.</p><pre><code class="language-ruby">10.clamp(5, 20)=&gt; 1010.clamp(15, 20)=&gt; 1510.clamp(0, 5)=&gt; 5</code></pre><h4>Clamping strings</h4><p>Similarly, strings can also be clamped within a range.</p><pre><code class="language-ruby">&quot;e&quot;.clamp(&quot;a&quot;, &quot;s&quot;)=&gt; &quot;e&quot;&quot;e&quot;.clamp(&quot;f&quot;, &quot;s&quot;)=&gt; &quot;f&quot;&quot;e&quot;.clamp(&quot;a&quot;, &quot;c&quot;)=&gt; &quot;c&quot;&quot;this&quot;.clamp(&quot;thief&quot;, &quot;thin&quot;)=&gt; &quot;thin&quot;</code></pre><p>Internally, this method relies on applying the<a href="https://en.wikipedia.org/wiki/Three-way_comparison">spaceship &lt;=&gt; operator</a>between the object and the min &amp; max arguments.</p><pre><code class="language-ruby">if x &lt;=&gt; min &lt; 0, x = min;if x &lt;=&gt; max &gt; 0 , x = maxelse x</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[New liberal_parsing option for parsing bad CSV data]]></title>
       <author><name>Ershad Kunnakkadan</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-introduces-liberal_parsing-option-for-parsing-bad-csv-data"/>
      <updated>2016-11-22T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-introduces-liberal_parsing-option-for-parsing-bad-csv-data</id>
      <content type="html"><![CDATA[<p>Comma-Separated Values (CSV) is a widely used data format and almost everylanguage has a module to parse it. In Ruby, we have<a href="http://ruby-doc.org/stdlib-2.3.2/libdoc/csv/rdoc/CSV.html">CSV class</a> to dothat.</p><p>According to <a href="https://tools.ietf.org/html/rfc4180#page-4">RFC 4180</a>, we cannothave unescaped double quotes in CSV input since such data can't be parsed.</p><p>We get <code>MalformedCSVError</code> error when the CSV data does not conform to RFC 4180.</p><p>Ruby 2.4 has added a<a href="https://bugs.ruby-lang.org/issues/11839">liberal parsing option</a> to parse suchbad data. When it is set to <code>true</code>, Ruby will try to parse the data even whenthe data does not conform to RFC 4180.</p><pre><code class="language-ruby"># Before Ruby 2.4&gt; CSV.parse_line('one,two&quot;,three,four')CSV::MalformedCSVError: Illegal quoting in line 1.# With Ruby 2.4&gt; CSV.parse_line('one,two&quot;,three,four', liberal_parsing: true)=&gt; [&quot;one&quot;, &quot;two\&quot;&quot;, &quot;three&quot;, &quot;four&quot;]</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Enumerable#chunk not mandatory in Ruby 2.4]]></title>
       <author><name>Abhishek Jain</name></author>
      <link href="https://www.bigbinary.com/blog/passing-block-with-enumerable-chunk-is-not-mandatory-in-ruby-2-4"/>
      <updated>2016-11-21T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/passing-block-with-enumerable-chunk-is-not-mandatory-in-ruby-2-4</id>
      <content type="html"><![CDATA[<p><a href="https://ruby-doc.org/core-2.3.2/Enumerable.html#method-i-chunk">Enumerable#chunk</a>method can be used on enumerator object to group consecutive items based on thevalue returned from the block passed to it.</p><pre><code class="language-ruby">[1, 4, 7, 10, 2, 6, 15].chunk { |item| item &gt; 5 }.each { |values| p values }=&gt; [false, [1, 4]][true, [7, 10]][false, [2]][true, [6, 15]]</code></pre><p>Prior to Ruby 2.4, passing a block to <code>chunk</code> method was must.</p><pre><code class="language-ruby">array = [1,2,3,4,5,6]array.chunk=&gt; ArgumentError: no block given</code></pre><h3>Enumerable#chunk without block in Ruby 2.4</h3><p>In Ruby 2.4, we will be able to use<a href="https://bugs.ruby-lang.org/issues/2172">chunk without passing block</a>. It justreturns the enumerator object which we can use to chain further operations.</p><pre><code class="language-ruby">array = [1,2,3,4,5,6]array.chunk=&gt; &lt;Enumerator: [1, 2, 3, 4, 5, 6]:chunk&gt;</code></pre><h3>Reasons for this change</h3><p>Let's take the<a href="http://stackoverflow.com/questions/8621733/how-do-i-summarize-array-of-integers-as-an-array-of-ranges">case of listing</a>consecutive integers in an array of ranges.</p><pre><code class="language-ruby"># Before Ruby 2.4integers = [1,2,4,5,6,7,9,13]integers.enum_for(:chunk).with_index { |x, idx| x - idx }.map do |diff, group|  [group.first, group.last]end=&gt; [[1,2],[4,7],[9,9],[13,13]]</code></pre><p>We had to use<a href="http://ruby-doc.org/core-2.3.2/Object.html#method-i-enum_for">enum_for</a> here as<code>chunk</code> can't be called without block.</p><p><code>enum_for</code> creates a new enumerator object which will enumerate by calling themethod passed to it. In this case the method passed was <code>chunk</code>.</p><p>With Ruby 2.4, we can use <code>chunk</code> method directly without using <code>enum_for</code> as itdoes not require a block to be passed.</p><pre><code class="language-ruby"># Ruby 2.4integers = [1,2,4,5,6,7,9,13]integers.chunk.with_index { |x, idx| x - idx }.map do |diff, group|  [group.first, group.last]end=&gt; [[1,2],[4,7],[9,9],[13,13]]</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 unifies Fixnum and Bignum into Integer]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-unifies-fixnum-and-bignum-into-integer"/>
      <updated>2016-11-18T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-unifies-fixnum-and-bignum-into-integer</id>
      <content type="html"><![CDATA[<p>Ruby uses <code>Fixnum</code> class for representing small numbers and <code>Bignum</code> class forbig numbers.</p><pre><code class="language-ruby"># Before Ruby 2.41.class         #=&gt; Fixnum(2 ** 62).class #=&gt; Bignum</code></pre><p>In general routine work we don't have to worry about whether the number we aredealing with is <code>Bignum</code> or <code>Fixnum</code>. It's just an implementation detail.</p><p>Interestingly, Ruby also has <code>Integer</code> class which is superclass for <code>Fixnum</code>and <code>Bignum</code>.</p><p>Starting with Ruby 2.4, Fixnum and Bignum<a href="https://bugs.ruby-lang.org/issues/12005">are unified into Integer</a>.</p><pre><code class="language-ruby"># Ruby 2.41.class         #=&gt; Integer(2 ** 62).class #=&gt; Integer</code></pre><p>Starting with Ruby 2.4 usage of Fixnum and Bignum constants<a href="https://bugs.ruby-lang.org/issues/12739">is deprecated</a>.</p><pre><code class="language-ruby"># Ruby 2.4&gt;&gt; Fixnum(irb):6: warning: constant ::Fixnum is deprecated=&gt; Integer&gt;&gt; Bignum(irb):7: warning: constant ::Bignum is deprecated=&gt; Integer</code></pre><h2>How to know if a number is Fixnum, Bignum or Integer?</h2><p>We don't have to worry about this change most of the times in our applicationcode. But libraries like Rails use the class of numbers for taking certaindecisions. These libraries need to support both Ruby 2.4 and previous versionsof Ruby.</p><p>Easiest way to know whether the Ruby version is using integer unification or notis to check class of 1.</p><pre><code class="language-ruby"># Ruby 2.41.class #=&gt; Integer# Before Ruby 2.41.class #=&gt; Fixnum</code></pre><p>Look at <a href="https://github.com/rails/rails/pull/25056">PR #25056</a> to see how Railsis handling this case.</p><p>Similarly Arel is<a href="https://github.com/rails/arel/commit/dc85a6e9c74942945ad696f5da4d82490a85b865">also supporting</a>both Ruby 2.4 and previous versions of Ruby.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 implements Array#min and Array#max]]></title>
       <author><name>Rohit Kumar</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-implements-array-min-and-max"/>
      <updated>2016-11-17T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-implements-array-min-and-max</id>
      <content type="html"><![CDATA[<p>Ruby has <code>Enumerable#min</code> and <code>Enumerable#max</code> which can be used to find theminimum and the maximum value in an Array.</p><pre><code class="language-ruby">(1..10).to_a.max#=&gt; 10(1..10).to_a.method(:max)#=&gt; #&lt;Method: Array(Enumerable)#max&gt;</code></pre><p>Ruby 2.4 adds <a href="https://bugs.ruby-lang.org/issues/12172">Array#min and Array#max</a>which are much faster than <code>Enumerable#max</code> and <code>Enuermable#min</code>.</p><p>Following benchmark is based on<a href="https://blog.blockscore.com/new-features-in-ruby-2-4">https://blog.blockscore.com/new-features-in-ruby-2-4</a>.</p><pre><code class="language-ruby">Benchmark.ips do |bench|  NUM1 = 1_000_000.times.map { rand }  NUM2 = NUM1.dup  ENUM_MAX = Enumerable.instance_method(:max).bind(NUM1)  ARRAY_MAX = Array.instance_method(:max).bind(NUM2)  bench.report('Enumerable#max') do    ENUM_MAX.call  end  bench.report('Array#max') do    ARRAY_MAX.call  end  bench.compare!endWarming up --------------------------------------      Enumerable#max     1.000  i/100ms           Array#max     2.000  i/100msCalculating -------------------------------------      Enumerable#max     17.569  ( 5.7%) i/s -     88.000  in   5.026996s           Array#max     26.703  ( 3.7%) i/s -    134.000  in   5.032562sComparison:           Array#max:       26.7 i/s      Enumerable#max:       17.6 i/s - 1.52x  slowerBenchmark.ips do |bench|  NUM1 = 1_000_000.times.map { rand }  NUM2 = NUM1.dup  ENUM_MIN = Enumerable.instance_method(:min).bind(NUM1)  ARRAY_MIN = Array.instance_method(:min).bind(NUM2)  bench.report('Enumerable#min') do    ENUM_MIN.call  end  bench.report('Array#min') do    ARRAY_MIN.call  end  bench.compare!endWarming up --------------------------------------      Enumerable#min     1.000  i/100ms           Array#min     2.000  i/100msCalculating -------------------------------------      Enumerable#min     18.621  ( 5.4%) i/s -     93.000  in   5.007244s           Array#min     26.902  ( 3.7%) i/s -    136.000  in   5.064815sComparison:           Array#min:       26.9 i/s      Enumerable#min:       18.6 i/s - 1.44x  slower</code></pre><p>This benchmark shows that the new methods <code>Array#max</code> and <code>Array#min</code> are about1.5 times faster than <code>Enumerable#max</code> and <code>Enumerable#min</code>.</p><p>Similar to <code>Enumerable#max</code> and <code>Enumerable#min</code>, <code>Array#max</code> and <code>Array#min</code>also assumes that the objects use<a href="https://ruby-doc.org/core-2.3.2/Comparable.html">Comparable</a> mixin to define<code>spaceship &lt;=&gt;</code> operator for comparing the elements.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Hunting down a memory leak in shoryuken]]></title>
       <author><name>Rohit Kumar</name></author>
      <link href="https://www.bigbinary.com/blog/hunting-down-a-memory-leak-in-shoryuken"/>
      <updated>2016-11-15T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/hunting-down-a-memory-leak-in-shoryuken</id>
      <content type="html"><![CDATA[<p>This is a story of how we found and fixed memory leak in<a href="https://github.com/phstc/shoryuken/">shoryuken</a>.</p><p>We use shoryuken to process SQS messages inside of docker containers. A whileback we noticed that memory was growing without bound. After every few days, wehad to restart all the docker containers as a temporary workaround.</p><p>Since the workers were inside of a docker container we had limited tools.So we went ahead with the UNIX way of investigating the issue.</p><p>First we noticed that the number of threads inside the worker was high, 115 inour case. shoryuken boots up all the worker threads at<a href="https://github.com/phstc/shoryuken/blob/cea4f5f475b2e756f82e367152db831f9e2cc6f5/lib/shoryuken/manager.rb#L22">startup</a>.</p><pre><code class="language-ruby"># ps --no-header uH p &lt;PID&gt; | wc -l#=&gt; 115</code></pre><p>The proc filesystem exposes a lot of useful information of all the runningprocesses. ``/proc/[pid]/task` directory has information about all the threadsof a process.</p><p>Some of the threads with lower ID's were executing syscall 23<a href="http://man7.org/linux/man-pages/man2/select.2.html">(select)</a> and271 <a href="https://linux.die.net/man/2/ppoll">(ppoll)</a>.These threads were waitingfor a message to arrive in the SQS queue, but most of the threads wereexecuting syscall 202<a href="http://man7.org/linux/man-pages/man2/futex.2.html">(futex)</a>.</p><p>At this point we had an idea about the root cause of the memory leak -it was due to the workerstarting a lot of threads which were not getting terminated.We wanted to knowhow and when these threads are started.</p><p>Ruby 2.0.0 introduced <a href="http://ruby-doc.org/core-2.0.0/TracePoint.html">tracepoint</a>,which provides an interface to a lot ofinternal ruby events like when a exception is raised, when a method is called orwhen a method returns, etc.</p><p>We added the following code to our workers.</p><pre><code class="language-ruby">tc = TracePoint.new(:thread_begin, :thread_end) do |tp|  puts tp.event  puts tp.self.classendtc.enable</code></pre><p>Executing the ruby workers with tracing enabled revealed that a new<code>Celluloid::Thread</code> was being created before each method was processed and thatthread was never terminated. Hence the number of zombie threads in the workerwas growing with the number messages processed.</p><pre><code class="language-ruby">thread_beginCelluloid::Thread[development] [306203a5-3c07-4174-b974-77390e8a4fc3] SQS Message: ...snip...thread_beginCelluloid::Thread[development] [2ce2ed3b-d314-46f1-895a-f1468a8db71e] SQS Message: ...snip...</code></pre><p>Unfortunately tracepoint didn't pinpoint the place where the thread was started,hence we added a couple of puts statements to investigate the issue further.</p><p>After a lot of debugging, we were able to find that a new thread was started toincrease the <a href="https://github.com/phstc/shoryuken/blob/a40e6b26e2dfbc4a78a36198d02010dce66a977e/lib/shoryuken/middleware/server/auto_extend_visibility.rb#L48">visibility time</a>of the SQS message in a shoryuken middleware whenauto_visibility_timeout was true.</p><p>The fix was to<a href="https://github.com/phstc/shoryuken/pull/267">terminate</a>the thread after the work is done.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 Extracting captured data from Regexp results]]></title>
       <author><name>Rohit Kumar</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-adds-better-support-for-extracting-captured-data-from-regexp-match-results"/>
      <updated>2016-11-10T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-adds-better-support-for-extracting-captured-data-from-regexp-match-results</id>
      <content type="html"><![CDATA[<p>Ruby has <a href="https://ruby-doc.org/core-2.2.0/MatchData.html">MatchData</a> type whichis returned by <code>Regexp#match</code> and <code>Regexp.last_match</code>.</p><p>It has methods <code>#names</code> and <code>#captures</code> to return the names used for capturingand the actual captured data respectively.</p><pre><code class="language-ruby">pattern = /(?&lt;number&gt;\d+) (?&lt;word&gt;\w+)/match_data = pattern.match('100 thousand')#=&gt; #&lt;MatchData &quot;100 thousand&quot; number:&quot;100&quot; word:&quot;thousand&quot;&gt;&gt;&gt; match_data.names=&gt; [&quot;number&quot;, &quot;word&quot;]&gt;&gt; match_data.captures=&gt; [&quot;100&quot;, &quot;thousand&quot;]</code></pre><p>If we want all named captures in a key value pair, we have to combine the resultof names and captures.</p><pre><code class="language-ruby">match_data.names.zip(match_data.captures).to_h#=&gt; {&quot;number&quot;=&gt;&quot;100&quot;, &quot;word&quot;=&gt;&quot;thousand&quot;}</code></pre><p>Ruby 2.4 adds <a href="https://bugs.ruby-lang.org/issues/11999"><code>#named_captures</code></a> whichreturns both the name and data of the capture groups.</p><pre><code class="language-ruby">pattern=/(?&lt;number&gt;\d+) (?&lt;word&gt;\w+)/match_data = pattern.match('100 thousand')match_data.named_captures#=&gt; {&quot;number&quot;=&gt;&quot;100&quot;, &quot;word&quot;=&gt;&quot;thousand&quot;}</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 Regexp#match? not polluting global variables]]></title>
       <author><name>Rohit Kumar</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-implements-regexp-match-without-polluting-global-variables"/>
      <updated>2016-11-04T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-implements-regexp-match-without-polluting-global-variables</id>
      <content type="html"><![CDATA[<p>Ruby has many ways to match with a regular expression.</p><h4>Regexp#===</h4><p>It returns true/false and sets the $~ global variable.</p><pre><code class="language-ruby">/stat/ === &quot;case statements&quot;#=&gt; true$~#=&gt; #&lt;MatchData &quot;stat&quot;&gt;</code></pre><h3>Regexp#=~</h3><p>It returns integer position it matched or nil if no match. It also sets the $~global variable.</p><pre><code class="language-ruby">/stat/ =~ &quot;case statements&quot;#=&gt; 5$~#=&gt; #&lt;MatchData &quot;stat&quot;&gt;</code></pre><h3>Regexp#match</h3><p>It returns match data and also sets the $~ global variable.</p><pre><code class="language-ruby">/stat/.match(&quot;case statements&quot;)#=&gt; #&lt;MatchData &quot;stat&quot;&gt;$~#=&gt; #&lt;MatchData &quot;stat&quot;&gt;</code></pre><h3>Ruby 2.4 adds Regexp#match?</h3><p><a href="https://bugs.ruby-lang.org/issues/8110">This new method</a> just returnstrue/false and does not set any global variables.</p><pre><code class="language-ruby">/case/.match?(&quot;case statements&quot;)#=&gt; true</code></pre><p>So <code>Regexp#match?</code> is good option when we are only concerned with the fact thatregex matches or not.</p><p><code>Regexp#match?</code> is also faster than its counterparts as it reduces objectallocation by not creating a back reference and changing <code>$~</code>.</p><pre><code class="language-ruby">require 'benchmark/ips'Benchmark.ips do |bench|  EMAIL_ADDR = 'disposable.style.email.with+symbol@example.com'  EMAIL_REGEXP_DEVISE = /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/  bench.report('Regexp#===') do    EMAIL_REGEXP_DEVISE === EMAIL_ADDR  end  bench.report('Regexp#=~') do    EMAIL_REGEXP_DEVISE =~ EMAIL_ADDR  end  bench.report('Regexp#match') do    EMAIL_REGEXP_DEVISE.match(EMAIL_ADDR)  end  bench.report('Regexp#match?') do    EMAIL_REGEXP_DEVISE.match?(EMAIL_ADDR)  end  bench.compare!end#=&gt; Warming up --------------------------------------#=&gt;          Regexp#===   103.876k i/100ms#=&gt;           Regexp#=~   105.843k i/100ms#=&gt;        Regexp#match    58.980k i/100ms#=&gt;       Regexp#match?   107.287k i/100ms#=&gt; Calculating -------------------------------------#=&gt;          Regexp#===      1.335M ( 9.5%) i/s -      6.648M in   5.038568s#=&gt;           Regexp#=~      1.369M ( 6.7%) i/s -      6.880M in   5.049481s#=&gt;        Regexp#match    709.152k ( 5.4%) i/s -      3.539M in   5.005514s#=&gt;       Regexp#match?      1.543M ( 4.6%) i/s -      7.725M in   5.018696s#=&gt;#=&gt; Comparison:#=&gt;       Regexp#match?:  1542589.9 i/s#=&gt;           Regexp#=~:  1369421.3 i/s - 1.13x  slower#=&gt;          Regexp#===:  1335450.3 i/s - 1.16x  slower#=&gt;        Regexp#match:   709151.7 i/s - 2.18x  slower</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby 2.4 implements Enumerable#sum]]></title>
       <author><name>Mohit Natoo</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-2-4-introduces-enumerable-sum"/>
      <updated>2016-11-02T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-2-4-introduces-enumerable-sum</id>
      <content type="html"><![CDATA[<p>It is a common use case to calculate sum of the elements of an array or valuesfrom a hash.</p><pre><code class="language-ruby">[1, 2, 3, 4] =&gt; 10{a: 1, b: 6, c: -3} =&gt; 4</code></pre><p>Active Support already implements<a href="https://github.com/rails/rails/blob/3d716b9e66e334c113c98fb3fc4bcf8a945b93a1/activesupport/lib/active_support/core_ext/enumerable.rb#L2-L27">Enumerable#sum</a></p><pre><code class="language-ruby">&gt; [1, 2, 3, 4].sum #=&gt; 10&gt; {a: 1, b: 6, c: -3}.sum{ |k, v| v**2 } #=&gt; 46&gt; ['foo', 'bar'].sum # concatenation of strings #=&gt; &quot;foobar&quot;&gt; [[1], ['abc'], [6, 'qwe']].sum # concatenation of arrays #=&gt; [1, &quot;abc&quot;, 6, &quot;qwe&quot;]</code></pre><p>Until Ruby 2.3, we had to use Active Support to use <code>Enumerable#sum</code> method orwe could use <code>#inject</code> which is<a href="https://github.com/rails/rails/blob/3d716b9e66e334c113c98fb3fc4bcf8a945b93a1/activesupport/lib/active_support/core_ext/enumerable.rb#L2-L27">used by Active Support under the hood</a>.</p><p>Ruby 2.4.0 implements<a href="https://github.com/ruby/ruby/commit/41ef7ec381338a97d15a6b4b18acd8b426a9ce79">Enumerable#sum</a>as <a href="https://bugs.ruby-lang.org/issues/12217">part of the language</a> itself.</p><p>Let's take a look at how <code>sum</code> method fares on some of the enumerable objects inRuby 2.4.</p><pre><code class="language-ruby">&gt; [1, 2, 3, 4].sum #=&gt; 10&gt; {a: 1, b: 6, c: -3}.sum { |k, v| v**2 } #=&gt; 46&gt; ['foo', 'bar'].sum #=&gt; TypeError: String can't be coerced into Integer&gt; [[1], ['abc'], [6, 'qwe']].sum #=&gt; TypeError: Array can't be coerced into Integer</code></pre><p>As we can see, the behavior of <code>Enumerable#sum</code> from Ruby 2.4 is same as that ofActive Support in case of numbers but not the same in case of string or arrayconcatenation. Let's see what is the difference and how we can make it work inRuby 2.4 as well.</p><h3>Understanding addition/concatenation identity</h3><p>The <code>Enumerable#sum</code> method takes an optional argument which acts as anaccumulator. Both Active Support and Ruby 2.4 accept this argument.</p><p>When identity argument is not passed, <code>0</code> is used as default accumulator in Ruby2.4 whereas Active Support uses <code>nil</code> as default accumulator.</p><p>Hence in the cases of string and array concatenation, the error occurred in Rubybecause the code attempts to add a string and array respectively to <code>0</code>.</p><p>To overcome this, we need to pass proper addition/concatenation identity as anargument to the <code>sum</code> method.</p><p>The addition/concatenation identity of an object can be defined as the valuewith which calling <code>+</code> operation on an object returns the same object.</p><pre><code class="language-ruby">&gt; ['foo', 'bar'].sum('') #=&gt; &quot;foobar&quot;&gt; [[1], ['abc'], [6, 'qwe']].sum([]) #=&gt; [1, &quot;abc&quot;, 6, &quot;qwe&quot;]</code></pre><h3>What about Rails ?</h3><p>As we have seen earlier, Ruby 2.4 implements <code>Enumerable#sum</code> favouring numericoperations whereas also supporting non-numeric callers with the identityelement. This behavior is not entirely same as that of Active Support. But stillActive Support can make use of the native sum method whenever possible. There isalready a <a href="https://github.com/rails/rails/pull/25202">pull request</a> open whichuses <code>Enumerable#sum</code> from Ruby whenever possible. This will help gain someperformance boost as the Ruby's method is implemented natively in C whereas thatin Active Support is implemented in Ruby.</p>]]></content>
    </entry><entry>
       <title><![CDATA[String#concat, Array#concat & String#prepend Ruby 2.4]]></title>
       <author><name>Abhishek Jain</name></author>
      <link href="https://www.bigbinary.com/blog/string-array-concat-and-string-prepend-take-multiple-arguments-in-ruby-2-4"/>
      <updated>2016-10-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/string-array-concat-and-string-prepend-take-multiple-arguments-in-ruby-2-4</id>
      <content type="html"><![CDATA[<p>In Ruby, we use <code>#concat</code> to append a string to another string or an element tothe array. We can also use <code>#prepend</code> to add a string at the beginning of astring.</p><h3>Ruby 2.3</h3><h4>String#concat and Array#concat</h4><pre><code class="language-ruby">string = &quot;Good&quot;string.concat(&quot; morning&quot;)#=&gt; &quot;Good morning&quot;array = ['a', 'b', 'c']array.concat(['d'])#=&gt; [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;]</code></pre><h4>String#prepend</h4><pre><code class="language-ruby">string = &quot;Morning&quot;string.prepend(&quot;Good &quot;)#=&gt; &quot;Good morning&quot;</code></pre><p>Before Ruby 2.4, we could pass only one argument to these methods. So we couldnot add multiple items in one shot.</p><pre><code class="language-ruby">string = &quot;Good&quot;string.concat(&quot; morning&quot;, &quot; to&quot;, &quot; you&quot;)#=&gt; ArgumentError: wrong number of arguments (given 3, expected 1)</code></pre><h3>Changes with Ruby 2.4</h3><p>In Ruby 2.4, we can pass multiple arguments and Ruby processes each argument oneby one.</p><h4>String#concat and Array#concat</h4><pre><code class="language-ruby">string = &quot;Good&quot;string.concat(&quot; morning&quot;, &quot; to&quot;, &quot; you&quot;)#=&gt; &quot;Good morning to you&quot;array = ['a', 'b']array.concat(['c'], ['d'])#=&gt; [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;]</code></pre><h4>String#prepend</h4><pre><code class="language-ruby">string = &quot;you&quot;string.prepend(&quot;Good &quot;, &quot;morning &quot;, &quot;to &quot;)#=&gt; &quot;Good morning to you&quot;</code></pre><p>These methods work even when no argument is passed unlike in previous versionsof Ruby.</p><pre><code class="language-ruby">&quot;Good&quot;.concat#=&gt; &quot;Good&quot;</code></pre><h4>Difference between <code>concat</code> and shovel <code>&lt;&lt;</code> operator</h4><p>Though shovel <code>&lt;&lt;</code> operator can be used interchangeably with <code>concat</code> when weare calling it once, there is a difference in the behavior when calling itmultiple times.</p><pre><code class="language-ruby">str = &quot;Ruby&quot;str &lt;&lt; strstr#=&gt; &quot;RubyRuby&quot;str = &quot;Ruby&quot;str.concat strstr#=&gt; &quot;RubyRuby&quot;str = &quot;Ruby&quot;str &lt;&lt; str &lt;&lt; str#=&gt; &quot;RubyRubyRubyRuby&quot;str = &quot;Ruby&quot;str.concat str, strstr#=&gt; &quot;RubyRubyRuby&quot;</code></pre><p>So <code>concat</code> behaves as appending <code>present</code> content to the caller twice. Whereascalling <code>&lt;&lt;</code> twice is just sequence of binary operations. So the argument forthe second call is output of the first <code>&lt;&lt;</code> operation.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Hash#compact and Hash#compact! now part of Ruby 2.4]]></title>
       <author><name>Prathamesh Sonpatki</name></author>
      <link href="https://www.bigbinary.com/blog/hash-compact-and-hash-compact-now-part-of-ruby-2-4"/>
      <updated>2016-10-24T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/hash-compact-and-hash-compact-now-part-of-ruby-2-4</id>
      <content type="html"><![CDATA[<p>It is a common use case to remove the <code>nil</code> values from a hash in Ruby.</p><pre><code class="language-ruby">{ &quot;name&quot; =&gt; &quot;prathamesh&quot;, &quot;email&quot; =&gt; nil} =&gt; { &quot;name&quot; =&gt; &quot;prathamesh&quot; }</code></pre><p>Active Support already has a solution for this in the form of<a href="http://api.rubyonrails.org/classes/Hash.html#method-i-compact">Hash#compact</a>and<a href="http://api.rubyonrails.org/classes/Hash.html#method-i-compact-21">Hash#compact!</a>.</p><pre><code class="language-ruby">hash = { &quot;name&quot; =&gt; &quot;prathamesh&quot;, &quot;email&quot; =&gt; nil}hash.compact #=&gt; { &quot;name&quot; =&gt; &quot;prathamesh&quot; }hash #=&gt; { &quot;name&quot; =&gt; &quot;prathamesh&quot;, &quot;email&quot; =&gt; nil}hash.compact! #=&gt; { &quot;name&quot; =&gt; &quot;prathamesh&quot; }hash #=&gt; { &quot;name&quot; =&gt; &quot;prathamesh&quot; }</code></pre><p>Now, Ruby 2.4 will have these 2 methods in the<a href="https://bugs.ruby-lang.org/issues/11818">language</a><a href="https://bugs.ruby-lang.org/issues/12863">itself</a>, so even those not using Railsor Active Support will be able to use them. Additionally it will also giveperformance boost over the Active Support versions because now these methods areimplemented in C natively whereas the Active Support versions are in Ruby.</p><p>There is already a<a href="https://github.com/rails/rails/pull/26868">pull request open</a> in Rails to usethe native versions of these methods from Ruby 2.4 whenever available so that wewill be able to use the performance boost.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Configuring CircleCI for JRuby]]></title>
       <author><name>Ershad Kunnakkadan</name></author>
      <link href="https://www.bigbinary.com/blog/how-to-configure-circle-ci-for-jruby"/>
      <updated>2016-08-01T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/how-to-configure-circle-ci-for-jruby</id>
      <content type="html"><![CDATA[<p>Recently we worked with a client where we had to run a part of their multi-threaded code in JRuby for performance reasons. They have been using <a href="https://circleci.com">CircleCI</a> with MRI for running tests. In this post I will explain how we configured CircleCI to run the same tests using both JRuby and MRI.</p><p>CircleCI uses <code>circle.yml</code> file for configuration. Before configuring JRuby, this is how it looked like:</p><pre><code class="language-yaml">machine:  ruby:    version: 2.1.5dependencies:  pre:    - ./bundle_install_circle_ci.sh  cache_directories:    - &quot;~/vendor/bundle&quot;test:  override:    - ? bundle exec rspec --format progress --format documentation --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/app.xml      : parallel: true        pwd: app        files:          - spec/**/*_spec.rb</code></pre><p>&lt;br/&gt;Here are the steps to enable JRuby in CircleCI.</p><p><strong>Specify the JDK version</strong></p><p>We need to specify a JDK version before using JRuby.</p><pre><code class="language-yaml">machine:  java:    version: openjdk7</code></pre><p><strong>Install proper dependencies</strong></p><p>We needed to use JRuby 9.0.4.0 but the version of JRuby that came with Ubuntu 12.04 image of CircleCI was different. We added <code>rvm install</code> command as follows to install specific version that we wanted. Also we can configure any script (like <code>bundle install</code>) that needs to run before running tests.</p><pre><code class="language-yaml">dependencies:  pre:    - rvm install jruby-9.0.4.0    - ./bundle_install_jruby_circle_ci.sh  cache_directories:    - &quot;~/vendor/bundle&quot;</code></pre><p><strong>Configure JRuby</strong></p><p>We used <code>rvm-exec</code> to set JRuby for running tests for this particular component in the <code>test</code> section. Otherwise by default it picks up MRI.</p><pre><code class="language-yaml">test:  override:    - ? rvm-exec jruby-9.0.4.0 bash -c &quot;bundle exec rspec --format progress --format documentation --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/app_jruby.xml&quot;      : parallel: true        pwd: app        files:          - spec/**/*_spec.rb</code></pre><p><strong>Improving test runs on JRuby</strong></p><p>Once we started running tests with JRuby, we observed it was taking comparatively slower to finish all tests. Most of the time was spent in starting the JVM. We made it faster by setting <a href="https://github.com/jruby/jruby/wiki/Improving-startup-time#use-the---dev-flag"><code>--dev</code> parameter</a> in <code>JRUBY_OPTS</code> environment variable. This parameter improves JRuby boot time and it shaved more than a minute time for us.</p><pre><code class="language-yaml">machine:  environment:    JRUBY_OPTS: &quot;--dev&quot;</code></pre><p><strong>Here is the final circle.yml file:</strong></p><pre><code class="language-yaml"># circle.ymlmachine:  ruby:    version: 2.1.5  java:    version: openjdk7  environment:    JRUBY_OPTS: &quot;--dev&quot;dependencies:  pre:    - rvm install jruby-9.0.4.0    - ./bundle_install_jruby_circle_ci.sh  cache_directories:    - &quot;~/vendor/bundle&quot;test:  override:    - ? rvm-exec jruby-9.0.4.0 bash -c &quot;bundle exec rspec --format progress --format documentation --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/app_jruby.xml&quot;      : parallel: true        pwd: app        files:          - spec/**/*_spec.rb    - ? bundle exec rspec --format progress --format documentation --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/app_mri.xml      : parallel: true        pwd: app        files:          - spec/**/*_spec.rb</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Author information in jekyll blog]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/author-information-in-jekyll-blog"/>
      <updated>2015-01-09T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/author-information-in-jekyll-blog</id>
      <content type="html"><![CDATA[<p>BigBinary's <a href="https://bigbinary.com/blog">blog</a> is powered by<a href="http://jekyllrb.com">jekyll</a>. In every blog we display author's name, author'stwitter handle, author's github id and author's avatar. In this blog I'm goingto discuss how we collect all that information in a simple manner.</p><p>We create a directory called <strong>_data</strong> in the root folder. This directory has asingle file called <strong>authors.yml</strong> which in our case looks like this.</p><pre><code class="language-plaintext">vipulnsward:  name: Vipul  avatar: http://bigbinary.com/assets/team/vipul.jpg  github: vipulnsward  twitter: vipulnswardneerajsingh0101:  name: Neeraj Singh  avatar: http://bigbinary.com/assets/team/neeraj.jpg  github: neerajsingh0101  twitter: neerajsingh0101</code></pre><p>We do not need to do anything to load <strong>authors.yml</strong> . It is automaticallyloaded by jekyll.</p><p>When we create a blog then the top of the blog looks like this.</p><pre><code class="language-plaintext">---layout: posttitle: How to deploy jekyll site to herokucategories: [Ruby]author_github: neerajsingh0101---</code></pre><p>Notice the last line where we have put in the author's github id. That's theidentifier we use to pull in author's information.</p><p>In order to display author's name we have following code in the layout.</p><pre><code class="language-plaintext">{% raw %}&lt;span class=&quot;author-name&quot;&gt;  {{ site.data.authors[page.author_github].name }}&lt;/span&gt;{% endraw %}</code></pre><p>Similarly to display author's twitter handle and github id we have followingcode.</p><pre><code class="language-plaintext">{% raw %}&lt;a href=&quot;www.twitter.com/{{site.data.authors[page.author_github].twitter}}&quot;&gt;  &lt;i class=&quot;ico-twitter&quot;&gt;&lt;/i&gt;&lt;/a&gt;&lt;a href=&quot;www.github.com/{{site.data.authors[page.author_github].github}}&quot;&gt;  &lt;i class=&quot;ico-github&quot;&gt;&lt;/i&gt;&lt;/a&gt;{% endraw %}</code></pre><p>Now the blog will display the author information and all this information isnicely centralized in one single file.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Six Year Old Optional / Keyword Arguments bug]]></title>
       <author><name>Vipul</name></author>
      <link href="https://www.bigbinary.com/blog/six-years-old-optional-keyword-arguments-bug"/>
      <updated>2014-04-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/six-years-old-optional-keyword-arguments-bug</id>
      <content type="html"><![CDATA[<p>I recently conducted a workshop about <strong><em>Contributing to Open-Source</em></strong> at first-ever <a href="http://rubyconf.ph/">Rubyconf Philippines</a>. In its introductory talk,I spoke about how Aaron Patterson, fixed <a href="https://github.com/rails/rails/commit/e88da370f190cabd1e9750c5b3531735950ab415">a 6 year old bug</a>about Optional Arguments, that existed in Rails.</p><h2>Bug in ruby</h2><p>Let's try a small program.</p><pre><code class="language-ruby">class Labdef dayputs 'invoked''sunday'enddef runday = dayendendputs Lab.new.run</code></pre><p>What do you think would be printed on your terminal when you run the above program.</p><p>If you are using ruby 2.1 or below then you will see nothing. Why is that ? That's because of a bug in ruby.</p><p>This is <a href="https://bugs.ruby-lang.org/issues/9593">bug number 9593</a> in ruby issue tracker.</p><p>In the statement <code>day = day</code> the left hand side variable assignment is stopping the call to method <code>day</code>. So the method <code>day</code> is never invoked.</p><h2>Another variation of the same bug</h2><pre><code class="language-ruby">class Labdef dayputs 'invoked''sunday'enddef run( day: day)endendputs Lab.new.run</code></pre><p>In the above case we are using the keyword argument feature added in Ruby 2.0 . If you are unfamiliar with keyword arguments feature of ruby then checkout this <a href="https://www.youtube.com/watch?v=u8Q6Of_mScI">excellent video</a> by <a href="https://twitter.com/peterc">Peter Cooper</a>.</p><p>In this case again the same behavior is exhibited. The method <code>day</code> is never invoked.</p><h2>How this bug affects Rails community</h2><p>You might be thinking that I would never write code like that. Why would you have a variable name same as method name.</p><p>Well Rails had this bug because rails has code like this.</p><pre><code class="language-ruby">def has_cached_counter?(reflection = reflection)end</code></pre><p>In this case method <code>reflection</code> never got called and the variable <code>reflection</code> was always assigned nil.</p><h2>Fixing the bug</h2><p><a href="https://bugs.ruby-lang.org/users/4">Nobu</a> <a href="https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/45272">fixed</a> this bug in ruby 2.2.0. By the way Nobu is also known as &quot;ruby patch-monster&quot; because of amount of patches he applies to ruby.</p><p>So this bug is fixed in ruby 2.2.0. What about the people who are not using ruby 2.2.0.</p><p>The simple solution is not to omit the parameter. If we change the above code to</p><pre><code class="language-ruby">def has_cached_counter?(reflection = reflection())end</code></pre><p>then we are explicitly invoking the method <code>reflection</code> and the variable <code>reflection</code> will be assigned the output of method <code>reflection</code>.</p><p>And this is how <a href="https://github.com/rails/rails/commit/e88da370f190cabd1e9750c5b3531735950ab415">Aaron Patterson fixed</a> six years old bug.</p>]]></content>
    </entry><entry>
       <title><![CDATA[How to deploy jekyll site to heroku]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/deploy-jekyll-to-heroku"/>
      <updated>2014-04-27T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/deploy-jekyll-to-heroku</id>
      <content type="html"><![CDATA[<p><a href="http://jekyllrb.com">jekyll</a> is an excellent tool for creating static pages andblogs. Our <a href="https://bigbinary.com/blog">BigBinary blog</a> is based on jekyll.Deploying our blog to heroku took longer than I had expected. I am outliningwhat I did to deploy <a href="https://bigbinary.com/blog">BigBinary blog</a> to heroku.</p><h2>Add exclude vendor to _config.yml</h2><p>Open <code>_config.yml</code> and add following line at the very bottom.</p><pre><code class="language-ruby">exclude: ['vendor']</code></pre><h2>Add Procfile</h2><p>Create a new file called <code>Procfile</code> at the root of the project with followingcontent.</p><pre><code class="language-ruby">web: bundle exec jekyll build &amp;&amp; bundle exec thin start -p\$PORT -Vconsole: echo consolerake: echo rake</code></pre><h2>Add Gemfile</h2><p>Add <code>Gemfile</code> at the root of the project.</p><pre><code class="language-ruby">source 'https://rubygems.org'gem 'jekyll', '2.4.0'gem 'rake'gem 'foreman'gem 'thin'gem 'rack-contrib'</code></pre><h2>Add config.ru</h2><p>Add <code>config.ru</code> at the root of the project with following content.</p><pre><code class="language-ruby">require 'rack/contrib/try_static'use Rack::TryStatic,:root =&gt; &quot;\_site&quot;,:urls =&gt; %w[/],:try =&gt; ['.html', 'index.html', '/index.html']run lambda { |env|return [404, {'Content-Type' =&gt; 'text/html'}, ['Not Found']]}</code></pre><h2>Test on local machine first</h2><p>Test locally by executing <code>bundle exec jekyll serve</code>.</p><h2>Push code to heroku</h2><p>Now run <em>bundle install</em> and add the <em>Gemfile.lock</em> to the repository and pushthe repository to heroku.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Getting arguments passed to command]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/getting-arguments-passed-to-command"/>
      <updated>2013-09-22T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/getting-arguments-passed-to-command</id>
      <content type="html"><![CDATA[<p>In <a href="do-not-allow-force-push-to-master">previous blog</a> we discussed ruby codewhere we used <code>ps -ocommand</code>. In this blog let's discuss how to get argumentspassed to a command.</p><h2>What is the issue</h2><p>In the referred blog we are trying to find if <code>--force</code> or <code>-f</code> argument waspassed to the <code>git push</code> command.</p><p>The kernel knows the arguments that was passed to the command. So the only wayto find that answer would be to ask kernel what was the full command. The toolto deal with such issues is <code>ps</code>.</p><p>In order to play with <code>ps</code> command let's write a simple ruby program first.</p><pre><code class="language-plaintext"># sl.rbputs Process.pidputs Process.ppidsleep 99999999</code></pre><p>In terminal execute <code>ruby sl.rb</code>. In another terminal execute <code>ps</code>.</p><pre><code class="language-plaintext">$ ps  PID TTY           TIME CMD82246 ttys000    0:00.51 -bash87070 ttys000    0:00.04 ruby loop.rb a, b, c82455 ttys001    0:00.40 -bash</code></pre><p>So here I have two bash shell open in two different tabs in my terminal. Firstterminal tab is running s1.rb. The second terminal tab is running <code>ps</code>. In thesecond terminal we can see the arguments that were passed to program <code>s1</code>.</p><p>By default <code>ps</code> lists all the processes belonging to the user executing thecommand and the processes started from the current terminal.</p><h2>Option -p</h2><p><code>ps -p87070</code> would show result only for the given process id.</p><pre><code class="language-plaintext">$ ps -p 87070  PID TTY           TIME CMD87070 ttys000    0:00.04 ruby loop.rb a, b, c</code></pre><p>We can pass more than on process id.</p><pre><code class="language-plaintext">$ ps -o pid,command -p87070,82246  PID COMMAND82246 -bash87070 ruby loop.rb a, b, c</code></pre><h2>Option -o</h2><p><code>ps -o</code> can be used to select the attributes that we want to be shown. Forexample I want only pids to be shown.</p><pre><code class="language-plaintext">$ ps -o pid  PID822468707082455</code></pre><p>Now I want <code>pid</code> and <code>command</code>.</p><pre><code class="language-plaintext">$ ps -o pid,command  PID COMMAND82246 -bash87070 ruby loop.rb a, b, c82455 -bash</code></pre><p>I want result only for a certain process id.</p><pre><code class="language-plaintext">$ ps -o command -p87070COMMANDruby loop.rb a, b, c</code></pre><p>Now we have the arguments that were passed to the command. This is the code thatarticle was talking about.</p><p>For the sake of completeness let's see a few more options.</p><h2>Option -e</h2><p><code>ps -e</code> would list all processes.</p><pre><code class="language-plaintext">$ ps -e  PID TTY           TIME CMD    1 ??         2:56.20 /sbin/launchd   11 ??         0:01.90 /usr/libexec/UserEventAgent (System)   12 ??         0:02.11 /usr/libexec/kextd   14 ??         0:09.00 /usr/sbin/notifyd   15 ??         0:05.81 /usr/sbin/securityd -i   ........................................   ........................................</code></pre><h2>Option -f</h2><p><code>ps -f</code> would list a lot more attributes including <code>ppid</code>.</p><pre><code class="language-plaintext">$ ps -f  UID   PID  PPID   C STIME   TTY           TIME CMD  501 82246 82245   0  2:06PM ttys000    0:00.51 -bash  501 87070 82246   0  4:54PM ttys000    0:00.04 ruby loop.rb a, b, c  501 82455 82452   0  2:07PM ttys001    0:00.42 -bash</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[What is ppid]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/what-is-ppid"/>
      <updated>2013-09-21T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/what-is-ppid</id>
      <content type="html"><![CDATA[<p>In <a href="do-not-allow-force-push-to-master">previous blog</a> we discussed ruby codewhere we used two things: <code>ppid</code> and <code>ps -ocommand</code>. In this blog let's discuss<code>ppid</code>. <code>ps -ocommand</code> is discussed in the<a href="getting-arguments-passed-to-command">next blog</a>.</p><h2>Parent process id is ppid</h2><p>We know that every process has a process id. This is usually referred as <code>pid</code>.In *nix world every process has a parent process. And in ruby the way to getthe &quot;process id&quot; of the parent process is through <code>ppid</code>.</p><p>Let's see it in action. Time to fire up irb.</p><pre><code class="language-plaintext">irb(main):002:0&gt; Process.pid=&gt; 83132irb(main):003:0&gt; Process.ppid=&gt; 82455</code></pre><p>Now keep the irb session open and go to anther terminal tab. In this new tabexecute <code>pstree -p 83132</code></p><pre><code class="language-plaintext">$ pstree -p 83132-+= 00001 root /sbin/launchd \-+= 00151 nsingh /sbin/launchd   \-+= 00189 nsingh /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal -psn_0_45067     \-+= 82452 root login -pf nsingh       \-+= 82455 nsingh -bash         \--= 83132 nsingh irb</code></pre><p>If <code>pstree</code> is not available then you can easily install it using<code>brew install pstree</code>.</p><p>As you can see from the output the process id 83132 is at the very bottom of thetree. The parent process id is 82455 which belongs to &quot;bash shell&quot;.</p><p>In irb session when we did <code>Process.ppid</code> then we got the same value 82455.</p>]]></content>
    </entry><entry>
       <title><![CDATA[How to setup Pinch to Zoom for an image in RubyMotion]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/pinch-to-zoom-for-an-image-in-rubymotion"/>
      <updated>2013-08-27T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/pinch-to-zoom-for-an-image-in-rubymotion</id>
      <content type="html"><![CDATA[<p>In this post we will see how to build &quot;pinch to zoom&quot; functionality to zoom inan image in RubyMotion.</p><p>First let's add a <code>UIViewController</code> that is initialized with an image.</p><pre><code class="language-ruby">class ImageViewController &lt; UIViewController  def initWithImage(image)    @image = image  endend</code></pre><h2>UIScrollView and UIImageView</h2><p>Now, we will add a <code>UIScrollView</code> with frame size set to full screen size andsome other properties as listed below.</p><pre><code class="language-ruby">scrollView = UIScrollView.alloc.initWithFrame(UIScreen.mainScreen.bounds)scrollView.scrollEnabled = falsescrollView.clipsToBounds = truescrollView.contentSize = @image.sizescrollView.minimumZoomScale = 1.0scrollView.maximumZoomScale = 4.0scrollView.zoomScale = 0.3</code></pre><p>Create a new <code>UIImageView</code> and add it to the scrollView created above.</p><pre><code class="language-ruby">imageView = UIImageView.alloc.initWithImage(@image)imageView.contentMode = UIViewContentModeScaleAspectFitimageView.userInteractionEnabled = trueimageView.frame = scrollView.bounds</code></pre><p>We are setting the image view's content mode to<code>UIViewContentModeScaleAspectFit</code>. Content mode can be set to either<code>UIViewContentModeScaleToFill</code>, <code>UIViewContentModeAspectFill</code> or<code>UIViewContentModeScaleAspectFit</code> depending on what suits your app. By default,<code>contentMode</code> property for most views is set to <code>UIViewContentModeScaleToFill</code>,which causes the views contents to be scaled to fit the new frame size.<a href="https://developer.apple.com/library/ios/documentation/windowsviews/conceptual/viewpg_iphoneos/WindowsandViews/WindowsandViews.html">This Apple doc</a>explains this behavior.</p><p>We need to add the above imageView as a subview to our scrollView.</p><pre><code class="language-ruby">scrollView.addSubview(imageView)self.view.addSubview(@scrollView)</code></pre><p>This is how our controller looks with all the above additions.</p><pre><code class="language-ruby">class ImageViewController &lt; UIViewController  def initWithImage(image)    @image = image    scrollView = UIScrollView.alloc.initWithFrame(UIScreen.mainScreen.bounds)    scrollView.scrollEnabled = false    scrollView.clipsToBounds = true    scrollView.contentSize = @image.size    scrollView.minimumZoomScale = 1.0    scrollView.maximumZoomScale = 4.0    scrollView.zoomScale = 0.3    scrollView.delegate = self    imageView = UIImageView.alloc.initWithImage(@image)    imageView.contentMode = UIViewContentModeScaleToFill    imageView.userInteractionEnabled = true    imageView.frame = scrollView.bounds    init  endend</code></pre><h2>ScrollView delegate</h2><p>We must set a delegate for our scroll view to support zooming. The delegateobject must conform to the <code>UIScrollViewDelegate</code> protocol. This is the reasonwe are setting scrollView.delegate = self above. The delegate class mustimplement <code>viewForZoomingInScrollView</code> and <code>scrollViewDidZoom</code> methods.</p><pre><code class="language-ruby">def viewForZoomingInScrollView(scrollView)  scrollView.subviews.firstenddef scrollViewDidZoom(scrollView)  if scrollView.zoomScale != 1.0    scrollView.scrollEnabled = true  else    scrollView.scrollEnabled = false  endend</code></pre><p>These two methods added above allow the scrollView to support pinch to zoom.</p><h2>Supporting orientation changes</h2><p>There is one more thing to do if we want to support orientations changes. Weneed to add the following methods:</p><pre><code class="language-ruby">def shouldAutorotateToInterfaceOrientation(*)  trueenddef viewDidLayoutSubviews  @scrollView.frame = self.view.boundsend</code></pre><p>We have to set the scrollView's frame to view bounds in <code>viewDidLayoutSubviews</code>so that the scrollView frame is resized when the device orientation changes.</p><p>That's it. With all those changes now our app supports orientation change andnow we are able to pinch and zoom images.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Fix image orientation issue in RubyMotion]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/rubymotion-image-orientation"/>
      <updated>2013-08-04T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/rubymotion-image-orientation</id>
      <content type="html"><![CDATA[<p>I'm building an app using RubyMotion. When I take picture then it all looksgood. However when the picture is posted on web then the orientation of thepicture is different.</p><h2>UIImage and UIImageOrientation</h2><p><a href="https://developer.apple.com/library/ios/documentation/uikit/reference/UIImage_Class/Reference/Reference.html">UIImage</a>in iOS has a property called UIImageOrientation. Image orientation affects theway the image data is displayed when drawn. The api docs mention that bydefault, images are displayed in the <code>up</code> orientation. However, if the image hasassociated metadata (such as EXIF information), then this property contains theorientation indicated by that metadata.</p><p>After using<a href="https://developer.apple.com/library/ios/documentation/uikit/reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html">UIImagePickerController</a>to take an image using the iPhone camera, I was using BubbleWrap to send theimage to a webserver. When the image is taken in landscape/portrait mode, thenthe image appeared fine when it is viewed in the browser. But, when the image issent back via api and is shown on the iphone, the image is rotated by 90 degreesif the image is taken in portrait mode. In exif metadata, iOS incorrectly setsthe orientation to UIImageOrientationRight .</p><p>Here is how I fixed the image orientation issue:</p><pre><code class="language-ruby">if image.imageOrientation == UIImageOrientationUp  return_image = imageelse  UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)  image.drawInRect([[0,0], image.size])  normalized_image = UIImage.UIGraphicsGetImageFromCurrentImageContext  UIGraphicsEndImageContext()  return_image = normalized_imageend</code></pre><p>First, we are checking the image orientation of the image we have in hand. Ifthe image orientation is UIImageOrientationUp, we don't have to change anything.Otherwise we are redrawing the image and returning the normalized image.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Background/header for Formotion forms in RubyMotion]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/set-formotion-background-and-header"/>
      <updated>2013-06-08T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/set-formotion-background-and-header</id>
      <content type="html"><![CDATA[<p><a href="https://github.com/clayallsopp/formotion">Formotion</a> for<a href="http://www.rubymotion.com/">Rubymotion</a> makes it a breeze to create views withforms. I am building a rubymotion app and my login form uses formotion. I neededto set background color for my form and here is how you can set a backgroundcolor for a form created using Formotion.</p><pre><code class="language-ruby">class LoginViewController &lt; Formotion::FormController  def viewDidLoad    super    view = UIView.alloc.init    view.backgroundColor = 0x838E61.uicolor    self.tableView.backgroundView = view  endend</code></pre><p>After the login view is done loading, I'm creating a new UIView and setting itsbackground color. Then this UIView object is set as the background view toformotion's table view.</p><h2>Setting header image</h2><p>If you want to add some branding to the login form, you can add a image to theform's header by adding the below code to <code>viewDidLoad</code>:</p><pre><code class="language-ruby">header_image = UIImage.imageNamed('header_image_name.png')header_view = UIImageView.alloc.initWithImage(header_image)self.tableView.tableHeaderView = header_view</code></pre><p>We are creating a <code>UIImageView</code> and initializing it with the image we want toshow in the header. Now, set the tableview's tableHeaderView value to theUIImageView we created.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Handling money in ruby]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/handling-money-in-ruby"/>
      <updated>2013-01-14T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/handling-money-in-ruby</id>
      <content type="html"><![CDATA[<p>In ruby do not use float for calculation since float is not good for precisecalculation.</p><pre><code class="language-ruby">irb(main):001:0&gt; 200 * (7.0/100)=&gt; 14.000000000000002</code></pre><p>7 % of 200 should be 14. But float is returning <code>14.000000000000002</code> .</p><p>In order to ensure that calculation is right make sure that all the actorsparticipating in calculation is of class<a href="http://www.ruby-doc.org/stdlib-1.9.3/libdoc/bigdecimal/rdoc/BigDecimal.html">BigDecimal</a>. Here is how same operation can be performed using BigDecimal .</p><pre><code class="language-ruby">irb(main):003:0&gt; result = BigDecimal.new(200) * ( BigDecimal.new(7)/BigDecimal.new(100))=&gt; #&lt;BigDecimal:7fa5eefa1720,'0.14E2',9(36)&gt;irb(main):004:0&gt; result.to_s=&gt; &quot;14.0&quot;</code></pre><p>As we can see BigDecimal brings much more accurate result.</p><h2>Converting money to cents</h2><p>In order to charge the credit card using <a href="https://stripe.com/">Stripe</a> we neededto have the amount to be charged in cents. One way to convert the value in centswould be</p><pre><code class="language-ruby">amount  = BigDecimal.new(200) * ( BigDecimal.new(7)/BigDecimal.new(100))puts (amount * 100).to_i #=&gt; 1400</code></pre><p>Above method works but I like to delegate the functionality of making money outof a complex BigDecimal value to gem like<a href="https://rubygems.org/gems/money">money</a> . In this project we are using<a href="https://rubygems.org/gems/activemerchant">activemerchant</a> which depends onmoney gem . So we get money gem for free. You might have to add money gem toGemfile if you want to use following technique.</p><p>money gem lets you get a money instance out of BigDecimal.</p><pre><code class="language-ruby">amount  = BigDecimal.new(200) * ( BigDecimal.new(7)/BigDecimal.new(100))amount_in_money = amount.to_moneyputs amount_in_money.cents #=&gt; 1400</code></pre><h2>Stay in BigDecimal or money mode for calculation</h2><p>If you are doing any sort of calculation then all participating elements must beeither BigDecimal or Money instance. It is best if all the elements are of thesame type.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Executing shell commands in ruby]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/backtick-system-exec-in-ruby"/>
      <updated>2012-10-18T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/backtick-system-exec-in-ruby</id>
      <content type="html"><![CDATA[<p>Ruby allows many different ways to execute a command or a sub-process. In thisarticle we are going to see some of them.</p><h2>backtick</h2><h4>1. Returns standard output</h4><p><a href="http://ruby-doc.org/core-1.9.3/Kernel.html#method-i-60">backtick</a> returns thestandard output(<code>stdout</code>) of the operation.</p><pre><code class="language-ruby">output = `pwd`puts &quot;output is #{output}&quot;</code></pre><pre><code class="language-ruby">$ ruby main.rboutput is /Users/neerajsingh/code/misc</code></pre><p>backtick does not capture <code>STDERR</code> . If you want to learn about <code>STDERR</code> thencheckout this<a href="https://www.howtogeek.com/435903/what-are-stdin-stdout-and-stderr-on-linux/">excellent article</a>.</p><p>You can redirect <code>STDERR</code> to <code>STDOUT</code> if you want to capture <code>STDERR</code> usingbacktick.</p><pre><code class="language-ruby">output = `grep hosts /private/etc/* 2&gt;&amp;1`</code></pre><h4>2. Exception is passed on to the main program</h4><p>Backtick operation forks the master process and the operation is executed in anew process. If there is an exception in the sub-process then that exception isgiven to the main process and the main process might terminate if exception isnot handled.</p><p>In the following case I am executing <code>xxxxx</code> which is not a valid executablename.</p><pre><code class="language-ruby">output = `xxxxxxx`puts &quot;output is #{output}&quot;</code></pre><p>Result of above code is given below. Notice that <code>puts</code> was never executedbecause the backtick operation raised exception.</p><pre><code class="language-ruby">$ ruby main.rbmain.rb:1:in ``': No such file or directory - xxxxxxx (Errno::ENOENT)from main.rb:1:in `&lt;main&gt;'</code></pre><h4>3. Blocking operation</h4><p>Backtick is a blocking operation. The main application waits until the result ofbacktick operation completes.</p><h4>4. Checking the status of the operation</h4><p>To check the status of the backtick operation you can execute <code>$?.success?</code></p><pre><code class="language-ruby">output = `ls`puts &quot;output is #{output}&quot;puts $?.success?</code></pre><p>Notice that the last line of the result contains <code>true</code> because the backtickoperation was a success.</p><pre><code class="language-ruby">$ ruby main.rboutput is lab.rbmain.rbtrue</code></pre><h4>5. String interpolation is allowed within the ticks</h4><pre><code class="language-ruby">cmd = 'ls'`#{cmd}`</code></pre><h4>6. Different delimiter and string interpolation</h4><p><code>%x</code> does the same thing as backtick. It allows you to have different delimiter.</p><pre><code class="language-ruby">output = %x[ ls ]output = %x{ ls }</code></pre><p>backtick runs the command in subshell. So shell features like stringinterpolation and wild card can be used. Here is an example.</p><pre><code class="language-ruby">$ irb&gt; dir = '/etc'&gt; %x&lt;ls -al #{dir}&gt;=&gt; &quot;lrwxr-xr-x@ 1 root  wheel  11 Jan  5 21:10 /etc -&gt; private/etc&quot;</code></pre><p>If you are building a script which you mean to run on your laptops and not onserver then most likely if there is an exception then you want the script toabort. For such cases <code>backtick</code> is the best choice.</p><p>For example let's say that I want to write a script to make my repo up-to-dateautomatically. The command would be something like this.</p><pre><code>cd directory_name &amp;&amp; git checkout main &amp;&amp; git pull origin main</code></pre><p>If there is any error while executing this command then you want to have thefull access to the exception so that you could debug. In such cases the best wayto execute this command is as shown below.</p><pre><code>cmd = &quot;cd #{directory_name} &amp;&amp; git checkout main &amp;&amp; git pull origin main&quot;%x[ cmd ]</code></pre><h2>system</h2><p>The <a href="http://ruby-doc.org/core-1.9.3/Kernel.html#M005971">system</a> command runs ina subshell.</p><p>Just like <code>backtick</code>, <code>system</code> is a blocking operation.</p><p>Since <code>system</code> command runs in a subshell it eats up all the exceptions. So themain operation never needs to worry about capturing an exception raised from thechild process.</p><pre><code class="language-ruby">output = system('xxxxxxx')puts &quot;output is #{output}&quot;</code></pre><p>Result of the above operation is given below. Notice that even when exception israised the main program completes and the output is printed. The value of outputis nil because the child process raised an exception.</p><pre><code class="language-plaintext">$ ruby main.rboutput is</code></pre><p><code>system</code> returns <code>true</code> if the command was successfully performed ( exit statuszero ) . It returns <code>false</code> for non zero exit status. It returns <code>nil</code> ifcommand execution fails.</p><pre><code class="language-ruby">system(&quot;command that does not exist&quot;)  #=&gt; nilsystem(&quot;ls&quot;)                           #=&gt; truesystem(&quot;ls | grep foo&quot;)                #=&gt; false</code></pre><p><code>system</code> sets the global variable $? to the exit status of the process. Rememberthat a value of zero means the operation was a success.</p><p>The biggest issue with <code>system</code> command is that it's not possible to capture theoutput of the operation.</p><h2>exec</h2><p><a href="http://ruby-doc.org/core-1.9.3/Kernel.html#method-i-exec">Kernel#exec</a> replacesthe current process by running the external command.</p><p>Let's see an example. Here I am in irb and I am going to execute <code>exec('ls')</code>.</p><pre><code class="language-plaintext">$ irbe1.9.3-p194 :001 &gt; exec('ls')lab.rb  main.rbnsingh ~/neerajsingh$</code></pre><p>I see the result but since the irb process was replaced by the <code>exec</code> process Iam no longer in <code>irb</code> .</p><p>Behind the scene both <code>system</code> and <code>backtick</code> operations use <code>fork</code> to fork thecurrent process and then they execute the given operation using <code>exec</code> .</p><p>Since <code>exec</code> replaces the current process it does not return anything. It printsthe output on the screen. There is no way to know if the operation was a&quot;success&quot; or a &quot;failure&quot; and hence it's not recommended to use <code>exec</code>.</p><h2>sh</h2><p><a href="http://rake.rubyforge.org/classes/FileUtils.html">sh</a> actually calls <code>system</code>under the hood. However it is worth a mention here. This method is added by<code>FileUtils</code> in <code>rake</code>. It allows an easy way to check the exit status of thecommand.</p><pre><code class="language-ruby">require 'rake'sh %w(xxxxx) do |ok, res|   if !ok     abort 'the operation failed'   endend</code></pre><h2>popen3</h2><p>If you are going to capture <code>stdout</code> and <code>stderr</code> then you should use<a href="http://www.ruby-doc.org/stdlib-1.9.3/libdoc/open3/rdoc/Open3.html#method-c-popen3">popen3</a>since this method allows you to interact with <code>stdin</code>, <code>stdout</code> and <code>stderr</code> .</p><p>I want to execute <code>git push heroku master</code> programmatically and I want tocapture the output. Here is my code.</p><pre><code class="language-ruby">require 'open3'cmd = 'git push heroku master'Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|  puts &quot;stdout is:&quot; + stdout.read  puts &quot;stderr is:&quot; + stderr.readend</code></pre><p>And here is the output. It has been truncated since rest of output is notrelevant to this discussion.</p><pre><code class="language-plaintext">stdout is:stderr is:-----&gt; Heroku receiving push-----&gt; Ruby/Rails app detected-----&gt; Installing dependencies using Bundler version 1.2.1</code></pre><p>The important thing to note here is that when I execute the program<code>ruby lab.rb</code> I do not see any output on my terminal for first 10 seconds. ThenI see the whole output as one single dump.</p><p>The other thing to note is that heroku is writing all this output to <code>stderr</code>and not to <code>stdout</code> .</p><p>Above solution works but it has one major drawback. The push to heroku mighttake 10 to 20 seconds and for this period we do not get any feedback on theterminal. In reality when we execute <code>git push heroku master</code> we start seeingresult on our terminal one by one as heroku is processing things.</p><p>So we should capture the output from heroku as it is being streamed rather thandumping the whole output as one single chunk of string at the end of processing.</p><p>Here is the modified code.</p><pre><code class="language-ruby">require 'open3'cmd = 'git push heroku master'Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|  while line = stderr.gets    puts line  endend</code></pre><p>Now when I execute above command using <code>ruby lab.rb</code> I get the output on myterminal incrementally as if I had typed <code>git push heroku master</code> .</p><p>Here is another example of capturing streaming output.</p><pre><code class="language-ruby">require 'open3'cmd = 'ping www.google.com'Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|  while line = stdout.gets    puts line  endend</code></pre><p>In the above case you will get the output of ping on your terminal as if you hadtyped <code>ping www.google.com</code> on your terminal .</p><p>Now let's see how to check if command succeeded or not.</p><pre><code class="language-ruby">require 'open3'cmd = 'ping www.google.com'Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|  exit_status = wait_thr.value  unless exit_status.success?    abort &quot;FAILED !!! #{cmd}&quot;  endend</code></pre><h2>popen2e</h2><p><a href="http://www.ruby-doc.org/stdlib-1.9.3/libdoc/open3/rdoc/Open3.html#method-c-popen2e">popen2e</a>is similar to popen3 but merges the standard output and standard error .</p><pre><code class="language-ruby">require 'open3'cmd = 'ping www.google.com'Open3.popen2e(cmd) do |stdin, stdout_err, wait_thr|  while line = stdout_err.gets    puts line  end  exit_status = wait_thr.value  unless exit_status.success?    abort &quot;FAILED !!! #{cmd}&quot;  endend</code></pre><p>In all other areas this method works similar to <code>popen3</code> .</p><h2>Process.spawn</h2><p><a href="http://www.ruby-doc.org/core-1.9.3/Process.html#method-c-spawn">Kernel.spawn</a>executes the given command in a subshell. It returns immediately with theprocess id.</p><pre><code class="language-ruby">irb(main)&gt; pid = Process.spawn(&quot;ls -al&quot;)=&gt; 81001</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[extend self in ruby]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/extend-self-in-ruby"/>
      <updated>2012-06-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/extend-self-in-ruby</id>
      <content type="html"><![CDATA[<p><em>Following code was tested with ruby 1.9.3 .</em></p><h2>Class is meant for both data and behavior</h2><p>Lets look at this ruby code.</p><pre><code class="language-ruby">class Util  def self.double(i)   i*2  endendUtil.double(4) #=&gt; 8</code></pre><p>Here we have a <code>Util</code> class. But notice that all the methods on this class areclass methods. This class does not have any instance variables. Usually a classis used to carry both data and behavior and ,in this case, the Util class hasonly behavior and no data.</p><h2>Similar utility tools in ruby</h2><p>Now to get some perspective on this discussion lets look at some ruby methodsthat do similar thing. Here are a few.</p><pre><code class="language-ruby">require 'base64'Base64.encode64('hello world') #=&gt; &quot;aGVsbG8gd29ybGQ=\n&quot;require 'benchmark'Benchmark.measure { 10*2000 }require 'fileutils'FileUtils.chmod 0644, 'test.rb'Math.sqrt(4) #=&gt; 2</code></pre><p>In all the above cases the class method is invoked without creating an instancefirst. So this is similar to the way I used <code>Util.double</code> .</p><p>However lets see what is the class of all these objects.</p><pre><code class="language-ruby">Base64.class #=&gt; ModuleBenchmark.class #=&gt; ModuleFileUtils.class #=&gt; ModuleMath.class #=&gt; Module</code></pre><p>So these are not classes but modules. That begs the question why the smart guysat ruby-core implemented them as modules instead of creating a class the way Idid for Util.</p><p>Reason is that Class is too heavy for creating only methods like <code>double</code>. As wediscussed earlier a class is supposed to have both data and behavior. If theonly thing you care about is behavior then ruby suggests to implement it as amodule.</p><h2>extend self is the answer</h2><p>Before I go on to discuss <code>extend self</code> here is how my <code>Util</code> class will lookafter moving from <code>Class</code> to <code>Module</code>.</p><pre><code class="language-ruby">module Util  extend self  def double(i)    i * 2  endendputs Util.double(4) #=&gt; 8</code></pre><h3>So how does extend self work</h3><p>First lets see what extend does.</p><pre><code class="language-ruby">module M def double(i)  i * 2 endendclass Calculator  extend Mendputs Calculator.double(4)</code></pre><p>In the above case <code>Calculator</code> is extending module <code>M</code> and hence all theinstance methods of module <code>M</code> are directly available to <code>Calculator</code>.</p><p>In this case <code>Calculator</code> is a class that extended the module <code>M</code>. However<code>Calculator</code> does not have to be a class to extend a module.</p><p>Now lets try a variation where <code>Calculator</code> is a module.</p><pre><code class="language-ruby">module M def double(i)  i * 2 endendmodule Calculator  extend Mendputs Calculator.double(4) #=&gt; 8</code></pre><p>Here Calculator is a module that is extending another module.</p><p>Now that we understand that a module can extend another module look at the abovecode and question why module <code>M</code> is even needed. Why can't we move the method<code>double</code> to module Calculator directly. Let's try that.</p><pre><code class="language-ruby">module Calculator  extend Calculator   def double(i)    i * 2   endendputs Calculator.double(4) #=&gt; 8</code></pre><p>I got rid of module <code>M</code> and moved the method <code>double</code> inside module<code>Calculator</code>. Since module <code>M</code> is gone I changed from <code>extend M</code> to<code>extend Calculator</code>.</p><p>One last fix.</p><p>Inside the module Calculator what is <code>self</code>. <code>self</code> is the module <code>Calculator</code>itself. So there is no need to repeat <code>Calculator</code> twice. Here is the finalversion</p><pre><code class="language-ruby">module Calculator  extend self   def double(i)    i * 2   endendputs Calculator.double(4) #=&gt; 8</code></pre><h2>Converting A Class into a Module</h2><p>Every time I would encounter code like <code>extend self</code> my brain will pause for amoment. Then I would google for it. Will read about it. Three months later Iwill repeat the whole process.</p><p>The best way to learn it is to use it. So I started looking for a case to use<code>extend self</code>. It is not a good practice to go hunting for code to apply an ideayou have in your mind but here I was trying to learn.</p><p>Here is a before snapshot of methods from <code>Util</code> class I used in a project.</p><pre><code class="language-ruby">class Util  def self.config2hash(file); end  def self.in_cents(amount); end  def self.localhost2public_url(url, protocol); endend</code></pre><p>After using <code>extend self</code> code became</p><pre><code class="language-ruby">module Util  extend self  def config2hash(file); end  def in_cents(amount); end  def localhost2public_url(url, protocol); endend</code></pre><p>Much better. It makes the intent clear and ,I believe, it is in line with theway ruby would expect us to use.</p><h2>Another usage inline with how Rails uses extend self</h2><p>Here I am building an ecommerce application and each new order needs to get anew order number from a third party sales application. The code might look likethis. I have omitted the implementation of the methods because they are notrelevant to this discussion.</p><pre><code class="language-ruby">class Order  def amount; end  def buyer; end  def shipped_at; end  def number    @number || self.class.next_order_number  end  def self.next_order_number; 'A100'; endendputs Order.new.number #=&gt; A100</code></pre><p>Here the method <code>next_order_number</code> might be making a complicated call toanother sales system. Ideally the class <code>Order</code> should not expose method<code>next_order_number</code> . So we can make this method <code>private</code> but that does notsolve the root problem. The problem is that model <code>Order</code> should not know howthe new order number is generated. Well we can move the method<code>next_order_number</code> to another <code>Util</code> class but that would create too muchdistance.</p><p>Here is a solution using <code>extend self</code>.</p><pre><code class="language-ruby">module Checkout  extend self  def next_order_number; 'A100'; end  class Order    def amount; end    def buyer; end    def shipped_at; end    def number      @number || Checkout.next_order_number    end  endendputs Checkout::Order.new.number #=&gt; A100</code></pre><p>Much better. The class Order is not exposing method <code>next_order_number</code> and thismethod is right there in the same file. No need to open the <code>Util</code> class.</p><p>To see practical examples of <code>extend self</code> please look at Rails source code andsearch for <code>extend self</code>. You will find some interesting usage.</p><p>This is my first serious attempt to learn usage of <code>extend self</code> so that nexttime when I come across such code my brain does not freeze. If you think I havemissed out something then do let me know.</p>]]></content>
    </entry><entry>
       <title><![CDATA[to_str in ruby]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/to_str-in-ruby"/>
      <updated>2012-06-26T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/to_str-in-ruby</id>
      <content type="html"><![CDATA[<p><em>Following code was tested with ruby 1.9.3 .</em></p><h2>All objects have to_s method</h2><p><code>to_s</code> method is define in <code>Object</code> class and hence all ruby objects have method<code>to_s</code>.</p><p>Certain methods always call <code>to_s</code> method. For example when we do stringinterpolation then <code>to_s</code> method is called. <code>puts</code> invokes <code>to_s</code> method too.</p><pre><code class="language-ruby">class Lab def to_s  'to_s' end def to_str  'to_str' endendl = Lab.newputs &quot;#{l}&quot; #=&gt; to_sputs l #=&gt; to_s</code></pre><p><code>to_s</code> is simply the string representation of the object.</p><p>Before we look at <code>to_str</code> let's see a case where ruby raises error.</p><pre><code class="language-ruby">e = Exception.new('not sufficient fund')# case 1puts e# case 2puts &quot;notice: #{e}&quot;# case 3puts &quot;Notice: &quot; + e</code></pre><p>Here is the result</p><pre><code class="language-text">not sufficient fundNotice: not sufficient fund`+': can't convert Exception into String (TypeError)</code></pre><p>In the first two cases the <code>to_s</code> method of object <code>e</code> was printed.</p><p>However in case '3' ruby raised an error.</p><p>Let's read the error message again.</p><pre><code class="language-text">`+': can't convert Exception into String (TypeError)</code></pre><p>In this case on the left hand side we have a string object. To this stringobject we are trying to add object <code>e</code>. Ruby could have called <code>to_s</code> method on<code>e</code> and could have produced the result. But ruby refused to do so.</p><p>Ruby refused to do so because it found that the object we are trying to add tostring is not of type String. When we call <code>to_s</code> we get the stringrepresentation of the string. But the object might or might not be behaving likea string.</p><p>Here we are not looking for the string representation of <code>e</code>. What we want isfor <code>e</code> to behave a like string. And that is where <code>to_str</code> comes in picture. Ihave a few more examples to clear this thing so hang in there.</p><h2>What is to_str</h2><p>If an object implements <code>to_str</code> method then it is telling the world that myclass might not be <code>String</code> but for all practical purposes treat me like astring.</p><p>So if we want to make exception object behave like a string then we can add<code>to_str</code> method to it like this.</p><pre><code class="language-ruby">e = Exception.new('not sufficient fund')def e.to_str  to_sendputs &quot;Notice: &quot; + e #=&gt; Notice: not sufficient fund</code></pre><p>Now when we run the code we do not get any exception.</p><h2>What would happen if Fixnum has to_str method</h2><p>Here is an example where ruby raises exception.</p><pre><code class="language-ruby">i = 10puts '7' + i #=&gt; can't convert Fixnum into String (TypeError)</code></pre><p>Here Ruby is saying that Fixnum is not like a string and it should not be addedto String.</p><p>We can make Fixnum to behave like a string by adding a <code>to_str</code> method.</p><pre><code class="language-ruby">class Fixnum  def to_str    to_s  endendi = 10puts '7' + i #=&gt; 710</code></pre><p>The practical usage of this example can be seen here.</p><pre><code class="language-text">irb(main):002:0&gt; [&quot;hello&quot;, &quot;world&quot;].join(1)TypeError: no implicit conversion of Fixnum into String</code></pre><p>In the above case ruby is refusing to invoke <code>to_s</code> on &quot;1&quot; because it knows thatadding &quot;1&quot; to a string does not feel right.</p><p>However we can add method <code>to_str</code> to Fixnum as shown in the last section andthen we will not get any error. In this case the result will be as shown below.</p><pre><code class="language-text">irb(main):008:0&gt; [&quot;hello&quot;, &quot;world&quot;].join(1)=&gt; &quot;hello1world&quot;</code></pre><h2>A real practical example of defining to_str</h2><p>I <a href="https://twitter.com/neerajsingh0101/status/217128187489042432">tweeted</a> about<a href="https://github.com/rails/rails/commit/188cc90af9b29d5520564af7bd7bbcdc647953ca">a quick lesson in to_s vs to_str</a>and a few people asked me to expand on that. Lets see what is happening here.</p><p>Before the refactoring was done <code>Path</code> is a subclass of <code>String</code>. So it isString and it has all the methods of a string.</p><p>As part of refactoring <code>Path</code> is no longer extending from <code>String</code>. However forall practical purposes it acts like a string. This line is important and I amgoing to repeat it. For all practical purposes <code>Path</code> here is like a <code>String</code>.</p><p>Here we are not talking about the string representation of <code>Path</code>. Here <code>Path</code>is so close to <code>String</code> that practically it can be replaced for a string.</p><p>So in order to be like a <code>String</code> class <code>Path</code> should have <code>to_str</code> method andthat's exactly what was done as part of refactoring.</p><p>During discussion with my friends someone suggested instead of defining <code>to_str</code>tenderlove could have just defined <code>to_s</code> and the result would have been same.</p><p>Yes the result would be same whether you have defined <code>to_s</code> or <code>to_str</code> if youdoing <code>puts</code>.</p><pre><code class="language-ruby">puts Path.new('world')</code></pre><p>However in the following case just defining <code>to_s</code> will cause error. Only byhaving <code>to_str</code> following case will work.</p><pre><code class="language-ruby">puts 'hello ' + Path.new('world')</code></pre><p>So the difference between defining <code>to_s</code> and <code>to_str</code> is not just what you seein the output.</p><h2>Conclusion</h2><p>If a class defines <code>to_str</code> then that class is telling the world that althoughmy class is not <code>String</code> you can treat me like a <code>String</code>.</p>]]></content>
    </entry><entry>
       <title><![CDATA[alias vs alias_method]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/alias-vs-alias-method"/>
      <updated>2012-01-08T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/alias-vs-alias-method</id>
      <content type="html"><![CDATA[<p>It comes up very often. Should I use <code>alias</code> or <code>alias_method</code> . Let's take alook at them in a bit detail.</p><h2>Usage of alias</h2><pre><code class="language-ruby">class User  def full_name    puts &quot;Johnnie Walker&quot;  end  alias name full_nameendUser.new.name #=&gt;Johnnie Walker</code></pre><h2>Usage of alias_method</h2><pre><code class="language-ruby">class User  def full_name    puts &quot;Johnnie Walker&quot;  end  alias_method :name, :full_nameendUser.new.name #=&gt;Johnnie Walker</code></pre><p>First difference you will notice is that in case of <code>alias_method</code> we need touse a comma between the &quot;new method name&quot; and &quot;old method name&quot;.</p><p><code>alias_method</code> takes both symbols and strings as input. Following code wouldalso work.</p><pre><code class="language-ruby">alias_method 'name', 'full_name'</code></pre><p>That was easy. Now let's take a look at how scoping impacts usage of <code>alias</code> and<code>alias_method</code> .</p><h2>Scoping with alias</h2><pre><code class="language-ruby">class User  def full_name    puts &quot;Johnnie Walker&quot;  end  def self.add_rename    alias_method :name, :full_name  endendclass Developer &lt; User  def full_name    puts &quot;Geeky geek&quot;  end  add_renameendDeveloper.new.name #=&gt; 'Gekky geek'</code></pre><p>In the above case method &quot;name&quot; picks the method &quot;full_name&quot; defined in&quot;Developer&quot; class. Now let's try with <code>alias</code>.</p><pre><code class="language-ruby">class User  def full_name    puts &quot;Johnnie Walker&quot;  end  def self.add_rename    alias :name :full_name  endendclass Developer &lt; User  def full_name    puts &quot;Geeky geek&quot;  end  add_renameendDeveloper.new.name #=&gt; 'Johnnie Walker'</code></pre><p>With the usage of <code>alias</code> the method &quot;name&quot; is not able to pick the method&quot;full_name&quot; defined in <code>Developer</code>.</p><p>This is because <code>alias</code> is a keyword and it is lexically scoped. It means ittreats <code>self</code> as the value of <code>self</code> at the time the source code was read . Incontrast <code>alias_method</code> treats <code>self</code> as the value determined at the run time.</p><p>Overall my recommendation would be to use <code>alias_method</code>. Since <code>alias_method</code>is a method defined in class <code>Module</code> it can be overridden later and it offersmore flexibility.</p>]]></content>
    </entry><entry>
       <title><![CDATA[Ruby pack unpack]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/ruby-pack-unpack"/>
      <updated>2011-07-20T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/ruby-pack-unpack</id>
      <content type="html"><![CDATA[<p>C programming language allows developers to directly access the memory wherevariables are stored. Ruby does not allow that. There are times while working inRuby when you need to access the underlying bits and bytes. Ruby provides twomethods <code>pack</code> and <code>unpack</code> for that.</p><p>Here is an example.</p><pre><code class="language-ruby">&gt; 'A'.unpack('b*')=&gt; [&quot;10000010&quot;]</code></pre><p>In the above case 'A' is a string which is being stored and using <code>unpack</code> I amtrying to read the bit value. The <a href="http://www.asciitable.com">ASCII table</a> saysthat ASCII value of 'A' is 65 and the binary representation of 65 is <code>10000010</code>.</p><p>Here is another example.</p><pre><code class="language-ruby">&gt; 'A'.unpack('B*')=&gt; [&quot;01000001&quot;]</code></pre><p>Notice the difference in result from the first case. What's the differencebetween <code>b*</code> and <code>B*</code>. In order to understand the difference first lets discussMSB and LSB.</p><h2>Most significant bit vs Least significant bit</h2><p>All bits are not created equal. <code>C</code> has ascii value of 67. The binary value of67 is <code>1000011</code>.</p><p>First let's discuss MSB (most significant bit) style . If you are following MSBstyle then going from left to right (and you always go from left to right) thenthe most significant bit will come first. Because the most significant bit comesfirst we can pad an additional zero to the left to make the number of bitseight. After adding an additional zero to the left the binary value looks like<code>01000011</code>.</p><p>If we want to convert this value in the LSB (Least Significant Bit) style thenwe need to store the least significant bit first going from left to right. Givenbelow is how the bits will be moved if we are converting from MSB to LSB. Notethat in the below case position 1 is being referred to the leftmost bit.</p><pre><code>move value 1 from position 8 of MSB to position 1 of LSBmove value 1 from position 7 of MSB to position 2 of LSBmove value 0 from position 6 of MSB to position 3 of LSBand so on and so forth</code></pre><p>After the exercise is over the value will look like <code>11000010</code>.</p><p>We did this exercise manually to understand the difference between<code>most significant bit</code> and <code>least significant bit</code>. However unpack method candirectly give the result in both MSB and LSB. The <code>unpack</code> method can take both<code>b*</code> and <code>B*</code> as the input. As per the ruby documentation here is thedifference.</p><pre><code>B | bit string (MSB first)b | bit string (LSB first)</code></pre><p>Now let's take a look at two examples.</p><pre><code class="language-ruby">&gt; 'C'.unpack('b*')=&gt; [&quot;11000010&quot;]&gt; 'C'.unpack('B*')=&gt; [&quot;01000011&quot;]</code></pre><p>Both <code>b*</code> and <code>B*</code> are looking at the same underlying data. It's just that theyrepresent the data differently.</p><h2>Different ways of getting the same data</h2><p>Let's say that I want binary value for string <code>hello</code> . Based on the discussionin the last section that should be easy now.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('B*')=&gt; [&quot;0110100001100101011011000110110001101111&quot;]</code></pre><p>The same information can also be derived as</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('C*').map {|e| e.to_s 2}=&gt; [&quot;1101000&quot;, &quot;1100101&quot;, &quot;1101100&quot;, &quot;1101100&quot;, &quot;1101111&quot;]</code></pre><p>Let's break down the previous statement in small steps.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('C*')=&gt; [104, 101, 108, 108, 111]</code></pre><p>Directive <code>C*</code> gives the <code>8-bit unsigned integer</code> value of the character. Notethat ascii value of <code>h</code> is <code>104</code>, ascii value of <code>e</code> is <code>101</code> and so on.</p><p>Using the technique discussed above I can find hex value of the string.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('C*').map {|e| e.to_s 16}=&gt; [&quot;68&quot;, &quot;65&quot;, &quot;6c&quot;, &quot;6c&quot;, &quot;6f&quot;]</code></pre><p>Hex value can also be achieved directly.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('H*')=&gt; [&quot;68656c6c6f&quot;]</code></pre><h2>High nibble first vs Low nibble first</h2><p>Notice the difference in the below two cases.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('H*')=&gt; [&quot;68656c6c6f&quot;]&gt; &quot;hello&quot;.unpack('h*')=&gt; [&quot;8656c6c6f6&quot;]</code></pre><p>As per ruby documentation for unpack</p><pre><code>H | hex string (high nibble first) h | hex string (low nibble first)</code></pre><p>A byte consists of 8 bits. A nibble consists of 4 bits. So a byte has twonibbles. The ascii value of 'h' is <code>104</code>. Hex value of 104 is <code>68</code>. This <code>68</code> isstored in two nibbles. First nibble, meaning 4 bits, contain the value <code>6</code> andthe second nibble contains the value <code>8</code>. In general we deal with high nibblefirst and going from left to right we pick the value <code>6</code> and then <code>8</code>.</p><p>However if you are dealing with low nibble first then low nibble value <code>8</code> willtake the first slot and then <code>6</code> will come. Hence the result in &quot;low nibblefirst&quot; mode will be <code>86</code>.</p><p>This pattern is repeated for each byte. And because of that a hex value of<code>68 65 6c 6c 6f</code> looks like <code>86 56 c6 c6 f6</code> in low nibble first format.</p><h2>Mix and match directives</h2><p>In all the previous examples I used <code>*</code>. And a <code>*</code> means to keep going as longas it has to keep going. Lets see a few examples.</p><p>A single <code>C</code> will get a single byte.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('C')=&gt; [104]</code></pre><p>You can add more <code>Cs</code> if you like.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('CC')=&gt; [104, 101]&gt; &quot;hello&quot;.unpack('CCC')=&gt; [104, 101, 108]&gt; &quot;hello&quot;.unpack('CCCCC')=&gt; [104, 101, 108, 108, 111]</code></pre><p>Rather than repeating all those directives, I can put a number to denote howmany times you want previous directive to be repeated.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('C5')=&gt; [104, 101, 108, 108, 111]</code></pre><p>I can use <code>*</code> to capture al the remaining bytes.</p><pre><code class="language-ruby">&gt; &quot;hello&quot;.unpack('C*')=&gt; [104, 101, 108, 108, 111]</code></pre><p>Below is an example where <code>MSB</code> and <code>LSB</code> are being mixed.</p><pre><code class="language-ruby">&gt; &quot;aa&quot;.unpack('b8B8')=&gt; [&quot;10000110&quot;, &quot;01100001&quot;]</code></pre><h3>pack is reverse of unpack</h3><p>Method <code>pack</code> is used to read the stored data. Let's discuss a few examples.</p><pre><code class="language-ruby">&gt;  [1000001].pack('C')=&gt; &quot;A&quot;</code></pre><p>In the above case the binary value is being interpreted as<code>8 bit unsigned integer</code> and the result is 'A'.</p><pre><code class="language-ruby">&gt; ['A'].pack('H')=&gt; &quot;\xA0&quot;</code></pre><p>In the above case the input 'A' is not ASCII 'A' but the hex 'A'. Why is it hex'A'. It is hex 'A' because the directive 'H' is telling pack to treat inputvalue as hex value. Since 'H' is high nibble first and since the input has onlyone nibble then that means the second nibble is zero. So the input changes from<code>['A']</code> to <code>['A0']</code> .</p><p>Since hex value <code>A0</code> does not translate into anything in the ASCII table thefinal output is left as it and hence the result is <code>\xA0</code>. The leading <code>\x</code>indicates that the value is hex value.</p><p>Notice the in hex notation <code>A</code> is same as <code>a</code>. So in the above example I canreplace <code>A</code> with <code>a</code> and the result should not change. Let's try that.</p><pre><code class="language-ruby">&gt; ['a'].pack('H')=&gt; &quot;\xA0&quot;</code></pre><p>Let's discuss another example.</p><pre><code class="language-ruby">&gt; ['a'].pack('h')=&gt; &quot;\n&quot;</code></pre><p>In the above example notice the change. I changed directive from <code>H</code> to <code>h</code>.Since <code>h</code> means low nibble first and since the input has only one nibble thevalue of low nibble becomes zero and the input value is treated as high nibblevalue. That means value changes from <code>['a']</code> to <code>['0a']</code>. And the output will be<code>\x0A</code>. If you look at ASCII table then hex value <code>A</code> is ASCII value 10 which is<code>NL line feed, new line</code>. Hence we see <code>\n</code> as the output because it represents&quot;new line feed&quot;.</p><h2>Usage of unpack in Rails source code</h2><p>I did a quick grep in Rails source code and found following usage of unpack.</p><pre><code>email_address_obfuscated.unpack('C*')'mailto:'.unpack('C*')email_address.unpack('C*')char.unpack('H2')column.class.string_to_binary(value).unpack(&quot;H*&quot;)data.unpack(&quot;m&quot;)s.unpack(&quot;U\*&quot;)</code></pre><p>Already we have seen the usage of directive <code>C*</code> and <code>H</code> for unpack. Thedirective <code>m</code> gives the base64 encoded value and the directive <code>U*</code> gives theUTF-8 character. Here is an example.</p><pre><code class="language-ruby">&gt; &quot;Hello&quot;.unpack('U*')=&gt; [72, 101, 108, 108, 111]</code></pre><h2>Testing environment</h2><p>Above code was tested with ruby 1.9.2 .</p><p>French version of this article is available<a href="http://vfsvp.fr/article/les-methodes-pack-et-unpack-en-ruby/">here</a> .</p>]]></content>
    </entry><entry>
       <title><![CDATA[Infinite hash and default_proc]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/default_proc_in_infinite_hash"/>
      <updated>2010-12-31T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/default_proc_in_infinite_hash</id>
      <content type="html"><![CDATA[<p>I you already know how<a href="http://twitter.com/#!/tenderlove/status/5687291469107200">this infinite hash</a>works then you are all set. If not read along.</p><h2>Default value of Hash</h2><p>If I want a hash to have a default value then that's easy.</p><pre><code class="language-ruby">h = Hash.new(0)puts h['usa'] #=&gt; 0</code></pre><p>Above code will give me a fixed value if key is not found. If I want dynamicvalue then I can use block form.</p><pre><code class="language-ruby">h = Hash.new{|h,k| h[k] = k.upcase}puts h['usa'] #=&gt; USAputs h['india'] #=&gt; INDIA</code></pre><h2>Default value is hash</h2><p>If I want the default value to be a <code>hash</code> then it seems easy but it falls apartsoon.</p><pre><code class="language-ruby">h = Hash.new{|h,k| h[k] = {} }puts h['usa'].inspect #=&gt; {}puts h['usa']['ny'].inspect #=&gt; nilputs h['usa']['ny']['nyc'].inspect #=&gt; NoMethodError: undefined method `[]' for nil:NilClass</code></pre><p>In the above if a key is missing for <code>h</code> then it returns a hash. However thatreturned hash is an ordinary hash which does not have a capability of returninganother hash if a key is missing.</p><p>This is where <code>default_proc</code> comes into picture.<a href="http://ruby-doc.org/core-1.8.6/classes/Hash.html#M002854">hash.default_proc</a>returns the block which was passed to <code>Hash.new</code> .</p><pre><code class="language-ruby">h = Hash.new{|h,k| Hash.new(&amp;h.default_proc)}puts h['usa']['ny']['nyc'].inspect #=&gt; {}</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[instance_exec , changing self and params]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/instance-exec-changing-self-and-parameters-to-proc"/>
      <updated>2010-05-28T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/instance-exec-changing-self-and-parameters-to-proc</id>
      <content type="html"><![CDATA[<p><em>Here is<a href="understanding-instance-exec-in-ruby">updated article on the same topic</a> .</em></p><p>Following code will print <code>99</code> as the output.</p><pre><code class="language-ruby">class Klass  def initialize    @secret = 99  endendputs Klass.new.instance_eval { @secret }</code></pre><p>Nothing great there. However try passing a parameter to <code>instance_eval</code> .</p><pre><code class="language-ruby">puts Klass.new.instance_eval(self) { @secret }</code></pre><p>You will get following error.</p><pre><code class="language-ruby">wrong number of arguments (1 for 0)</code></pre><p>So <code>instance_eval</code> does not allow you to pass parameters to a block.</p><h2>How to get around to the restriction that instance_eval does not accept parameters</h2><p><code>instance_exec</code> was added to ruby 1.9 and it allows you to pass parameters to aproc. This feature has been backported to ruby 1.8.7 so we don't really needruby 1.9 to test this feature. Try this.</p><pre><code class="language-ruby">class Klass  def initialize    @secret = 99  endendputs Klass.new.instance_exec('secret') { |t| eval&quot;@#{t}&quot; }</code></pre><p>Above code works. So now we can pass parameters to block. Good.</p><h2>Changing value of self</h2><p>Another feature of <code>instance_exec</code> is that it changes the value of <code>self</code>. Toillustrate that I need to give a longer example.</p><pre><code class="language-ruby">module Kernel  def singleton_class    class &lt;&lt; self      self    end  endendclass Human  proc = lambda { puts 'proc says my class is ' + self.name.to_s }  singleton_class.instance_eval do    define_method(:lab)  do      proc.call    end  endendclass Developer &lt; HumanendHuman.lab # class is HumanDeveloper.lab # class is Human ; oops</code></pre><p>Notice that in that above case <code>Developer.lab</code> says &quot;Human&quot;. And that is theright answer from ruby perspective. However that is not what I intended. rubystores the binding of the proc in the context it was created and hence itrightly reports that self is &quot;Human&quot; even though it is being called by<code>Developer</code>.</p><p>Go to<a href="http://facets.rubyforge.org/apidoc/api/core/index.html">http://facets.rubyforge.org/apidoc/api/core/index.html</a>and look for <code>instance_exec</code> method. The doc says</p><p>&lt;blockquote&gt;Evaluate the block with the given arguments within the context of this object,so self is set to the method receiver.&lt;/blockquote&gt;</p><p>It means that <code>instance_exec</code> evaluates self in a new context. Now try the samecode with <code>instance_exec</code> .</p><pre><code class="language-ruby">module Kernel  def singleton_class    class &lt;&lt; self      self    end  endendclass Human  proc = lambda { puts 'proc says my class is ' + self.name.to_s }  singleton_class.instance_eval do    define_method(:lab)  do      self.instance_exec &amp;proc    end  endendclass Developer &lt; HumanendHuman.lab # class is HumanDeveloper.lab # class is Developer</code></pre><p>In this case <code>Developer.lab</code> says <code>Developer</code> and not <code>Human</code>.</p><p>You can also checkout this page (Link is not available) which has much moredetailed explanation of <code>instance_exec</code> and also emphasizes that <code>instance_exec</code>does pass a new value of <code>self</code> .</p><p><code>instance_exec</code> is so useful that <code>ActiveSupport</code> needs it. And since ruby 1.8.6does not have it <code>ActiveSupport</code> has code to support it.</p><p>I came across <code>instance_exec</code> issue while resolving<a href="https://rails.lighthouseapp.com/projects/8994/tickets/4507">#4507 rails ticket</a>. The final solution did not need <code>instance_exec</code> but I learned a bit about it.</p>]]></content>
    </entry><entry>
       <title><![CDATA[$LOADED_FEATURES and require, load, require_dependency]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/require-load-loaded_features"/>
      <updated>2010-05-12T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/require-load-loaded_features</id>
      <content type="html"><![CDATA[<p>Rails developers know that in development mode classes are loaded on demand. Inproduction mode all the classes are loaded as part of bootstrapping the system.Also in development mode classes are reloaded every single time page isrefreshed.</p><p>In order to reload the class, Rails first has to <code>unload</code> . That unloading isdone something like this.</p><pre><code class="language-ruby"># unload User classObjet.send(:remove_const, :User)</code></pre><p>However a class might have other constants and they need to be unloaded too.Before you unload those constants you need to know all the constants that aredefined in the class that is being loaded. Long story short rails keep track ofevery single constant that is loaded when it loads <code>User</code> or <code>UserController</code>.</p><h2>Dependency mechanism is not perfect</h2><p>Sometimes dependency mechanism by rails lets a few things fall through thecrack. Try following case.</p><pre><code class="language-ruby">require 'open-uri'class UsersController &lt; ApplicationController  def index    open(&quot;http://www.ruby-lang.org/&quot;) {|f| }    render :text =&gt; 'hello'  endend</code></pre><p>Start the server in development mode and visit <code>http://localhost:3000/users</code> .First time every thing will come up fine. Now refresh the page. This time youshould get an exception <code>uninitialized constant OpenURI</code> .</p><p>So what's going on.</p><p>After the page is served the very first time then at the end of response railswill unload all the constants that were autoloaded including <code>UsersController</code>.However while unloading <code>UsersContorller</code> rails will also unload <code>OpenURI</code>.</p><p>When the page is refreshed then <code>UsersController</code> will be loaded and<code>require 'open-uri'</code> will be called. However that require will return <code>false</code>.</p><h2>Why require returns false</h2><p>Try the following test case in irb.</p><p>step 1</p><pre><code class="language-ruby">irb(main):002:0&gt; require 'ostruct'=&gt; true</code></pre><p>step 2</p><pre><code class="language-ruby">irb(main):005:0* Object.send(:remove_const, :OpenStruct)=&gt; OpenStruct</code></pre><p>step 3 : ensure that OpenStruct is truly removed</p><pre><code class="language-ruby">irb(main):006:0&gt; Object.send(:remove_const, :OpenStruct)NameError: constant Object::OpenStruct not defined        from (irb):6:in `remove_const'        from (irb):6:in `send'        from (irb):6</code></pre><p>step 4</p><pre><code class="language-ruby">irb(main):007:0&gt; require 'ostruct'=&gt; false</code></pre><p>step 5</p><pre><code class="language-ruby">irb(main):009:0&gt; OpenStruct.newNameError: uninitialized constant OpenStruct        from (irb):9</code></pre><p>Notice that in the above case in step 4 require returns <code>false</code>. 'require'checks against <code>$LOADED_FEATURES</code>. When <code>OpenStruct</code> was removed then it was notremoved from <code>$LOADED_FEATURES</code> and hence ruby thought <code>ostruct</code> is alreadyloaded.</p><p>How to get around to this issue.</p><p><code>require</code> loads only once. However <code>load</code> loads every single time. In stead of'require', 'load' could be used in this case.</p><pre><code class="language-ruby">irb(main):001:0&gt; load 'ostruct.rb'=&gt; trueirb(main):002:0&gt; OpenStruct.new=&gt; #&lt;OpenStruct&gt;</code></pre><h2>Back to the original problem</h2><p>In our rails application refresh of the page is failing. To get around to thatissue use <code>require_dependency</code> instead of <code>require</code>. <code>require_dependency</code> is arails thing. Under the hood rails does the same trick we did in the previousstep. Rails calls <code>kernel.load</code> to load the constants that would fail if requirewere used.</p>]]></content>
    </entry><entry>
       <title><![CDATA[$stdout.sync = true to flush output immediately]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/stdout-sync-true-to-flush-output-immediately"/>
      <updated>2009-07-04T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/stdout-sync-true-to-flush-output-immediately</id>
      <content type="html"><![CDATA[<p>Try this.</p><pre><code class="language-ruby">5.times do  putc('.')  sleep(2)end</code></pre><p>I was hoping that I will get a dot after every two seconds. But that's not whathappens when you run the code. I see nothing for first 10 seconds then I seefive dots in one shot. This is not what I wanted.</p><p>I started looking around at the documentation for IO class and found the methodcalled <a href="http://www.ruby-doc.org/core/classes/IO.html#M002263">sync=</a> which ifset to true will flush all output immediately to the underlying OS.</p><p>The reason why OS does not flush immediately is to minimize the IO operationwhich is usually slow. However in this case you are asking OS to not to bufferand to flush the output immediately.</p><pre><code class="language-ruby">$stdout.sync = true5.times do  putc('.')  sleep(2)end</code></pre>]]></content>
    </entry><entry>
       <title><![CDATA[Why the id of nil is 4 in Ruby]]></title>
       <author><name>Neeraj Singh</name></author>
      <link href="https://www.bigbinary.com/blog/why-the-id-of-nil-is-4-in-ruby"/>
      <updated>2008-06-23T12:00:00+00:00</updated>
      <id>https://www.bigbinary.com/blog/why-the-id-of-nil-is-4-in-ruby</id>
      <content type="html"><![CDATA[<p><em>Following code was tested with ruby 1.8.7 and Rails 2.3</em> .</p><p>While developing rails application you have must seen this</p><pre><code class="language-plaintext">Called id for nil, which would mistakenly be 4  if you reallywanted the id of nil, use object_id</code></pre><p>We all know that this message is added by Rails and it is called <code>whiny nil</code> .If you open your <code>config/development.rb</code> file you will see</p><pre><code class="language-ruby"># Log error messages when you accidentally call methods on nil.config.whiny_nils = true</code></pre><p>Simply stated it means that if the application happens to invoke id on a nilobject then throw an error. Rails assumes that under no circumstance a developerwants to find id of a nil object. So this must be an error case and Rails throwsan exception.</p><p>The question I have is why 4. Why Matz chose the id of nil to be 4.<a href="http://confreaks.tv/videos/mwrc2008-ruby-internals">This awesome presentation</a>on 'Ruby Internals' has the answer.</p><p>In short Matz decided to have all the odd numbers reserved for numerical values.Check this out.</p><pre><code class="language-ruby">&gt; irb&gt;&gt; 0.id(irb):1: warning: Object#id will be deprecated; use Object#object_id=&gt; 1&gt;&gt; 1.id(irb):2: warning: Object#id will be deprecated; use Object#object_id=&gt; 3&gt;&gt; 2.id(irb):3: warning: Object#id will be deprecated; use Object#object_id=&gt; 5&gt;&gt; 3.id(irb):4: warning: Object#id will be deprecated; use Object#object_id=&gt; 7</code></pre><p>Id 1,3,5 and 7 are taken by 0,1,2 and 3.</p><p>Now we are left with the id 0,2,4 and higher values.</p><pre><code class="language-ruby">&gt; irb&gt; FALSE.id(irb):5: warning: Object#id will be deprecated; use Object#object_id=&gt; 0&gt;&gt; TRUE.id(irb):6: warning: Object#id will be deprecated; use Object#object_id=&gt; 2</code></pre><p>FALSE had the id 0 and TRUE has the id 2.</p><p>Now the next available id left is 4 and that is taken by NIL.</p><pre><code class="language-ruby">&gt; irb&gt;&gt; NIL.id(irb):7: warning: Object#id will be deprecated; use Object#object_id=&gt; 4</code></pre><p>We won't even be discussing this issue once 1.9 comes out where we will have touse <code>object_id</code> and then this won't be an issue.</p><p>You can follow more discussion about this article at<a href="https://news.ycombinator.com/item?id=3543695">Hacker news</a> .</p>]]></content>
    </entry>
     </feed>