CrackedRuby logo

CrackedRuby

RuboCop

A comprehensive guide to using RuboCop for static code analysis and automatic formatting in Ruby projects.

Testing and Quality Code Quality Tools
8.3.1

Overview

RuboCop is a Ruby static code analyzer and formatter based on the Ruby Style Guide. It examines Ruby code and reports violations of style guidelines, potential bugs, and code smells while providing automatic correction capabilities for many issues.

RuboCop operates through a collection of cops (analyzers) organized into departments like Layout, Style, Lint, Metrics, and Naming. Each cop checks for specific patterns and can suggest or automatically apply corrections. The tool integrates with editors, CI systems, and development workflows to maintain code quality across Ruby projects.

The main classes include RuboCop::CLI for command-line operations, RuboCop::Runner for executing cops, and RuboCop::Cop::Base as the foundation for all analysis rules. Configuration happens through .rubocop.yml files that define which cops to enable, their severity levels, and customization options.

# Basic RuboCop violation
def bad_method( x,y )
  return x+y
end

# RuboCop-compliant version
def good_method(first, second)
  first + second
end

RuboCop supports multiple output formats including JSON, JUnit XML, and human-readable text. The auto-correction feature can fix many violations automatically, while others require manual intervention based on the cop's design and safety considerations.

# Running RuboCop programmatically
require 'rubocop'

cli = RuboCop::CLI.new
result = cli.run(['--format', 'json', 'app/'])
# Returns exit code: 0 for success, 1 for violations found

Basic Usage

Install RuboCop through gem installation and run it against Ruby files or directories. The basic command analyzes code and reports violations with file locations, line numbers, and descriptions of issues found.

# Gemfile
gem 'rubocop', require: false

# Command line usage
bundle exec rubocop
bundle exec rubocop app/models/
bundle exec rubocop --auto-correct app/controllers/users_controller.rb

The --auto-correct flag applies safe corrections automatically, while --auto-correct-all includes potentially unsafe corrections. Use --safe-auto-correct to apply only corrections marked as safe by cop authors.

# Example violations RuboCop detects
class UserService
  def initialize(user)
    @user=user  # Style/SpaceAroundOperators
  end
  
  def process()  # Style/DefWithParentheses
    if @user.nil?  # Style/GuardClause
      return false
    end
    
    @user.update(status: 'active')
    return true  # Style/RedundantReturn
  end
end

Configuration files control RuboCop behavior through .rubocop.yml placed in project root or parent directories. RuboCop searches upward through the directory tree until it finds configuration files, merging settings hierarchically.

# .rubocop.yml
AllCops:
  TargetRubyVersion: 3.0
  NewCops: enable
  Exclude:
    - 'vendor/**/*'
    - 'db/schema.rb'

Style/Documentation:
  Enabled: false

Metrics/LineLength:
  Max: 120

Individual cops accept configuration parameters that modify their behavior. Common parameters include Max for metric cops, Enabled for turning cops on/off, and cop-specific options that change detection patterns.

# Running specific cops or departments
bundle exec rubocop --only Style/TrailingCommaInHashLiteral
bundle exec rubocop --except Lint/UnusedMethodArgument
bundle exec rubocop --only Style,Layout

The --display-cop-names flag shows which cop triggered each offense, helping identify patterns and configure suppressions. Use --display-only-fail-level-offenses to see only violations that would cause RuboCop to exit with a failure status.

Advanced Usage

Custom cop development allows teams to enforce project-specific rules beyond RuboCop's built-in cops. Create custom cops by inheriting from RuboCop::Cop::Base and implementing node pattern matching for Abstract Syntax Tree analysis.

# lib/custom_cops/no_sleep_cop.rb
module CustomCops
  class NoSleepCop < RuboCop::Cop::Base
    MSG = 'Avoid using `sleep` in production code.'
    
    RESTRICT_ON_SEND = [:sleep].freeze
    
    def on_send(node)
      return unless node.method_name == :sleep
      
      add_offense(node, message: MSG)
    end
    
    def on_block(node)
      return unless node.send_node.method_name == :sleep
      
      add_offense(node, message: MSG)
    end
  end
