Skip to content

Instantly share code, notes, and snippets.

@johnallen3d
Last active January 4, 2016 22:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnallen3d/36da743fee550d91bef0 to your computer and use it in GitHub Desktop.
Save johnallen3d/36da743fee550d91bef0 to your computer and use it in GitHub Desktop.
Technekes Rubocop Introduction and Instructions

A goal of the engineering team is to improve code quality and consistancy. One of the simplest ways to head in that direction is to start (or further) the use of RuboCop. If you're not farmiliar, RuboCop is a static Ruby code analyzer that use a common Ruby Style Guide as it's basis for enforcing standards. Once installed (it's just a gem) the RuboCop binary can be used as part of our development workflow to help enforce standards and consistancy on a change by change basis (with the help of Guard for example).

Realizing that some projects currently have a version of RuboCop setup and some do not at all we would like to take a gradual approach to introducing RuboCop. The idea would be to get RuboCop installed on an existing code base and then disable all of the cops that are not passing at the outset. From there we would spend a little time each week (or as you're naturally editing an existing piece of code) bringing things up to snuff. In addition we will hook RuboCop into our CI scripts and fail builds if all cops are not passing.

Installation

Add RuboCop for dev and test groups in your Gemfile.

group :development, :test do
  gem 'rubocop'
end

Install RuboCop

> bundle install

Configuration

Copy the standard Technekes configuration for RuboCop to the project.

> curl -o .rubocop.yml https://gist.githubusercontent.com/johnallen3d/36da743fee550d91bef0/raw/rubocop.yml

Generate an override configuration file for existing projects. The generated file .rubocop_todo.yml contains configuration to disable cops that currently detect an offense in the code by excluding the offending files, or disabling the cop altogether once a file count limit has been reached.

> bundle exec rubocop --auto-gen-config

Usage

From the projects root run the rubocop command to execute the cops.

> bundle exec rubocop

Integration

In order to make RuboCop part of our daily workflow let's get it integrated with rake, guard and CI.

Development / Testing

Add Rubocop to the default rake task in your Rakefile (may need to be tailored to project).

# Rakefile
if %w(development test).include?(ENV['RAILS_ENV'])
  require 'rspec/core/rake_task'
  require 'rubocop/rake_task'

  RSpec::Core::RakeTask.new(:spec) do |spec|
    spec.pattern = 'spec/**/*_spec.rb'
  end

  RuboCop::RakeTask.new(:rubocop)

  task default: [:rubocop, :spec]
end

With this configuration simply running rake (or bundle exec rake if required) will run all specs and RuboCop. For example:

> bundle exec rake
Running RuboCop...
Inspecting 19 files
...................

19 files inspected, no offenses detected

/usr/local/bin/ruby -I/usr/local/bundle/gems/rspec-core-3.3.2/lib:/usr/local/bundle/gems/rspec-support-3.3.0/lib /usr/local/bundle/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\*\*/\*_spec.rb
No examples found.

Finished in 0.00018 seconds (files took 0.06957 seconds to load)
0 examples, 0 failures

Guard

If the project you're working on is configured with Guard (if not, why?!?) then the guard-rubocop gem can be used to integrate RuboCop into your Guard workflow.

Include the Guard plugins for RSpec and RuboCop.

group :development, :test do
  gem 'rubocop'
  gem 'guard-rspec'
  gem 'guard-rubocop'
end

Install Guard and it's plugins.

> bundle install
> bundle exec guard init rspec
> bundle exec guard init rubocop

Execute the Guard binary to start watching files.

> bundle exec guard
# inside a container?
> guard -p -l 5

Editor Integration

There are many editor plugin that will help make RuboCop part of your everyday development workflow. Check out the editor integration section in the RuboCop README for details on your editor of choice.

Continuous Integration

If the project has a CI script or task that relies on the default rake task then RuboCop is now also integrated with CI builds. If not either modify the CI script/task to run the default rake task or append bundle exec rubocop along side the RSpec command.

For example a ci script (./script/ci) might look like this.

#!/bin/bash

echo "perform necessary setup"
# bundle exec rake db:migrate

echo "run all specs and rubocop"
bundle exec rake
inherit_from:
- .rubocop_todo.yml
AllCops:
Exclude:
- vendor/**
- bin/**
- config/environments/**
Documentation:
# don't require classes to be documented
Enabled: false
Encoding:
# no need to always specify encoding
Enabled: false
AlignParameters:
# allow for multi-line methods to have normal indentation.
# for example:
#
# Person.where(
# first_name: 'tom',
# last_name: 'foolery'
# )
EnforcedStyle: with_fixed_indentation
Style/AlignParameters:
# allow for end of if to be aligned with a variable.
# for example:
#
# foo = if a == b
# 'bar'
# else
# 'baz'
# end
EnforcedStyle: with_fixed_indentation
Lint/EndAlignment:
AlignWith: variable
ClassAndModuleChildren:
# ok to use compact style when modules are predefined.
# for example the following is fine so long as we're sure that
# module MDB has already been required/defined.
#
# class MDB::Person; end
Enabled: false
@brittanys
Copy link

@johnallen3d
Here's the rubocop configuration that resolved what we thought Lint/EndAlignment would do:

Style/AlignParameters:
  # allow for `end` of if to be aligned with a variable.
  # for example:
  #
  # foo = if a == b
  #   'bar'
  # else
  #   'baz'
  # end
  EnforcedStyle: with_fixed_indentation

@brittanys
Copy link

Style/ElseAlignment:
  Enabled: false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment