Add Rubocop to every Rails project

The longer I have been in programming, the more I think that following best practices for coding style is an essential quality of a good programmer. When working on a team, I find many people want to debate about these things. While this can be fun, after a while it can become a time suck and a waste of energy. The best thing is to simply agree on a standard style guide and conform to it.

In April 2014, I was introduced to Rubocop. Similar to JSLint, Rubocop follows a standard Ruby style guide and includes a command line program for checking for clear violations. It has a clearly defined style guide that is customizable via a yaml file. What follows is how I use it in my current Ruby on Rails projects.

RoboCop

Getting started

After following the Rubocop gem installation instructions, checking for violations is simple:

$ rubocop

If it is an existing project, there will be tons of violations. This should not overwhelm because Rubocop has a nice way of letting me gradually fix violations. By creating the .rubocop_todo.yml file, I see the work that needs to be done. To do this:

$ rubocop --auto-gen-config

Next, I create a the .rubocop.yml file. My standard .rubocop.yml file looks like this. It inherits from the .rubocop_todo.yml. It excludes files that are generated by Rails itself. It also includes some of my opinions about what is acceptable violations. For example, I don’t find empty lines around modules and blocks to be violations.

inherit_from: .rubocop_todo.yml

AllCops:
  Exclude:
    - db/schema.rb
    - db/migrate/*
    - bin/*
  RunRailsCops: true

Documentation:
  Enabled: false

DotPosition:
  EnforcedStyle: trailing

Style/EmptyLinesAroundBlockBody:
  Enabled: false

Style/EmptyLinesAroundModuleBody:
  Enabled: false

Style/EmptyLinesAroundClassBody:
  Enabled: false

Style/EmptyLinesAroundMethodBody:
Enabled: false

Now, I should have a clean run when I do:

$ rubocop

Next, I add a task that runs on the continuous integration server to make sure this is enforced. I create a file lib/tasks/ci.rake and add two rake tasks: ci:rubocop and ci:rubocop_changed. One will run on CI and the other will run as part of my ‘git’ pre-commit hook. The tasks looks like this:

On my continuous integration server, I will add bundle exec rake ci:rubocop as step in the build.

Locally, I change my .git/hooks/pre-commit to include:

Now when I do a git commit, Rubocop will run on my local files making sure I am not checking in files that are in violation.

Fixing Violation

Now that I am setup to have Rubocop police my programming, I can fix existing style violations in the code. The first and easiest to fix are violations that can be auto-corrected by Rubocop itself.

To do this, I open .rubocop_todo.yml in my favorite editor (at the moment it is Atom). I search or scan this file for rules that have the comment “# Cop supports --auto-correct” about them. For example:

# Offense count: 1
# Cop supports --auto-correct.
Lint/StringConversionInInterpolation:
  Enabled: false

# Offense count: 1
# Cop supports --auto-correct.
Lint/BlockAlignment:
  Enabled: false

I comment out the first rule using the #, like this:

# Offense count: 1
# Cop supports --auto-correct.
# Lint/StringConversionInInterpolation:
#  Enabled: false

# Offense count: 1
# Cop supports --auto-correct.
Lint/BlockAlignment:
  Enabled: false

Next, I run Rubocop’s auto-correct feature from the command line and Rubocop shows me which files it corrects:

$ rubocop -a
Inspecting 71 files
..................................................W....................

Offenses:

spec/controllers/v1/widgets_controller_spec.rb:67:8: W: [Corrected] end at 67, 7 is not aligned with it 'has client url' do at 65, 6
       end
       ^^^

71 files inspected, 1 offense detected, 1 offense corrected

Finally, I commit this change to git with a note about the rule that was fixed:

$ git commit  -m "Fix Lint/BlockAlignment violation found by Rubocop" spec/controllers/v1/widgets_controller_spec.rb

I then re-run the auto-gen command a get a new version of the .rubocop_todo.yml that has this violation removed.

$ rubocop --auto-gen-config
$ git diff .rubocop_todo.yml
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 2f55803..e87e458 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,16 +1,11 @@

-# Offense count: 1
-# Cop supports --auto-correct.
-Lint/BlockAlignment:
-  Enabled: false
-

This procedure can be repeated until most violations in the .rubocop_todo.yml. Usually, I will wait until most are fixed before committing a new version of the .rubocop_todo.yml.