summaryrefslogtreecommitdiff
path: root/rubocop/cop/rspec/verbose_include_metadata.rb
blob: 58390622d609ecf11e0f9a729e3a9515612ec6b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# frozen_string_literal: true

require 'rubocop-rspec'

module RuboCop
  module Cop
    module RSpec
      # Checks for verbose include metadata used in the specs.
      #
      # @example
      #   # bad
      #   describe MyClass, js: true do
      #   end
      #
      #   # good
      #   describe MyClass, :js do
      #   end
      class VerboseIncludeMetadata < Cop
        MSG = 'Use `%s` instead of `%s`.'

        SELECTORS = %i[describe context feature example_group it specify example scenario its].freeze

        def_node_matcher :include_metadata, <<-PATTERN
          (send {(const nil :RSpec) nil} {#{SELECTORS.map(&:inspect).join(' ')}}
            !const
            ...
            (hash $...))
        PATTERN

        def_node_matcher :invalid_metadata?, <<-PATTERN
          (pair
            (sym $...)
            (true))
        PATTERN

        def on_send(node)
          invalid_metadata_matches(node) do |match|
            add_offense(node, :expression, format(MSG, good(match), bad(match)))
          end
        end

        def autocorrect(node)
          lambda do |corrector|
            invalid_metadata_matches(node) do |match|
              corrector.replace(match.loc.expression, good(match))
            end
          end
        end

        private

        def invalid_metadata_matches(node)
          include_metadata(node) do |matches|
            matches.select(&method(:invalid_metadata?)).each do |match|
              yield match
            end
          end
        end

        def bad(match)
          "#{metadata_key(match)}: true"
        end

        def good(match)
          ":#{metadata_key(match)}"
        end

        def metadata_key(match)
          match.children[0].source
        end
      end
    end
  end
end