end

Advanced configuration includes cop inheritance, shared configurations, and conditional enabling based on Ruby version or gems present. Use inherit_from to include external configuration files and inherit_mode to control merge behavior.

# .rubocop.yml with inheritance
inherit_from:
  - .rubocop_todo.yml
  - config/rubocop_shared.yml

inherit_mode:
  merge:
    - Exclude
    - Include

AllCops:
  TargetRubyVersion: 3.1
  SuggestExtensions: false
  
# Conditional cop configuration
Style/FrozenStringLiteralComment:
  Enabled: true
  EnforcedStyle: always
  SupportedStyles:
    - always
    - never

Department-level configuration applies settings to multiple related cops simultaneously. Configure entire departments through Department/All syntax or create custom departments for organization-specific rule groupings.

# Department configuration
Layout:
  Enabled: true
  
Style/All:
  Exclude:
    - 'spec/**/*'
    - 'test/**/*'

Lint:
  Severity: error
  
Metrics/All:
  Exclude:
    - 'db/migrate/**/*'

Complex pattern matching in custom cops uses RuboCop's node pattern DSL for sophisticated AST analysis. Define patterns using def_node_matcher and def_node_search macros for reusable node detection logic.

class ComplexPatternCop < RuboCop::Cop::Base
  extend AutoCorrector
  
  MSG = 'Use specific exception classes instead of StandardError.'
  
  def_node_matcher :raises_standard_error?, <<~PATTERN
    (send nil? :raise (const nil? :StandardError) ...)
  PATTERN
  
  def on_send(node)
    return unless raises_standard_error?(node)
    
    add_offense(node) do |corrector|
      corrector.replace(node.arguments.first, 'RuntimeError')
    end
  end
end

Production Patterns

Continuous Integration integration requires careful RuboCop configuration to balance code quality enforcement with development velocity. Configure RuboCop to run as part of CI pipelines while handling incremental adoption and legacy code exceptions.

# .github/workflows/rubocop.yml
name: RuboCop
on: [push, pull_request]

jobs:
  rubocop:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.1
          bundler-cache: true
      - run: bundle exec rubocop --parallel --format github

Team workflow integration involves establishing RuboCop TODO files for gradual improvement and consistent developer environment setup. Use rubocop --auto-gen-config to generate TODO files that exclude existing violations while enforcing rules for new code.

# Generated .rubocop_todo.yml
# This configuration was generated by
# `rubocop --auto-gen-config`

Metrics/AbcSize:
  Exclude:
    - 'app/controllers/admin/reports_controller.rb'
    - 'lib/data_processor.rb'

Style/Documentation:
  Exclude:
    - 'app/models/legacy_user.rb'
    - 'spec/**/*'

# Set target for gradual improvement
Metrics/LineLength:
  Max: 100  # Decrease from current 120 over time

Editor integration streamlines development workflow through real-time feedback and automatic correction on save. Configure editors to run RuboCop on file save or provide inline violation display during coding.

# VS Code settings.json
{
  "ruby.rubocop.onSave": true,
  "ruby.rubocop.configFilePath": ".rubocop.yml",
  "editor.formatOnSave": true,
  "ruby.format": "rubocop"
}

# Vim configuration with ALE
let g:ale_linters = {'ruby': ['rubocop']}
let g:ale_fixers = {'ruby': ['rubocop']}
let g:ale_ruby_rubocop_options = '--display-cop-names'
let g:ale_fix_on_save = 1

Large codebase strategies involve incremental adoption, selective enabling, and performance optimization. Configure RuboCop to focus on specific file patterns or directories while excluding generated code and vendor dependencies.

# Incremental adoption strategy
AllCops:
  Include:
    - 'app/**/*.rb'
    - 'lib/**/*.rb'
  Exclude:
    - 'vendor/**/*'
    - 'db/schema.rb'
    - 'config/routes.rb'
    - 'bin/**/*'

