Skip to content

Commit

Permalink
Check that Include and Exclude paths exist (#33)
Browse files Browse the repository at this point in the history
* Check that `Include` and `Exclude` paths exist

- This adds a `PathCleanup` class that removes any paths in the `Include`
  and `Exclude` lists that don't exist (relative to the `.rubocop.yml`,
  ignoring paths with globs).
- This is useful for when you have a `.rubocop.yml` file that has been
  around for a while and has lots of paths that people forget to clean
  up when they delete the files, so doing so manually would be tedious.

* More comprehensive `path_cleanup` test

* Remove `Symbol` from `PERMITTED_CLASSES`

- This was needed in an earlier iteration of the code I wrote, but it
  seems to work without it now on my test repos.

* Rename method for clarity

* The YAML parsing makes string checks redundant

* Use `filter_map` instead of `each_with_index` and an intermediate array

- This is very nice!
  • Loading branch information
issyl0 committed Jan 21, 2024
1 parent e53f655 commit 765d34f
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 3 deletions.
1 change: 1 addition & 0 deletions lib/ruboclean.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require "ruboclean/rubocop_configuration_path"
require "ruboclean/runner"
require "ruboclean/orderer"
require "ruboclean/path_cleanup"

# Ruboclean entry point
module Ruboclean
Expand Down
36 changes: 36 additions & 0 deletions lib/ruboclean/path_cleanup.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

module Ruboclean
# Cleans up any `Include` or `Exclude` paths that don't exist.
# The `Include` and `Exclude` paths are relative to the directory
# where the `.rubocop.yml` file is located. If a path includes a
# wildcard, it's assumed to be valid.
class PathCleanup
def initialize(config_hash)
@config_hash = config_hash
end

def cleanup
%i[Include Exclude].each do |kind|
select_stanzas(kind).each do |cop|
paths = @config_hash.dig(cop, kind)
paths&.select! { |path| regexp_or_wildcard?(path) || File.exist?(path) }
end
end

@config_hash
end

def select_stanzas(kind)
@config_hash.filter_map do |cop, value|
next unless value.is_a?(Hash)

cop if value.key?(kind)
end
end

def regexp_or_wildcard?(path)
path.is_a?(Regexp) || path.include?("*")
end
end
end
9 changes: 9 additions & 0 deletions lib/ruboclean/rubocop_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ def order
Ruboclean::Orderer.new(@config_hash).order
end

def path_cleanup
Ruboclean::PathCleanup.new(@config_hash).cleanup
end

def perform
@config_hash = order
path_cleanup
end

def nil?
@config_hash.nil?
end
Expand Down
4 changes: 2 additions & 2 deletions lib/ruboclean/rubocop_configuration_path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
module Ruboclean
# Interface for reading and writing the `.rubocop.yml` file
class RubocopConfigurationPath
PERMITTED_CLASSED = [Regexp].freeze
PERMITTED_CLASSES = [Regexp].freeze

# Thrown if given path is invalid
class InvalidPathError < StandardError
Expand Down Expand Up @@ -44,7 +44,7 @@ def sanitize_yaml(data)
end

def load_yaml
YAML.safe_load(source_yaml, permitted_classes: PERMITTED_CLASSED)
YAML.safe_load(source_yaml, permitted_classes: PERMITTED_CLASSES)
end

def source_yaml
Expand Down
2 changes: 1 addition & 1 deletion lib/ruboclean/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def run!

return if rubocop_configuration.nil?

rubocop_configuration_path.write(rubocop_configuration.order, preserve_comments: arguments.preserve_comments?)
rubocop_configuration_path.write(rubocop_configuration.perform, preserve_comments: arguments.preserve_comments?)
end

private
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/file_exists.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# frozen_string_literal: true
# test for path cleanup
2 changes: 2 additions & 0 deletions test/fixtures/other_file_exists.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# frozen_string_literal: true
# test for path cleanup
50 changes: 50 additions & 0 deletions test/ruboclean/path_cleanup_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

require "test_helper"
require "ruboclean/path_cleanup"

module Ruboclean
class PathCleanupTest < BaseTest
def test_path_cleanup_includes
input = { SomeCop: { Include: ["some_other_file.rb", "test/fixtures/file_exists.rb", "lib/**/*.rb"] } }
output = { SomeCop: { Include: ["test/fixtures/file_exists.rb", "lib/**/*.rb"] } }

assert_equal output, Ruboclean::PathCleanup.new(input).cleanup
end

def test_path_cleanup_excludes
input = { SomeCop: { Exclude: ["config/**/*.rb", "test/fixtures/other_file_exists.rb",
"some_other_non_existent_file.rb", "test/fixtures/not_here.rb"] } }
output = { SomeCop: { Exclude: ["config/**/*.rb", "test/fixtures/other_file_exists.rb"] } }

assert_equal output, Ruboclean::PathCleanup.new(input).cleanup
end

# rubocop:disable Metrics/MethodLength
def test_path_cleanup_include_and_exclude
input = {
SomeCop: {
Include: ["lib/**/*.rb", "test/fixtures/not_here.rb"],
Exclude: ["config/**/*.rb", "test/fixtures/other_file_exists.rb", "some_other_non_existent_file.rb"],
EnforcedStyle: "something"
},
SomeOtherCop: {
EnforcedStyle: "something"
}
}
output = {
SomeCop: {
Include: ["lib/**/*.rb"],
Exclude: ["config/**/*.rb", "test/fixtures/other_file_exists.rb"],
EnforcedStyle: "something"
},
SomeOtherCop: {
EnforcedStyle: "something"
}
}

assert_equal output, Ruboclean::PathCleanup.new(input).cleanup
end
# rubocop:enable Metrics/MethodLength
end
end
21 changes: 21 additions & 0 deletions test/ruboclean/rubocop_configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ def test_order
end
end

def test_path_cleanup
input = { SomeCop: { Include: ["some_other_file.rb", "test/fixtures/file_exists.rb", "lib/**/*.rb"] } }
output = { SomeCop: { Include: ["test/fixtures/file_exists.rb", "lib/**/*.rb"] } }

Ruboclean::RubocopConfiguration.new(input).path_cleanup.tap do |cleaned_output|
assert_instance_of Hash, cleaned_output
assert_equal output.to_a, cleaned_output.to_a
end
end

def test_perform
input = { "Rails" => { Exclude: ["does_not_exist.rb", "test/fixtures/file_exists.rb"] },
"AllCops" => { Enabled: true } }
output = { "AllCops" => { Enabled: true }, "Rails" => { Exclude: ["test/fixtures/file_exists.rb"] } }

Ruboclean::RubocopConfiguration.new(input).perform.tap do |cleaned_output|
assert_instance_of Hash, cleaned_output
assert_equal output.to_a, cleaned_output.to_a
end
end

def test_nil?
assert_nil Ruboclean::RubocopConfiguration.new(nil)
end
Expand Down

0 comments on commit 765d34f

Please sign in to comment.