Class: Reek::SmellDetectors::BaseDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/reek/smell_detectors/base_detector.rb

Overview

Shared responsibilities of all smell detectors.

See

- {file:docs/Basic-Smell-Options.md}
- {file:docs/Code-Smells.md}
- {file:README.md}

for details.

Constant Summary collapse

EXCLUDE_KEY =

The name of the config field that lists the names of code contexts that should not be checked. Add this field to the config for each smell that should ignore this code element.

'exclude'
DEFAULT_EXCLUDE_SET =

The default value for the EXCLUDE_KEY if it isn’t specified in any configuration file.

[].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configuration: {}, context: nil) ⇒ BaseDetector

Returns a new instance of BaseDetector.



32
33
34
35
# File 'lib/reek/smell_detectors/base_detector.rb', line 32

def initialize(configuration: {}, context: nil)
  @config = SmellConfiguration.new self.class.default_config.merge(configuration)
  @context = context
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



21
22
23
# File 'lib/reek/smell_detectors/base_detector.rb', line 21

def config
  @config
end

#contextObject (readonly, private)

Returns the value of attribute context.



56
57
58
# File 'lib/reek/smell_detectors/base_detector.rb', line 56

def context
  @context
end

Class Method Details

.configuration_keysSet<Symbol>

Returns all configuration keys that are available for this detector.

Returns:

  • (Set<Symbol>)

    all configuration keys that are available for this detector



139
140
141
# File 'lib/reek/smell_detectors/base_detector.rb', line 139

def configuration_keys
  Set.new(default_config.keys.map(&:to_sym))
end

.contextsObject



96
97
98
# File 'lib/reek/smell_detectors/base_detector.rb', line 96

def contexts
  [:def, :defs]
end

.default_configObject



101
102
103
104
105
106
# File 'lib/reek/smell_detectors/base_detector.rb', line 101

def default_config
  {
    SmellConfiguration::ENABLED_KEY => true,
    EXCLUDE_KEY                     => DEFAULT_EXCLUDE_SET.dup
  }
end

.descendantsArray<Constant>

Returns all descendants of BaseDetector

Returns:

  • (Array<Constant>)

    , e.g.: [Reek::SmellDetectors::Attribute,

    Reek::SmellDetectors::BooleanParameter,
    Reek::SmellDetectors::ClassVariable,
    ...]
    


121
122
123
# File 'lib/reek/smell_detectors/base_detector.rb', line 121

def descendants
  @descendants ||= []
end

.inherited(subclass) ⇒ Object



108
109
110
# File 'lib/reek/smell_detectors/base_detector.rb', line 108

def inherited(subclass)
  descendants << subclass
end

.smell_typeObject



92
93
94
# File 'lib/reek/smell_detectors/base_detector.rb', line 92

def smell_type
  @smell_type ||= name.split('::').last
end

.to_detector(detector_name) ⇒ SmellDetector

Transform a detector name to the corresponding constant. Note that we assume a valid name - exceptions are not handled here.

Parameters:

  • detector_name (String)

    the detector in question, e.g. ‘DuplicateMethodCall’

Returns:

  • (SmellDetector)

    this will return the class, not an instance



132
133
134
# File 'lib/reek/smell_detectors/base_detector.rb', line 132

def to_detector(detector_name)
  SmellDetectors.const_get detector_name
end

.todo_configuration_for(smells) ⇒ Object



48
49
50
51
52
# File 'lib/reek/smell_detectors/base_detector.rb', line 48

def self.todo_configuration_for(smells)
  default_exclusions = default_config.fetch 'exclude'
  exclusions = default_exclusions + smells.map(&:context)
  { smell_type => { 'exclude' => exclusions.uniq } }
end

Instance Method Details

#config_for(ctx) ⇒ Object (private)



78
79
80
# File 'lib/reek/smell_detectors/base_detector.rb', line 78

def config_for(ctx)
  ctx.config_for(self.class)
end

#enabled?Boolean (private)

Returns:

  • (Boolean)


70
71
72
# File 'lib/reek/smell_detectors/base_detector.rb', line 70

def enabled?
  config.enabled? && config_for(context)[SmellConfiguration::ENABLED_KEY] != false
end

#exception?Boolean (private)

Returns:

  • (Boolean)


66
67
68
# File 'lib/reek/smell_detectors/base_detector.rb', line 66

def exception?
  context.matches?(value(EXCLUDE_KEY, context))
end

#expressionObject (private)



58
59
60
# File 'lib/reek/smell_detectors/base_detector.rb', line 58

def expression
  @expression ||= context.exp
end

#runObject



41
42
43
44
45
46
# File 'lib/reek/smell_detectors/base_detector.rb', line 41

def run
  return [] unless enabled?
  return [] if exception?

  sniff
end

#smell_typeObject



37
38
39
# File 'lib/reek/smell_detectors/base_detector.rb', line 37

def smell_type
  self.class.smell_type
end

#smell_warning(**options) ⇒ Object (private)



82
83
84
85
86
87
88
89
# File 'lib/reek/smell_detectors/base_detector.rb', line 82

def smell_warning(**options)
  SmellWarning.new(smell_type,
                   source: expression.source,
                   context: context.full_name,
                   lines: options.fetch(:lines),
                   message: options.fetch(:message),
                   parameters: options.fetch(:parameters, {}))
end

#source_lineObject (private)



62
63
64
# File 'lib/reek/smell_detectors/base_detector.rb', line 62

def source_line
  @source_line ||= expression.line
end

#value(key, ctx) ⇒ Object (private)



74
75
76
# File 'lib/reek/smell_detectors/base_detector.rb', line 74

def value(key, ctx)
  config_for(ctx)[key] || config.value(key, ctx)
end