# Performance optimization
AllCops:
  UseCache: true
  MaxFilesInCache: 50000
  CacheRootDirectory: '/tmp'
  
# Enable only critical cops initially
Style/All:
  Enabled: false
  
Lint/All:
  Enabled: true
  
Layout/TrailingWhitespace:
  Enabled: true

Performance & Memory

RuboCop performance optimization becomes critical on large codebases where analysis time impacts development workflow. Enable caching, parallel execution, and selective cop running to reduce analysis time from minutes to seconds.

Cache configuration stores analysis results between runs, dramatically improving performance for unchanged files. The cache stores file modification times, checksums, and previous analysis results in a local directory structure.

# Performance-optimized configuration
AllCops:
  UseCache: true
  CacheRootDirectory: tmp/rubocop_cache
  MaxFilesInCache: 100000
  
# Enable parallel processing
bundle exec rubocop --parallel

File exclusion patterns prevent RuboCop from analyzing irrelevant files, reducing memory usage and execution time. Exclude generated files, vendor code, and test fixtures that don't require style enforcement.

# .rubocop.yml exclusion patterns
AllCops:
  Exclude:
    - 'vendor/**/*'
    - 'node_modules/**/*'
    - 'db/schema.rb'
    - 'db/structure.sql'
    - 'coverage/**/*'
    - 'tmp/**/*'
    - 'log/**/*'
    - 'public/assets/**/*'
    - '*.gemspec'

Memory usage optimization involves configuring garbage collection and limiting concurrent processes. Large codebases may require Ruby GC tuning and process memory limits to prevent system resource exhaustion.

# Environment variables for memory optimization
export RUBY_GC_HEAP_INIT_SLOTS=600000
export RUBY_GC_HEAP_FREE_SLOTS=600000
export RUBY_GC_HEAP_GROWTH_FACTOR=1.25
export RUBY_GC_HEAP_GROWTH_MAX_SLOTS=300000

# Limited parallel execution
bundle exec rubocop --parallel --fail-level warn

Selective cop execution reduces analysis time by running only relevant cops for specific scenarios. Use --only and --except flags to target specific violations or run lightweight cops during development.

# Fast feedback during development
alias rubocop-fast='bundle exec rubocop --only Style/TrailingWhitespace,Layout/TrailingBlankLines,Style/TrailingCommaInLiteral'

# Security-focused analysis
alias rubocop-security='bundle exec rubocop --only Lint/SecurityCop,Lint/UnreachableCode,Lint/UselessAssignment'

# Metrics-only analysis for code review
bundle exec rubocop --only Metrics --format json > metrics_report.json

Common Pitfalls

Configuration inheritance creates subtle behavior where multiple configuration files merge unexpectedly, causing cops to behave differently than intended. RuboCop searches parent directories for configuration files and merges them hierarchically.

# Problem: Unexpected cop enabling
# Parent directory .rubocop.yml
Style/Documentation:
  Enabled: true

# Current directory .rubocop.yml  
Style/StringLiterals:
  EnforcedStyle: single_quotes
# Documentation cop still enabled despite expectations

Auto-correction safety varies significantly between cops, with some corrections changing code semantics rather than just formatting. Review auto-corrected changes carefully, especially for cops marked as unsafe corrections.

# Unsafe auto-correction example
# Original code
def calculate(items)
  items.map { |item| item.price * item.quantity }
     .reduce(:+) || 0
end

# RuboCop suggests Style/SafeNavigation
def calculate(items)
  items.map { |item| item.price * item.quantity }
     .reduce(:+) || 0  # This change could alter behavior
end

Cop conflicts occur when multiple cops suggest contradictory changes to the same code, creating endless correction cycles. Common conflicts involve string quoting, line length, and method complexity cops.

# Conflicting cops example
very_long_method_name_that_exceeds_line_length(
  parameter_one: "single quotes",
  parameter_two: 'mixed quotes cause conflicts'
)

