lib/reek/detector_repository.rb
# frozen_string_literal: true
require_relative 'smell_detectors'
require_relative 'smell_detectors/base_detector'
require_relative 'configuration/app_configuration'
module Reek
#
# Contains all the existing smell detectors and exposes operations on them.
#
class DetectorRepository
# @return [Array<Reek::SmellDetectors::BaseDetector>] All known SmellDetectors
# e.g. [Reek::SmellDetectors::BooleanParameter, Reek::SmellDetectors::ClassVariable].
def self.smell_types
Reek::SmellDetectors::BaseDetector.descendants.sort_by(&:name)
end
# @param filter_by_smells [Array<String>]
# List of smell types to filter by, e.g. "DuplicateMethodCall".
# More precisely it should be whatever is returned by `BaseDetector`.smell_type.
# This means that you can write the "DuplicateMethodCall" from above also like this:
# Reek::SmellDetectors::DuplicateMethodCall.smell_type
# if you want to make sure you do not fat-finger strings.
#
# @return [Array<Reek::SmellDetectors::BaseDetector>] All SmellDetectors that we want to filter for
# e.g. [Reek::SmellDetectors::Attribute].
def self.eligible_smell_types(filter_by_smells = [])
return smell_types if filter_by_smells.empty?
smell_types.select do |klass|
filter_by_smells.include? klass.smell_type
end
end
def initialize(smell_types: self.class.smell_types,
configuration: {})
@configuration = configuration
@smell_types = smell_types
end
def examine(context)
smell_detectors_for(context.type).flat_map do |klass|
detector = klass.new configuration: configuration_for(klass), context: context
detector.run
end
end
# @return [Array<String>] The names of all known SmellDetectors
# e.g. ["BooleanParameter", "ClassVariable"].
def self.available_detector_names
smell_types.map(&:smell_type)
end
private
attr_reader :configuration, :smell_types
def configuration_for(klass)
configuration.fetch klass, {}
end
def smell_detectors_for(type)
smell_types.select { |detector| detector.contexts.include? type }
end
end
end