Rubocop with Standard

RuboCop/Standard configuration with the frustration removed
Icons/chart bar
Used 37 times
Created by
B Ben Morrall

Usage
Modified from the original RuboCoping with legacy post by Evil Martians.

With a few fun changes found along the way.

Run this command in your Rails app directory in the terminal:

rails app:template LOCATION="https://railsbytes.com/script/VdrsMK"
Template Source

Review the code before running this template on your machine.

say "Hey! Let's configure RuboCop for your project 🤖!\n" \
    "For more information, visit https://evilmartians.com/chronicles/rubocoping-with-legacy-bring-your-ruby-code-up-to-standard"

plugins = []
gems = []

specs = []
deps = []
ruby_version = Gem::Version.new(RUBY_VERSION).segments[0..1].join(".")

in_root do
  if File.file?("Gemfile.lock")
    bundler_parser = Bundler::LockfileParser.new(Bundler.read_file("Gemfile.lock"))
    specs = bundler_parser.specs.map(&:name)
    locked_version = bundler_parser.ruby_version.match(/(\d+\.\d+\.\d+)/)&.[](1) if bundler_parser.ruby_version
    ruby_version = Gem::Version.new(locked_version).segments[0..1].join(".") if locked_version
  end
end

in_root do
  if File.file?("Gemfile")
    bundler_parser = Bundler::Dsl.new
    bundler_parser.eval_gemfile("Gemfile")
    deps = bundler_parser.dependencies.map(&:name)
  end
end

has_rails = ((specs | deps) & %w[activerecord actionpack rails]).any?

if has_rails && yes?("Would your like to install rubocop-rails?")
  file ".rubocop/rails.yml", ERB.new(
    *[
  <<~'TCODE'
require:
  - rubocop-rails
  - standard-rails

inherit_gem:
  standard-rails: config/base.yml

  TCODE
  ], trim_mode: "<>").result(binding)
  plugins << ".rubocop/rails.yml"
  gems << "rubocop-rails"
  gems << "standard-rails"
end

has_rspec = in_root do
  ((specs | deps) & %w[rspec-core]).any? && File.directory?("spec")
end

if has_rspec && yes?("Would your like to install rubocop-rspec?")
  file ".rubocop/rspec.yml", ERB.new(
    *[
  <<~'TCODE'
require:
  - rubocop-rspec
  - rubocop-capybara

# Disable all cops by default,
# only enable those defined explcitly in this configuration file
RSpec:
  Enabled: false

RSpec/Focus:
  Enabled: true

RSpec/EmptyExampleGroup:
  Enabled: true

RSpec/EmptyLineAfterExampleGroup:
  Enabled: true

RSpec/EmptyLineAfterFinalLet:
  Enabled: true

RSpec/EmptyLineAfterHook:
  Enabled: true

RSpec/EmptyLineAfterSubject:
  Enabled: true

RSpec/HookArgument:
  Enabled: true

RSpec/HooksBeforeExamples:
  Enabled: true

RSpec/ImplicitExpect:
  Enabled: true

RSpec/IteratedExpectation:
  Enabled: true

RSpec/LetBeforeExamples:
  Enabled: true

RSpec/MissingExampleGroupArgument:
  Enabled: true

RSpec/ReceiveCounts:
  Enabled: true

# Capybara

Capybara/CurrentPathExpectation:
  Enabled: true
  TCODE
  ], trim_mode: "<>").result(binding)
  plugins << ".rubocop/rspec.yml"
  gems << "rubocop-rspec"
end

has_factory_bot = in_root do
  ((specs | deps) & %w[factory_bot_rails factory_bot]).any?
end

if has_factory_bot && yes?("Would your like to install rubocop-factory_bot?")
  file ".rubocop/factory_bot.yml", ERB.new(
    *[
  <<~'TCODE'
require:
  - rubocop-factory_bot
  
FactoryBot/AttributeDefinedStatically:
  Enabled: true

FactoryBot/CreateList:
  Enabled: true
  TCODE
  ], trim_mode: "<>").result(binding)
  plugins << ".rubocop/factory_bot.yml"
  gems << "rubocop-factory_bot"
end

has_minitest = in_root do
  ((specs | deps) & %w[rspec-core]).any? && File.directory?("test")
end

if has_minitest && yes?("Would your like to install rubocop-minitest?")
  file ".rubocop/minitest.yml", ERB.new(
    *[
  <<~'TCODE'
require:
  - rubocop-minitest
  TCODE
  ], trim_mode: "<>").result(binding)
  plugins << ".rubocop/minitest.yml"
  gems << "rubocop-minitest"
end
has_graphql = ((specs | deps) & %w[graphql]).any?