# Metrics/LineLength wants shorter lines
# Style/StringLiterals wants consistent quotes  
# Layout/MultilineMethodCallIndentation wants specific formatting

False positive violations appear when RuboCop misinterprets code context or domain-specific patterns. Configure cop exclusions for legitimate code patterns that violate style guides for valid reasons.

# False positive: Metrics/AbcSize in DSL code
class ApiEndpoint
  # This pattern triggers complexity warnings
  # but represents clean DSL usage
  post '/users' do
    validate_params(params)
    authenticate_request
    authorize_action(:create)
    sanitize_input(params)
    create_user(params)
    render_response(user)
    log_activity(user)
    send_notifications(user)
    update_metrics(:user_created)
  end
end

# Solution: Exclude DSL patterns
Metrics/AbcSize:
  Exclude:
    - 'app/api/**/*'

Version compatibility issues arise when RuboCop cops target newer Ruby versions than the project supports, causing syntax errors or unavailable method suggestions. Configure TargetRubyVersion to match project requirements.

# .rubocop.yml version configuration
AllCops:
  TargetRubyVersion: 2.7  # Match project Ruby version
  NewCops: disable  # Prevent new cops in updates
  
# Cop-specific version requirements
Style/HashEachMethods:
  Enabled: true
  VersionAdded: 0.80
  VersionChanged: 0.90
  Safe: true

Reference

Core Commands

Command Parameters Description
rubocop [files/dirs] Analyze specified files or current directory
rubocop --auto-correct [files] Apply safe automatic corrections
rubocop --auto-correct-all [files] Apply all automatic corrections including unsafe
rubocop --only COP_NAME cop_name Run only specified cops
rubocop --except COP_NAME cop_name Run all cops except specified
rubocop --parallel none Enable parallel processing

Configuration Options

Option Type Default Description
TargetRubyVersion String Latest Ruby version for compatibility
UseCache Boolean true Enable result caching
CacheRootDirectory String tmp/rubocop_cache Cache storage location
NewCops String pending How to handle new cops in updates
SuggestExtensions Boolean true Suggest RuboCop extensions
MaxFilesInCache Integer 20000 Maximum cached files

Cop Departments

Department Focus Example Cops
Layout Code formatting LineLength, IndentationWidth, TrailingWhitespace
Style Code style StringLiterals, Documentation, GuardClause
Lint Potential bugs UnusedVariable, ShadowingOuterLocalVariable
Metrics Code complexity AbcSize, CyclomaticComplexity, LineLength
Naming Naming conventions MethodName, ConstantName, VariableName
Security Security issues Eval, MarshalLoad, YAMLLoad

Severity Levels

Level Exit Code Description
info 0 Informational messages
refactor 1 Code improvement suggestions
convention 1 Style guide violations
warning 1 Potential problems
error 1 Definite problems
fatal 2 Syntax errors, crashes

Output Formats

Format Description Use Case
simple Human-readable text Development
json JSON structure Tool integration
junit JUnit XML CI systems
github GitHub Actions GitHub workflows
clang Clang-style format Editor integration
emacs Emacs compilation Emacs integration

Auto-Correction Safety

Safety Level Description Command Flag
Safe No semantic changes --auto-correct
Unsafe Potential semantic changes --auto-correct-all
Safe only Force safe corrections only --safe-auto-correct

Configuration Inheritance

Method Behavior Example
inherit_from Include external configs inherit_from: .rubocop_shared.yml
inherit_mode Control merge behavior inherit_mode: { merge: [Exclude] }
Directory traversal Search parent directories Automatic upward search

Common Cop Parameters

Parameter Type Description Example
Enabled Boolean Enable/disable cop Enabled: false
Severity String Override severity level Severity: warning
Exclude Array File patterns to skip Exclude: ['spec/**/*']
Include Array File patterns to check Include: ['**/*.rake']
Max Integer Maximum threshold Max: 120
EnforcedStyle String Style variation EnforcedStyle: single_quotes