A Standard way to lint your views
This blog post was originally posted at thoughtbot.com/blog.
#Why Standard?
In our Ruby guide we recommend using Standard. The gem describes itself as a Ruby style guide, linter, and formatter. It helps avoid the never-ending debates around code style by making decisions for us (I'm looking at you single vs double quotes!). It’s easy to use, consistent, avoids configuration and helps us write better styled and more consistent Ruby code.
#Introducing erb-lint
As developers, we often write HTML when working with Ruby. It can be useful to
lint our .erb
templates to ensure consistency and catch errors. The
erb-lint gem from Shopify is a tool to lint our views. The linters enabled by
default are outlined in the documentation.
We can run both tools as part of CI. Here’s how to do that in GitHub Actions.
# .github/workflows/lint.yml
name: Lint
on: push
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Run Standard
run: bundle exec standardrb
- name: Run erb-lint
run: bundle exec erblint --lint-all
Erb-lint can also run Rubocop to lint the Ruby code inside our views. The documentation demonstrates how to setup Rubocop linting with some basic configuration. But what about if we want to use Standard to lint the Ruby code in our views instead?
#Running Standard with erb-lint
Standard documentation demonstrates how it can be used via Rubocop. We can add this to our erb-lint config and use Standard via Rubocop to lint the Ruby code in our views.
At the time of writing, there is a minor open issue with Rubocop that means all cops aren’t disabled by default. But we can override that setting manually, for now.
# .erb-lint.yml
---
EnableDefaultLinters: true
linters:
Rubocop:
enabled: true
rubocop_config:
require: standard
inherit_gem:
standard: config/base.yml
AllCops:
DisabledByDefault: true
One caveat of how erb-lint uses Rubocop is that the tool considers all Ruby code in isolation (i.e as though it were an individual Ruby file). This means we need to disable some of the Standard config in order to obtain sensible results.
To do this, we can inherit from another config file in addition to the Standard
gem. We disable 3 rules that make little or no sense when linting inline Ruby
code in an .erb
file.
Layout/TrailingEmptyLines
: we don’t need trailing new lines when the Ruby code is inline.Layout/InitialIndentation
: the initial indentation might not be the start of the line when we write Ruby code in our views.Lint/UselessAssignment
: erb-lint cannot distinguish between useless and useful assignment, because it doesn’t retain any context. It can’t know whether or not a variable is subsequently used.
--- a/.erb-lint.yml
+++ b/.erb-lint.yml
---
EnableDefaultLinters: true
linters:
Rubocop:
enabled: true
rubocop_config:
require: standard
inherit_gem:
standard: config/base.yml
+ inherit_from: .erb-lint_rubocop.yml
AllCops:
DisabledByDefault: true
# .erb-lint_rubocop.yml
Layout/TrailingEmptyLines:
Enabled: false
Layout/InitialIndentation:
Enabled: false
Lint/UselessAssignment:
Enabled: false
Now we can lint our views including the Ruby code they contain using Standard - helping us to write better styled and more consistent code in our views!