DEV Community

Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com

More readable integer comparisons in Ruby

This article was originally published on Build a SaaS with Rails from Rails Designer


Let's be honest: comparison operators like <, >, <=, and >= work perfectly fine, but they're not so readable (even more so when you're scanning through code quickly or working with complex conditionals).

What if instead of writing seats < 10 you could write seats.below? 10? Or usage.at_least? limit instead of usage >= limit? Much clearer, right?

This is where refinements come in handy (in short: add methods to existing classes without the risks of monkey patching).

Here's a simple refinement module that I copy between my apps to make integer comparisons more expressive:

# lib/comparable_integer.rb (reusable modules and classes are stored in `lib/`)
module ComparableInteger
  refine Integer do
    def below?(other)
      self < other
    end

    def above?(other)
      self > other
    end

    def at_most?(other)
      self <= other
    end

    def at_least?(other)
      self >= other
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Now imagine you're building subscription logic that checks seat limits:

class SubscriptionsController < ApplicationController
  using ComparableInteger

  def upgrade
    if current_seats.below? requested_seats
      charge_additional_seats
      update_subscription

      redirect_to subscription_path, notice: "Upgraded successfully"
    else
      redirect_to subscription_path, alert: "Cannot downgrade seats"
    end
  end

  private

  def current_seats = @subscription.seats

  def requested_seats = params[:seats].to_i
end
Enter fullscreen mode Exit fullscreen mode

The code reads almost like plain English. current_seats.below? requested_seats is immediately clear, while current_seats < requested_seats requires a mental translation.

Or another example when dealing with pricing tiers or feature limits:

class FeatureAccess
  using ComparableInteger

  def initialize(subscription)
    @subscription = subscription
  end

  def can_access_advanced_analytics?
    @subscription.amount_in_cents.at_least? 4999
  end

  def needs_team_plan?
    @subscription.seats.above? 1
  end

  def qualifies_for_discount?
    @subscription.months_active.at_least? 12
  end
end
Enter fullscreen mode Exit fullscreen mode

Much more readable than a sea of >= and > symbols, don't you think? Got more ideas for making Ruby code more expressive? Let me know in the comments below.

Top comments (0)