johnallen3d
10/27/2015 - 12:18 PM

Technekes Rubocop Introduction and Instructions

Technekes Rubocop Introduction and Instructions

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

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

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.