lxxxvi/ruboclean

View on GitHub
lib/ruboclean/path_cleanup.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# 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
  # regexp, it's assumed to be valid.
  # If all entries in `Include` or `Exclude` are removed, the entire property is removed.
  # If a Cop gets entirely truncated due to removing all `Includes` and/or `Exclude`, the Cop itself will be removed.
  class PathCleanup
    def initialize(configuration_hash, root_directory)
      @configuration_hash = configuration_hash
      @root_directory = root_directory
    end

    def cleanup
      configuration_hash.each_with_object({}) do |(top_level_key, top_level_value), hash|
        result = process_top_level_value(top_level_value)

        next if Array(result).empty? # No configuration keys left in the cop, remove the entire cop

        hash[top_level_key] = result
      end
    end

    private

    attr_reader :configuration_hash, :root_directory

    # top_level_value could be something like this:
    #
    # {
    #   Include: [...],
    #   Exclude: [...],
    #   EnforcedStyle: "..."
    # }
    #
    # We process it further in case of a Hash.
    def process_top_level_value(top_level_value)
      return top_level_value unless top_level_value.is_a?(Hash)

      top_level_value.each_with_object({}) do |(cop_property_key, cop_property_value), hash|
        result = process_cop_property(cop_property_key, cop_property_value)

        next if Array(result).empty? # No entries left, will skip adding the key to the hash

        hash[cop_property_key] = result
      end
    end

    def process_cop_property(cop_property_key, cop_property_value)
      return cop_property_value unless %w[Include Exclude].include?(cop_property_key.to_s)
      return cop_property_value unless cop_property_value.respond_to?(:filter_map)

      cop_property_value.find_all do |item|
        path_exists?(item)
      end
    end

    def path_exists?(item)
      regexp_pattern?(item) ||
        specific_path_exists?(item) ||
        any_global_command_pattern?(item)
    end

    def specific_path_exists?(item)
      root_directory.join(item).exist?
    end

    def any_global_command_pattern?(item)
      root_directory.glob(item).any?
    end

    # We don't support Regexp, so we just say it exists.
    def regexp_pattern?(item)
      item.is_a?(Regexp)
    end
  end
end