Skip to content

Instantly share code, notes, and snippets.

@dingsdax
Created June 9, 2026 13:14
Show Gist options
  • Select an option

  • Save dingsdax/8585afefb23b307b93172a2a8eb184b8 to your computer and use it in GitHub Desktop.

Select an option

Save dingsdax/8585afefb23b307b93172a2a8eb184b8 to your computer and use it in GitHub Desktop.
ruby-modern-idioms.md
name ruby-modern-idioms
description Review Ruby code for semantic idioms that linters cannot catch. Use when reviewing any Ruby file for method naming violations (call), pattern matching on Result objects instead of if/else, Struct used instead of Data.define, or discouraged idioms (tap, &method).

Ruby Modern Idioms

Review Ruby code for semantic idioms that linters cannot catch. RuboCop (rubocop-rails-omakase) already enforces frozen string literals, hash shorthand, endless methods, and it blocks — do not flag those.

Rules

No method named call

Methods must be named for what they do. call is never acceptable as a method name.

# BAD
class DateParser
  def call(input) = ...
end

LocationIqClient.call(lat, lng)

# GOOD
class DateParser
  def self.parse(input, hemisphere:) = ...
end

LocationIqClient.reverse_geocode(lat, lng)

Flag any method definition named call in any class or module.

Pattern matching for Result handling

When branching on a Result object, use case/in pattern matching. Never use if result.success? or if result.failure?.

# BAD
result = MagicLink.create_for(email:, ip_address:, user_agent:)
if result.success?
  redirect_to root_path
else
  render :new, locals: { error: result.errors.first }
end

# GOOD
case MagicLink.create_for(email:, ip_address:, user_agent:)
in { success?: true }
  redirect_to root_path
in { success?: false, errors: [error, *] }
  render :new, locals: { error: }
end

Flag any if result.success?, unless result.failure?, or result.success? && in controller or domain code.

Data.define for value objects

Immutable value objects must use Data.define, not Struct or attr_reader classes.

# BAD
ParseResult = Struct.new(:visit_date, :precision, :success?)

class ParseResult
  attr_reader :visit_date, :precision
  def initialize(visit_date:, precision:) ...
end

# GOOD
ParseResult = Data.define(:visit_date, :precision, :success?) do
  def self.success(visit_date, precision) = new(...)
  def self.failure = new(...)
end

Flag any Struct.new(...) used for immutable result or value objects. Flag any class that acts as an immutable value object but doesn't use Data.define.

Discouraged idioms

Flag any use of:

  • &method(:foo) — use { foo(it) } instead
  • .tap { |x| ... } except in debugging sessions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment