Skip to content

Instantly share code, notes, and snippets.

@backus
Last active October 8, 2016 23:24
Show Gist options
  • Save backus/00f0a34857208bf356af to your computer and use it in GitHub Desktop.
Save backus/00f0a34857208bf356af to your computer and use it in GitHub Desktop.
Rubocop's --auto-gen-config changes your settings for certain cops. For example, if you have one line of code which has a LineLength of 150 characters then it is going to set your Metrics/LineLength config to Max: 150. This script instead generates a list of files to exclude only and does not lower your standards
#!/usr/bin/env ruby
gem 'slop', '4.2.1'
require 'slop'
require 'pathname'
require 'json'
require 'yaml'
module SlopExt
class PathOption < Slop::Option
def call(value)
Pathname(value).expand_path.freeze.tap do |path|
fail "Invalid path #{path}" unless path.exist? && path.file?
end
end
end
end
Slop.include(SlopExt)
module CLI
def self.parse(args)
options = Slop.parse(args) do |switch|
# Print and display help
switch.on('-h', '--help') { puts switch }
# Accept configuration file
switch.path '-c', '--config', 'Specify configuration file.'
end
fail "You must specify a config file" unless options.get(:config)
options.to_hash
end
end
SETTINGS = CLI.parse(ARGV)
# Note: comment out any existing excludes in your current config file
CONFIG_LOCATION = SETTINGS.fetch(:config)
json = `bundle exec rubocop -c #{CONFIG_LOCATION} -f json`
OUTPUT = JSON.parse(json, symbolize_names: true)
FILES = OUTPUT.fetch(:files)
OFFENSES = FILES.map do |file|
file.fetch(:offenses).map do |offense|
offense.merge(path: file.fetch(:path))
end
end.flatten
GROUPS = OFFENSES.group_by { |item| item.fetch(:cop_name) }
CONF = GROUPS.each.with_object({}) do |(key, offense), config|
config[key] ||= {}
config[key]['Exclude'] ||= []
offense.each { |o| config[key]['Exclude'] << o.fetch(:path) }
end
RUBOCOP_IGNORES = CONF.map do |key, settings|
[key, { 'Exclude' => settings.fetch('Exclude').sort.uniq }]
end.to_h
modified_yaml = CONFIG_LOCATION.readlines.each.with_index.map do |line, index|
line.gsub(/^#(.+)$/, ":yaml_comment#{index}:\\1")
end.join
CURRENT_CONFIG = YAML.load(modified_yaml)
CONFIGURATION_KEYS = (CURRENT_CONFIG.keys + RUBOCOP_IGNORES.keys).uniq
MERGED = CONFIGURATION_KEYS.each.with_object({}) do |key, memo|
if key.to_s.start_with?('yaml_comment')
next memo[key] = CURRENT_CONFIG.fetch(key)
end
existing = CURRENT_CONFIG.fetch(key, {})
additions = RUBOCOP_IGNORES.fetch(key, {})
excludes = (existing.fetch('Exclude', []) + additions.fetch('Exclude', [])).uniq
merged = existing.merge(additions)
merged = merged.merge('Exclude' => excludes) if excludes.any?
memo[key] = merged
end.to_h
updated_yaml = YAML.dump(MERGED)
final_yaml = updated_yaml.gsub(/^:yaml_comment\d+:(.+)$/, '#\1')
CONFIG_LOCATION.write(final_yaml)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment