Skip to content

Latest commit

 

History

History
144 lines (116 loc) · 4.73 KB

How-To-Write-New-Detectors.md

File metadata and controls

144 lines (116 loc) · 4.73 KB

How to write new detectors

Outline what you have in mind

Before starting to code you should discuss the overall idea for your new smell detector with us in a corresponding github issue. We all should have a solid understanding of what this detector actually reports, the edge cases it covers and the overall rationale behind it.

Structure

All smell detectors reside in lib/reek/smell_detectors and have the following base structure:

require_relative 'base_detector'
require_relative 'smell_warning'

module Reek
  module SmellDetectors
    #
    # Here goes your introduction for this detector.
    #
    # See {file:docs/Your-Detector.md} for details.
    class YourDetector < BaseDetector
      def self.contexts
        [:class] # In case you're operating on class contexts only - just an example.
      end

      #
      # Here you should document what you expect the detector's context to look
      # like.
      #
      # @return [Array<SmellWarning>]
      #
      def sniff
        # "found_smells" below is just an abstraction for
        # "find the smells in question" and iterate over them.
        # This can just be a method but it can also be a more sophisticated set up.
        # Check out other smell detectors to get a feeling for what to do here.
        found_smells.map do |smell|
          # "smell_warning" is defined in BaseDetector and should be used by you
          # to construct smell warnings
          smell_warning(
            lines: [], # lines on which the smell was detected
            message: "...", # the message that is printed on STDOUT
            # whatever you interpolate into the "message" should go into
            # parameters below - if you do not interpolate anything you
            # can omit this
            parameters: { })
          end
        end
      end

      private

      # Here goes everything you need for finding smells.
    end
  end
end

For your detector to be properly loaded you need to require it in lib/reek/smell_detectors.rb as well.

defaults.reek.yml

After you ran

bundle exec rake

for the first time with your shiny new detector in place the docs/defaults.reek.yml file should have been updated automatically. Make sure you don't forget to check in those changes as well.

Documentation

  • Above every SmellDetector::sniff method it should be documented what the expected AST is
  • Every detector should have a separate documentation page in /docs. You can take any arbitrary existing smell detector documentation page as template (since they all have the same structure already)
  • The detector should be listed under Code Smells
  • Depending on what your detector does it might make sense to add it to other doc pages as well e.g. Simulated Polymorphism

Rspec examples

All smell detector specs start out with 2 generic examples like below - the second one only if it makes sense. Here's what it looks like for UncommunicativeVariableName:

it 'reports the right values' do
  src = <<-RUBY
    def alfa
      bravo = 5
    end
  RUBY

  expect(src).to reek_of(:UncommunicativeVariableName,
                         lines:   [2],
                         context: 'alfa',
                         message: "has the variable name 'bravo'",
                         source:  'string',
                         name:    'bravo')
end

it 'does count all occurrences' do
  src = <<-RUBY
    def alfa
      bravo = 3
      charlie = 7
    end
  RUBY

  expect(src).to reek_of(:UncommunicativeVariableName,
                         lines: [2],
                         name:  'bravo')
  expect(src).to reek_of(:UncommunicativeVariableName,
                         lines: [3],
                         name:  'charlie')
end

The following examples should then cover the detector specific features.

Schema validation

We make use of dry-schema to validate the the reek configuration file (usually named .reek.yml in the root of a project). The validation will warn reek users of missing or incorrectly defined configuration.

If you add or modify a detector you will need to make sure that you update the schema file. For help with the schema syntax you can refer to the dry-schema documentation. You can also take a look at the existing schema rules for they all look fairly similar.

Cucumber features

We are trying to write as few Cucumber features as possible. Normally, there should be no need to write a new feature for a new smell detector. If you feel like this is necessary in this case, please discuss this with us via github issue or in your work-in-progress pull request before doing anything.