Ruby language guardrails, patterns, and best practices for AI-assisted development.
Use when working with Ruby files (.rb), Gemfile, Rakefile, or when the user mentions Ruby.
Provides block/proc patterns, metaprogramming guidelines, Bundler conventions,
and testing standards specific to this project's coding standards.
Ruby language guardrails, patterns, and best practices for AI-assisted development.
Use when working with Ruby files (.rb), Gemfile, Rakefile, or when the user mentions Ruby.
Provides block/proc patterns, metaprogramming guidelines, Bundler conventions,
and testing standards specific to this project's coding standards.
Applies to: Ruby 3.2+, Gems, APIs, CLIs, Web Applications
Core Principles
Least Surprise: Code should behave as readers expect; prefer clarity over cleverness
Everything is an Object: Leverage Ruby's object model; primitives are objects with methods
Convention Over Configuration: Follow established naming and structure conventions
Duck Typing with Confidence: Rely on behavior, not class checks; validate at boundaries
Blocks Everywhere: Use blocks for resource management, iteration, and DSLs
Guardrails
Version & Dependencies
Use Ruby 3.2+ with # frozen_string_literal: true in every .rb file
Manage dependencies with Bundler (Gemfile + Gemfile.lock)
Pin gem versions with pessimistic operator: gem "rails", "~> 7.1"
Run bundle audit before merging to check for vulnerable gems
Commit Gemfile.lock for applications; omit for gems
Specify required_ruby_version in .gemspec files
Code Style
Run rubocop before every commit (no exceptions)
snake_case for methods/variables/files, PascalCase for classes/modules, SCREAMING_SNAKE_CASE for constants
Predicate methods end with ?, dangerous methods end with !
Two-space indentation, no tabs
Prefer guard clauses over nested conditionals
# frozen_string_literal: true# Bad: deeply nesteddefprocess(user)
if user
if user.active?
do_something(user) if user.verified?
endendend# Good: guard clausesdefprocess(user)
returnunless user
returnunless user.active?
returnunless user.verified?
do_something(user)
end
Blocks & Procs
Use {} for single-line blocks, do...end for multi-line
Prefer block_given? + yield over explicit &block parameter
Use lambdas for strict arity checking; procs for flexible arity
# Block for resource managementFile.open("data.txt", "r") do |file|
file.each_line { |line| process(line) }
end# Lambda vs Proc
validator = ->(x) { x.positive? } # strict arity, returns from lambda
transformer = proc { |x| x.to_s } # flexible arity, returns from enclosing# Point-free style
names = users.map(&:name)
Error Handling
Rescue specific exceptions, never bare rescue
Define custom errors inheriting from StandardError
Use ensure for cleanup (not rescue for flow control)
Provide #message with actionable information in custom errors