Overview
Linting examines source code for programmatic and stylistic errors without executing the program. Formatters automatically restructure code to match style guidelines. These tools operate on the abstract syntax tree (AST) or token stream of source code, identifying patterns that violate defined rules and optionally modifying the code to fix violations.
The distinction matters: linters detect issues across multiple categories including logic errors, code smells, style violations, and potential bugs. Formatters focus exclusively on whitespace, indentation, line breaks, and other aesthetic concerns. A linter might flag an unused variable or warn about a method with too many parameters. A formatter ensures consistent spacing around operators and proper indentation depth.
Ruby's dynamic nature makes static analysis challenging yet valuable. The language permits runtime code modification, method definitions inside conditional blocks, and extensive metaprogramming. Linters compensate for the absence of compile-time checks that statically-typed languages provide, catching errors that would otherwise surface only during execution or testing.
The practice gained prominence as codebases grew and teams expanded. Manual code review could not scale to verify style consistency across thousands of files. Automated tools eliminated subjective style debates, reduced review cycle times, and caught mechanical errors before human reviewers saw the code. What began as simple style checkers evolved into sophisticated analysis engines examining security vulnerabilities, performance issues, and architectural violations.
# Before linting/formatting
def calculate(x,y)
if x>0
result=x*y
return result
end
end
# After linting/formatting
def calculate(x, y)
return unless x.positive?
x * y
end
Key Principles
Automated Enforcement
Manual style enforcement fails with team size and codebase growth. Humans miss inconsistencies during review, apply rules subjectively, and waste cognitive resources on formatting minutiae. Automated tools examine every line deterministically, applying identical standards across the entire codebase. The automation removes human judgment from style decisions, converting preferences into enforceable policies.
Separation of Concerns
Linting and formatting address distinct problems requiring different approaches. Linting rules carry semantic meaning: a method with excessive cyclomatic complexity indicates genuine design problems. A missing space after a comma carries no semantic weight. This distinction affects how teams adopt and configure tools. Formatting changes apply automatically without manual review. Linting violations require human judgment to address properly.
Configuration as Code
Linting configurations live in version-controlled files alongside source code. Teams track changes to rule sets, review modifications to style policies, and maintain different configurations for different projects or modules. The configuration defines the team's coding standards explicitly, eliminating ambiguity about style expectations. Developers clone a repository and inherit the project's linting rules automatically.
Progressive Adoption
Existing codebases cannot adopt strict linting rules instantly. A project with 100,000 lines of code might have 10,000 violations of a new rule set. Fixing all violations before enabling the linter blocks all other work. Progressive adoption allows teams to enable linting for new code, fix violations incrementally, and maintain momentum on feature development. Baseline files record existing violations, preventing new violations without requiring immediate fixes for legacy code.
Rule Categories
Linting rules group into categories by purpose and severity. Layout rules enforce visual consistency. Style rules promote idiomatic code. Metrics rules prevent complexity accumulation. Lint rules catch probable bugs. Security rules identify vulnerabilities. Each category requires different handling. Teams might auto-fix layout violations, review style violations during pull requests, and block merges on security violations.
Fast Feedback Loops
Effective linting provides immediate feedback during development. Developers see violations as they type, not hours later during CI checks. Editor integration shows squiggly underlines beneath violations. Save-on-format automatically corrects whitespace issues. Pre-commit hooks block commits containing violations. CI builds fail when violations reach the main branch. Each layer catches violations progressively earlier, reducing the cost of fixing them.
Tools & Ecosystem
RuboCop
RuboCop combines linting and formatting in a single extensible tool. The analyzer parses Ruby code into an AST, traverses nodes looking for pattern matches, and reports or corrects violations. The tool ships with hundreds of built-in cops (rule implementations) organized into departments: Layout, Style, Metrics, Lint, Performance, Security, and others.
Each cop examines specific patterns. The Style/StringLiterals cop verifies quote style consistency. The Metrics/CyclomaticComplexity cop calculates branching complexity. The Lint/UnusedMethodArgument cop identifies parameters that never appear in the method body. The Security/Eval cop flags dynamic code evaluation that might execute untrusted input.
RuboCop's extensibility allows custom cops for project-specific rules. Teams write cops to enforce architectural boundaries, naming conventions, or framework usage patterns. The plugin architecture supports third-party extensions that add domain-specific cops.
StandardRB
StandardRB wraps RuboCop with an opinionated, zero-configuration rule set. The tool eliminates configuration decisions by providing a single, unchangeable style guide. Teams install StandardRB and accept its style choices without debate. The approach trades flexibility for simplicity, removing the cognitive load of choosing and maintaining configurations.
The tool configures RuboCop with specific cop settings, disables configurable options, and provides simplified commands. Developers run a single command that both checks and fixes violations. The reduced surface area makes adoption easier for teams overwhelmed by RuboCop's configuration options.
RuboCop Extensions
The RuboCop ecosystem includes extensions for frameworks and libraries:
- rubocop-rails adds cops for Rails-specific patterns, checking for proper use of associations, validations, and framework conventions
- rubocop-rspec provides cops for RSpec test organization, expectation syntax, and spec file structure
- rubocop-performance identifies performance anti-patterns like inefficient enumeration or excessive object allocation
- rubocop-thread_safety detects thread-safety violations in concurrent code
Extensions follow RuboCop's plugin architecture. Each extension registers additional cops that activate when the relevant framework or library appears in the project.
Language Servers and Editor Integration
Editor integration transforms linting from batch checking into continuous feedback. The Ruby LSP (Language Server Protocol) implementation includes linting capabilities, providing real-time diagnostics as developers type. Editors display violations with inline messages, severity indicators, and quick-fix actions.
Different integration approaches offer various trade-offs. Direct RuboCop integration in editor plugins runs the full linter on save or on demand. Language server integration runs linting continuously in the background. File watchers trigger linting when files change. Each approach balances responsiveness against computational cost.
Formatters
While RuboCop handles both linting and formatting, specialized formatters focus exclusively on code layout. These tools make opinionated decisions about whitespace, line breaks, and indentation without configurable style options. The formatter reads code, parses it into an AST, and regenerates source code following strict formatting rules.
The single-purpose focus allows formatters to operate faster than full linters. A formatter completes in milliseconds, enabling format-on-save workflows that reformat files automatically. The deterministic output ensures every developer sees identically formatted code regardless of their editing habits.
Ruby Implementation
Installation and Basic Usage
RuboCop installs as a Ruby gem. The typical installation adds RuboCop to the development dependency group:
# Gemfile
group :development do
gem 'rubocop', require: false
gem 'rubocop-rails', require: false
gem 'rubocop-rspec', require: false
end
The command-line interface provides inspection and correction modes:
# Check files for violations
rubocop
# Check specific files or directories
rubocop app/models lib/services
# Auto-correct violations
rubocop -A
# Auto-correct safe violations only
rubocop -a
RuboCop distinguishes between safe and unsafe corrections. Safe corrections never change code semantics: adding spaces, breaking lines, or reordering independent statements. Unsafe corrections might alter behavior: changing string literals from double to single quotes affects interpolation, converting a conditional to a guard clause changes variable scope.
Configuration Files
The .rubocop.yml file controls RuboCop behavior. The YAML structure defines enabled cops, severity levels, and cop-specific parameters:
# .rubocop.yml
AllCops:
TargetRubyVersion: 3.2
NewCops: enable
Exclude:
- 'vendor/**/*'
- 'db/schema.rb'
- 'node_modules/**/*'
Style/StringLiterals:
Enabled: true
EnforcedStyle: single_quotes
Metrics/MethodLength:
Max: 15
CountComments: false
Layout/LineLength:
Max: 120
AllowedPatterns:
- '^\s*#' # Ignore comment lines
Configuration inheritance allows sharing standards across projects:
# .rubocop.yml
inherit_from:
- .rubocop_todo.yml
- config/rubocop_shared.yml
inherit_gem:
rubocop-rails: config/rails.yml
rubocop-rspec: config/rspec.yml
The inherit_from directive loads local configuration files. The inherit_gem directive loads configurations from installed gems. Both mechanisms support multiple inheritance, merging configurations in order.
Inline Configuration
Comments inside Ruby files modify RuboCop behavior for specific lines or blocks:
# Disable a cop for the next line
# rubocop:disable Style/NumericLiterals
API_KEY = 1234567890
# rubocop:enable Style/NumericLiterals
# Disable multiple cops for a block
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
def complex_legacy_method
# ... hundreds of lines ...
end
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
# Disable a cop for the current line (inline)
def process(data) # rubocop:disable Metrics/AbcSize
# method implementation
end
Inline disabling requires justification in code review. Teams establish policies about when disabling is acceptable: legacy code under refactor, generated code, temporary workarounds with follow-up issues.
Custom Cops
Teams create custom cops for project-specific rules. A cop inherits from RuboCop::Cop::Base and implements node pattern matching:
# lib/custom_cops/no_direct_model_access.rb
module CustomCops
class NoDirectModelAccess < RuboCop::Cop::Base
MSG = 'Avoid direct model access in controllers. Use a service object.'
def_node_matcher :model_constant?, <<~PATTERN
(const nil? {:User :Post :Comment})
PATTERN
def on_send(node)
return unless in_controller?
return unless model_constant?(node.receiver)
add_offense(node)
end
private
def in_controller?
processed_source.file_path.include?('app/controllers')
end
end
end
The cop registers with RuboCop through configuration:
# .rubocop.yml
require:
- ./lib/custom_cops/no_direct_model_access
CustomCops/NoDirectModelAccess:
Enabled: true
Custom cops access the AST through node matchers, examining code structure rather than text patterns. This approach catches violations regardless of formatting variations.
RuboCop Todo Files
Large codebases with existing violations use todo files to defer fixes:
# Generate a todo file
rubocop --auto-gen-config
# Creates .rubocop_todo.yml
Style/StringLiterals:
Exclude:
- 'app/models/user.rb'
- 'app/models/post.rb'
# ... hundreds of files ...
Metrics/MethodLength:
Exclude:
- 'app/services/complex_calculation.rb'
The todo file becomes part of the main configuration through inheritance. New code follows the rules strictly. Legacy code violations appear in the todo file. Teams chip away at the todo file, removing entries as they fix violations incrementally.
Implementation Approaches
Big Bang Adoption
Big bang adoption enables all desired cops simultaneously, requiring immediate fixes for all violations. This approach works for small codebases, greenfield projects, or teams willing to pause feature development temporarily. The benefit lies in reaching the desired state immediately without carrying technical debt forward.
The strategy requires dedicated time for fixing violations. A team might allocate a sprint to linting adoption, fixing violations in focused work sessions. Alternatively, the team might freeze feature development while addressing violations. The approach fails when violation counts exceed available fixing capacity or when urgent feature work cannot pause.
Gradual Enablement
Gradual enablement activates cops incrementally, allowing teams to maintain feature velocity while improving code quality. The process begins with non-controversial cops: formatting rules that auto-correct safely. Each iteration adds more cops, fixes existing violations, and monitors adoption success.
# Week 1: Layout cops only
AllCops:
DisabledByDefault: true
Layout:
Enabled: true
# Week 2: Add safe Style cops
Style/StringLiterals:
Enabled: true
Style/HashSyntax:
Enabled: true
# Week 3: Add Lint cops
Lint:
Enabled: true
The incremental approach reduces cognitive load. Developers learn rules gradually, internalize patterns, and build muscle memory. The small violation counts per iteration make fixing manageable. Teams maintain momentum on business features while improving code quality steadily.
Default Disabled Configuration
Some teams start with all cops disabled, enabling specific cops deliberately:
# .rubocop.yml
AllCops:
DisabledByDefault: true
# Explicitly enable desired cops
Layout/IndentationWidth:
Enabled: true
Style/StringLiterals:
Enabled: true
Lint/UnusedMethodArgument:
Enabled: true
This inverted approach forces conscious decisions about every rule. Teams evaluate each cop's value, discuss its implications, and enable only cops with broad support. The configuration grows organically as teams encounter patterns they want to enforce.
The downside appears when new RuboCop versions add valuable cops that remain disabled by default. Teams miss improvements unless they actively review new cop additions.
Strict vs Advisory
Teams choose between strict enforcement (build failures) and advisory reporting (warnings without blocking). Strict enforcement prevents violations from entering the codebase. Advisory reporting highlights issues without blocking progress.
Strict enforcement works for formatting rules with auto-correction. Developers run the auto-corrector before committing, and violations never reach the repository. Advisory enforcement suits complex rules requiring human judgment: refactoring large methods or reducing cyclomatic complexity.
Mixed enforcement allows different severity levels per cop:
# .rubocop.yml
Layout/IndentationWidth:
Severity: error # Block CI builds
Metrics/MethodLength:
Severity: warning # Report but don't block
Metrics/CyclomaticComplexity:
Severity: info # Track but don't highlight
Team Configuration Management
Organizations with multiple repositories maintain shared configurations. A central configuration repository provides base settings that project-specific configurations extend:
# shared-configs/.rubocop.yml (in its own repository)
AllCops:
TargetRubyVersion: 3.2
NewCops: enable
Style/StringLiterals:
EnforcedStyle: single_quotes
Metrics/MethodLength:
Max: 15
# project/.rubocop.yml
inherit_gem:
shared-configs: .rubocop.yml
# Project-specific overrides
Metrics/MethodLength:
Max: 20 # Looser for this legacy project
Shared configurations evolve over time. Updates to the central configuration propagate to all projects when they update the shared-configs gem. Projects opt into updates explicitly through dependency management, allowing gradual adoption of stricter rules.
Practical Examples
Rails Application Setup
A typical Rails application configuration balances framework conventions with team preferences:
# .rubocop.yml
require:
- rubocop-rails
- rubocop-rspec
AllCops:
TargetRubyVersion: 3.2
NewCops: enable
Exclude:
- 'bin/**/*'
- 'db/schema.rb'
- 'db/migrate/*.rb'
- 'vendor/**/*'
- 'node_modules/**/*'
Rails:
Enabled: true
Style/Documentation:
Enabled: false # Many Rails projects skip class documentation
Style/StringLiterals:
EnforcedStyle: single_quotes
ConsistentQuotesInMultiline: true
Style/FrozenStringLiteralComment:
Enabled: true
EnforcedStyle: always
Metrics/BlockLength:
Exclude:
- 'spec/**/*' # RSpec specs often have long blocks
- 'config/routes.rb'
- 'config/environments/*.rb'
Rails/HasManyOrHasOneDependent:
Enabled: true # Enforce dependent: option on associations
Rails/UniqueValidationWithoutIndex:
Enabled: true # Catch uniqueness validations without database indexes
Monorepo Configuration
Monorepos containing multiple Ruby projects require hierarchical configuration:
# Root .rubocop.yml (applies to entire repo)
AllCops:
TargetRubyVersion: 3.2
NewCops: enable
Style/StringLiterals:
EnforcedStyle: single_quotes
# services/api/.rubocop.yml (inherits from root)
inherit_from:
- ../../.rubocop.yml
AllCops:
Exclude:
- 'tmp/**/*'
Rails:
Enabled: true
# services/workers/.rubocop.yml (different rules for background jobs)
inherit_from:
- ../../.rubocop.yml
Metrics/MethodLength:
Max: 20 # Workers often have longer methods
Metrics/CyclomaticComplexity:
Max: 8 # More complex logic acceptable in workers
Each subdirectory inherits from the root configuration and overrides specific rules for its context. API services enforce Rails conventions. Worker services allow longer methods for complex background processing logic.
Pre-commit Hook Integration
Git hooks enforce linting before code reaches the repository:
# .git/hooks/pre-commit
#!/usr/bin/env ruby
changed_files = `git diff --cached --name-only --diff-filter=ACM`.
split("\n").
select { |file| file.end_with?('.rb') }
exit 0 if changed_files.empty?
system("rubocop #{changed_files.join(' ')}")
exit_status = $?.exitstatus
if exit_status != 0
puts "\nRuboCop found violations. Fix them or commit with --no-verify to skip."
exit 1
end
More sophisticated setups use tools like Lefthook or Husky to manage Git hooks across teams:
# lefthook.yml
pre-commit:
parallel: true
commands:
rubocop:
glob: "*.rb"
run: bundle exec rubocop {staged_files}
rubocop-auto-fix:
glob: "*.rb"
run: bundle exec rubocop -A {staged_files}
stage_fixed: true
CI/CD Integration
Continuous integration enforces linting on all pull requests:
# .github/workflows/rubocop.yml
name: RuboCop
on: [push, pull_request]
jobs:
rubocop:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- name: Run RuboCop
run: bundle exec rubocop --format github
The github format outputs annotations that appear inline in pull request diffs. Alternative formats include JSON for parsing by other tools, junit for test reporting dashboards, and html for visual reports.
Custom Cop for Architecture Enforcement
Teams enforce architectural boundaries through custom cops:
# lib/custom_cops/no_cross_boundary_calls.rb
module CustomCops
class NoCrossBoundaryRequires < RuboCop::Cop::Base
MSG = 'Core domain should not require from infrastructure layer'
INFRASTRUCTURE_PATHS = %w[
app/repositories
app/adapters
app/controllers
].freeze
def on_send(node)
return unless node.method_name == :require_relative
return unless in_core_domain?
required_path = node.first_argument.str_content
return unless requires_infrastructure?(required_path)
add_offense(node)
end
private
def in_core_domain?
processed_source.file_path.include?('app/domain')
end
def requires_infrastructure?(path)
INFRASTRUCTURE_PATHS.any? { |infra| path.include?(infra) }
end
end
end
This cop enforces clean architecture by preventing domain logic from depending on infrastructure concerns. The violation appears when domain models require repository or controller code.
Integration & Interoperability
Editor Integration
Modern editors integrate RuboCop through multiple mechanisms. Language Server Protocol implementations provide real-time linting as developers type. Direct editor plugins run RuboCop in response to file events. Each approach offers different characteristics for feedback speed and resource usage.
VS Code integration through the Ruby LSP extension displays violations inline with diagnostic messages. The extension highlights violations with colored underlines, shows detailed messages on hover, and provides quick-fix actions for auto-correctable violations. Configuration happens through workspace settings:
// .vscode/settings.json
{
"ruby.lint": {
"rubocop": true
},
"ruby.format": "rubocop",
"editor.formatOnSave": true,
"ruby.rubocop.useBundler": true
}
RubyMine integrates RuboCop natively through its inspections system. The IDE runs RuboCop analysis continuously, applying violations as inspection warnings. The integration respects RuboCop configuration files and provides IDE-based quick fixes:
# Settings > Editor > Inspections > Ruby > Gems and gem management > RuboCop
Enable RuboCop inspections: true
Run RuboCop inspections on the fly: true
RuboCop executable path: Use bundler
Vim integration typically uses ALE (Asynchronous Lint Engine) or similar plugins. ALE runs linters asynchronously, displaying results without blocking editing:
" .vimrc
let g:ale_linters = {
\ 'ruby': ['rubocop'],
\}
let g:ale_fixers = {
\ 'ruby': ['rubocop'],
\}
let g:ale_fix_on_save = 1
let g:ale_ruby_rubocop_executable = 'bundle'
CI Pipeline Integration
Linting in CI pipelines catches violations that escape local checks. The pipeline configuration determines when linting runs, how violations surface, and whether they block deployment.
GitHub Actions provides native RuboCop integration with pull request annotations:
# .github/workflows/lint.yml
name: Lint
on:
pull_request:
types: [opened, synchronize]
jobs:
rubocop:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- name: RuboCop
run: |
bundle exec rubocop \
--format json \
--out rubocop-results.json \
--format github
- name: Annotate PR
if: failure()
uses: reviewdog/action-rubocop@v2
with:
rubocop_version: gemfile
reporter: github-pr-review
GitLab CI integrates through Code Quality reports:
# .gitlab-ci.yml
rubocop:
stage: test
script:
- bundle exec rubocop --format json --out rubocop.json
artifacts:
reports:
codequality: rubocop.json
when: always
The Code Quality report shows violations in merge request diffs as inline comments. GitLab tracks quality trends across commits, showing whether code quality improves or degrades over time.
Pull Request Automation
Automated pull request checks enforce linting before human review. Review bots examine changed files, run linting, and comment on violations:
# .pronto.yml
github:
slug: organization/repository
access_token: <%= ENV['GITHUB_ACCESS_TOKEN'] %>
runners:
- rubocop
rubocop:
config_file: .rubocop.yml
Pronto runs linting on changed files only, reducing noise from pre-existing violations. The bot posts comments on specific lines containing violations, allowing developers to fix issues before reviewers examine the code.
Danger provides more flexible automation through Ruby scripts:
# Dangerfile
rubocop.lint(inline_comment: true)
if rubocop.violations.any?
warn "Please fix RuboCop violations before merging"
end
# Require documentation for public APIs
changed_files = git.modified_files + git.added_files
public_methods = changed_files.grep(/app\/(models|services)/).any? do |file|
File.read(file).include?('def self.')
end
if public_methods && rubocop.violations.any? { |v| v[:cop_name] == 'Style/Documentation' }
fail "Public API methods require documentation"
end
Git Hooks
Git hooks enforce linting at different points in the development workflow. Pre-commit hooks catch violations before they enter version control. Pre-push hooks run heavier analysis before code reaches remote repositories.
Lefthook provides cross-platform hook management:
# lefthook.yml
pre-commit:
parallel: true
commands:
rubocop-changed:
glob: "*.rb"
run: bundle exec rubocop --force-exclusion {staged_files}
rubocop-auto-fix:
glob: "*.rb"
run: bundle exec rubocop -A --force-exclusion {staged_files}
stage_fixed: true
pre-push:
commands:
rubocop-full:
run: bundle exec rubocop
The configuration runs fast checks on staged files during commit, reserving full repository analysis for the pre-push hook. Auto-fixing stages corrections automatically, ensuring consistent formatting without manual intervention.
Overcommit offers similar functionality with Ruby-based configuration:
# .overcommit.yml
PreCommit:
RuboCop:
enabled: true
on_warn: fail
command: ['bundle', 'exec', 'rubocop']
flags: ['--force-exclusion']
PrePush:
RuboCop:
enabled: true
required: true
command: ['bundle', 'exec', 'rubocop']
Development Workflow Integration
Linting integrates into development workflows at multiple points. Format-on-save provides immediate correction. Commit hooks prevent violations from entering version control. CI checks block merges containing violations. Each layer provides defense in depth.
Developers configure their environment to run auto-correction on save:
# .vscode/settings.json
{
"editor.formatOnSave": true,
"ruby.format": "rubocop"
}
The editor runs RuboCop with auto-correction flags whenever the developer saves a file. Formatting violations disappear immediately, maintaining consistency without conscious effort.
Watch mode enables continuous linting during development:
# Use guard to watch files
# Guardfile
guard :rubocop, all_on_start: false, cli: ['--auto-correct'] do
watch(%r{^.+\.rb$})
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
end
Guard monitors file changes and runs RuboCop automatically. Developers see violations moments after creating them, reducing the feedback loop from minutes to seconds.
Reference
Common RuboCop Cops
| Cop Name | Department | Description | Auto-correctable |
|---|---|---|---|
| Layout/IndentationWidth | Layout | Checks for correct indentation width | Yes |
| Layout/TrailingWhitespace | Layout | Detects trailing whitespace at end of lines | Yes |
| Layout/EmptyLineAfterGuardClause | Layout | Requires empty line after guard clause | Yes |
| Style/StringLiterals | Style | Enforces single or double quote consistency | Yes |
| Style/HashSyntax | Style | Enforces modern hash syntax where possible | Yes |
| Style/FrozenStringLiteralComment | Style | Requires frozen string literal comment | Yes |
| Style/Documentation | Style | Requires class and module documentation | No |
| Style/SymbolArray | Style | Enforces symbol array literal syntax | Yes |
| Metrics/MethodLength | Metrics | Flags methods exceeding line count threshold | No |
| Metrics/CyclomaticComplexity | Metrics | Calculates cyclomatic complexity of methods | No |
| Metrics/AbcSize | Metrics | Measures assignment, branch, condition complexity | No |
| Lint/UnusedMethodArgument | Lint | Detects method arguments never used | Yes |
| Lint/ShadowingOuterLocalVariable | Lint | Flags variables shadowing outer scope | No |
| Lint/Debugger | Lint | Detects leftover debugging statements | Yes |
| Lint/UnreachableCode | Lint | Identifies code after unconditional exit | No |
| Performance/StringReplacement | Performance | Suggests faster string replacement methods | Yes |
| Performance/FlatMap | Performance | Recommends flat_map over map.flatten | Yes |
| Rails/HasManyOrHasOneDependent | Rails | Enforces dependent option on associations | No |
| Rails/UniqueValidationWithoutIndex | Rails | Requires database index for uniqueness validation | No |
| Security/Eval | Security | Detects dangerous dynamic code evaluation | No |
| Security/JSONLoad | Security | Flags unsafe JSON parsing methods | Yes |
Configuration Options
| Option | Location | Purpose | Example |
|---|---|---|---|
| TargetRubyVersion | AllCops | Sets minimum Ruby version for syntax | 3.2 |
| NewCops | AllCops | Controls automatic enabling of new cops | enable, disable, pending |
| Exclude | AllCops or per-cop | Files/patterns to skip | db/schema.rb, vendor/** |
| DisabledByDefault | AllCops | Inverts default enabled state | true, false |
| EnforcedStyle | Style cops | Selects enforcement variant | single_quotes, double_quotes |
| Enabled | Any cop | Activates or deactivates cop | true, false |
| Severity | Any cop | Sets violation severity level | error, warning, info |
| Max | Metrics cops | Threshold for metric violations | 15, 20, 25 |
| AutoCorrect | Any cop | Enables auto-correction | true, false |
| inherit_from | Root level | Loads additional config files | .rubocop_todo.yml |
| inherit_gem | Root level | Loads gem-provided configs | rubocop-rails: config/rails.yml |
Command Line Options
| Flag | Purpose | Usage |
|---|---|---|
| -a, --auto-correct | Auto-correct safe violations | rubocop -a |
| -A, --auto-correct-all | Auto-correct all violations including unsafe | rubocop -A |
| --format | Output format selection | rubocop --format json |
| --out | Redirect output to file | rubocop --out report.html |
| --force-exclusion | Apply exclusions even with explicit paths | rubocop --force-exclusion app/models |
| --only | Run specific cops only | rubocop --only Layout/IndentationWidth |
| --except | Skip specific cops | rubocop --except Style/Documentation |
| --fail-level | Set minimum severity for exit code | rubocop --fail-level warning |
| --display-cop-names | Show cop names in output | rubocop --display-cop-names |
| --config | Use specific config file | rubocop --config config/strict.yml |
| --auto-gen-config | Generate todo file | rubocop --auto-gen-config |
| --regenerate-todo | Update existing todo file | rubocop --regenerate-todo |
Inline Configuration Syntax
| Pattern | Purpose | Example |
|---|---|---|
| rubocop:disable CopName | Disable cop until re-enabled | # rubocop:disable Metrics/MethodLength |
| rubocop:enable CopName | Re-enable previously disabled cop | # rubocop:enable Metrics/MethodLength |
| rubocop:disable all | Disable all cops until re-enabled | # rubocop:disable all |
| rubocop:todo CopName | Mark as intentional technical debt | # rubocop:todo Metrics/CyclomaticComplexity |
| Inline disable | Disable cop for single line | def method # rubocop:disable Metrics/AbcSize |
| Multiple cops | Disable multiple cops simultaneously | # rubocop:disable Style/Documentation, Metrics/MethodLength |
Output Formats
| Format | Purpose | Use Case |
|---|---|---|
| progress | Default progress indicator | Interactive terminal use |
| simple | Human-readable list | Command line review |
| json | Machine-parseable output | CI integration, tool consumption |
| html | Visual report with styling | Documentation, stakeholder reports |
| junit | JUnit XML format | Test reporting dashboards |
| github | GitHub Actions annotations | Pull request inline comments |
| offense_count | Count by cop type | Tracking improvement over time |
| worst_offenders | Most violated files | Prioritizing refactoring |
| tap | Test Anything Protocol | Test harness integration |
Severity Levels
| Level | Meaning | CI Behavior | Editor Display |
|---|---|---|---|
| error | Critical violation requiring fix | Fails build | Red underline |
| warning | Violation should be addressed | Passes build with warnings | Yellow underline |
| info | Informational only | Ignored | Blue underline |
| convention | Style preference | Configurable | Gray underline |
| refactor | Code smell requiring refactor | Configurable | Orange underline |
Department Categories
| Department | Focus | Example Cops |
|---|---|---|
| Layout | Code formatting and whitespace | IndentationWidth, TrailingWhitespace |
| Style | Idiomatic Ruby conventions | StringLiterals, HashSyntax, SymbolArray |
| Metrics | Complexity and size measurements | MethodLength, CyclomaticComplexity, AbcSize |
| Lint | Bug detection and suspicious patterns | UnusedMethodArgument, ShadowingOuterLocalVariable |
| Performance | Performance improvements | StringReplacement, FlatMap, ReverseEach |
| Security | Security vulnerabilities | Eval, JSONLoad, Open |
| Rails | Rails framework conventions | HasManyOrHasOneDependent, OutputSafety |
| RSpec | RSpec test organization | MultipleExpectations, NestedGroups |
| Migration | Rails migration best practices | ChangeColumn, RemoveColumn |
| Naming | Naming conventions | MethodName, VariableName, ConstantName |