if has_graphql && yes?("Would your like to install rubocop-graphql?")
  file ".rubocop/graphql.yml", ERB.new(
    *[
  <<~'TCODE'
require:
  - rubocop-graphql
  TCODE
  ], trim_mode: "<>").result(binding)
  plugins << ".rubocop/graphql.yml"
  gems << "rubocop-graphql"
end

in_root do
    # Final configuration generation

  file ".rubocop/strict.yml", ERB.new(
      *[
    <<~'TCODE'
  Lint/Debugger: # don't leave binding.pry
    Enabled: true
    Exclude: []

  <% if gems.include?("rubocop-rspec") %>
  RSpec/Focus: # run ALL tests on CI
    Enabled: true
    Exclude: []
  
  <% end %>
  <% if gems.include?("rubocop-rails") %>
  Rails/Output: # Don't leave puts-debugging
    Enabled: true
    Exclude: []
    AutoCorrect: false

  Rails/FindEach: # each could badly affect the performance, use find_each
    Enabled: true
    Exclude: []

  Rails/UniqBeforePluck: # uniq.pluck and not pluck.uniq
    Enabled: true
    Exclude: []
  
  <% end %>
    TCODE
    ], trim_mode: "<>").result(binding)
  file ".rubocop.yml", ERB.new(
      *[
    <<~'TCODE'
  inherit_mode:
    merge:
      - Exclude

  require:
    - standard
    - standard-custom
    - standard-performance
    - rubocop-performance

  inherit_gem:
    standard: config/base.yml
    standard-performance: config/base.yml
    standard-custom: config/base.yml

  inherit_from:
  <% plugins.each do |plugin| %>
    - <%= plugin %>
  <% end %>
    - .rubocop/strict.yml

  AllCops:
    NewCops: disable
    SuggestExtensions: true
    TargetRubyVersion: <%= ruby_version %>
    TCODE
    ], trim_mode: "<>").result(binding)
  file "gemfiles/rubocop.gemfile", ERB.new(
      *[
    <<~'TCODE'
  source "https://rubygems.org" do
    <% gems.each do |gem| %>
    gem "<%= gem %>"
    <% end %>
    gem "standard", "~> 1.28"
  end
    TCODE
    ], trim_mode: "<>").result(binding)

  in_root do
    if File.file?("Gemfile")
      file "Gemfile", File.read("Gemfile") + %(\ngroup :development do\n  eval_gemfile "gemfiles/rubocop.gemfile"\nend\n), force: true
    end
  end

    has_bin_rubocop = yes?("Would your like to create a standalone RuboCop executable (bin/rubocop)?")

  if has_bin_rubocop
    file "bin/rubocop", ERB.new(
      *[
    <<~'TCODE'
  #!/bin/bash

  cd $(dirname $0)/..

  export BUNDLE_GEMFILE=./gemfiles/rubocop.gemfile
  bundle check > /dev/null || bundle install

  bundle exec rubocop $@
    TCODE
    ], trim_mode: "<>").result(binding)
    in_root { run "chmod +x bin/rubocop" }
  end

end

if yes?("Would you like to generate a TODO config?")
  # First, run RuboCop and check the output
  # with formatter json
  in_root do
    has_bin_rubocop = File.file?("bin/rubocop")
    command = has_bin_rubocop ? "bin/rubocop" : "bundle exec rubocop"

    output = Bundler.with_unbundled_env do
      # Make sure dependencies are installed
      if has_bin_rubocop
        `#{command} > /dev/null`
      else
        run "bundle check > /dev/null || bundle install > /dev/null"
      end
      `#{command} --format json`
    end
    require "json"
    summary = JSON.parse(output).dig("summary")

    if summary["offense_count"] > 0
      Bundler.with_unbundled_env do
        # Prevent RuboCop from updating the `.rubocop.yml`
        run "cp .rubocop.yml .rubocop.yml.bak"
        run "#{command} " \
            "--auto-gen-config " \
            "--auto-gen-only-exclude " \
            "--no-exclude-limit " \
            "--no-auto-gen-timestamp"
        run "mv .rubocop.yml.bak .rubocop.yml"
      end

      inject_into_file ".rubocop.yml", "  - .rubocop_todo.yml\n", before: "  - .rubocop/strict.yml"
    else
      say "No offenses detected, good job! Skipping TODO generation"
    end
  end
end

say_status :info, "Congratulations! Your project got style! 🎉"

if yes?("Would you like to run RuboCop to check your configuration? (y/n)")
  in_root do
    if File.file?("bin/rubocop")
      Bundler.with_unbundled_env { run "bin/rubocop" }
    else
      Bundler.with_unbundled_env do
        run "bundle check > /dev/null || bundle install > /dev/null"
        run "bundle exec rubocop"
      end
    end
  end
end
Comments

Sign up or Login to leave a comment.