Adding just those 3 lines plus a gem dependency on our percy-style gem is all that’s now required for us to share styles across all of our Ruby projects.

So what’s in percy-style? Well, it’s open source!

You’ll notice that there is nothing special going on there, it is a standard Ruby gem created using bundle gem and we just dropped a default.yml in the root folder. The defaults in that file define our internal shared rubocop configs and style decisions, it’s something you’d want to customize for your team’s own style.

Shared RuboCop version

One extra thing we included in the repo was adding this to the gemspec:

spec.add_dependency "rubocop", "~> 0.49"

spec.add_dependency "rubocop-rspec", "~> 1.15"

Notice that this is add_dependency and not add_development_dependency which you may see more frequently. By making rubocop and rubocop-rspec a dependency, any project that brings in percy-style gets rubocop as well and can run:

$ bundle exec rubocop

…without actually including gem 'rubocop' in the project directly.

Even though transitive dependencies like this are usually frowned upon, we’ve found that in this case it helps us more easily maintain a consistent RuboCop version across all of our projects. Since new versions of RuboCop can introduce new style rules (and violations), making a single global place for upgrades helps us keep things in sync.

Style overrides

Sometimes, though we try to avoid it, it’s still necessary to override style rules in a project. Thankfully, RuboCop provides a nice inheritance hierarchy so that you can define overrides. The trail goes:

inherit_gem → inherit_from → local rules

Any local rules in the .rubocop.yml will take precedence over inheriting from a local project file, which will take precedence over inheriting from a gem.

For example, in our internal Rails app, we have:

inherit_gem:

percy-style:

- default.yml inherit_from: .rubocop_todo.yml AllCops:

Exclude:

- db/schema.rb

- db/migrate/*.rb

This helps us have some local style exceptions for our API app that we don’t necessarily want to share across all projects.