Welcome to mirror list, hosted at ThFree Co, Russian Federation.

module_with_instance_variables.rb « cop « rubocop - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f101ae09ad23c824d147209ac486d0fbf5161fbe (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
75
76
77
78
79
80
81
82
module RuboCop
  module Cop
    class ModuleWithInstanceVariables < RuboCop::Cop::Cop
      MSG = <<~EOL.freeze
        Do not use instance variables in a module. Please read this
        for the rationale behind it:

        https://docs.gitlab.com/ee/development/module_with_instance_variables.html
      EOL

      def on_module(node)
        return if
          rails_helper?(node) || rails_mailer?(node) || spec_helper?(node)

        check_method_definition(node)

        # Not sure why some module would have an extra begin wrapping around
        node.each_child_node(:begin) do |begin_node|
          check_method_definition(begin_node)
        end
      end

      private

      # We ignore Rails helpers right now because it's hard to workaround it
      def rails_helper?(node)
        node.source_range.source_buffer.name =~
          %r{app/helpers/\w+_helper.rb\z}
      end

      # We ignore Rails mailers right now because it's hard to workaround it
      def rails_mailer?(node)
        node.source_range.source_buffer.name =~
          %r{app/mailers/emails/}
      end

      # We ignore spec helpers because it usually doesn't matter
      def spec_helper?(node)
        node.source_range.source_buffer.name =~
          %r{spec/support/|features/steps/}
      end

      def check_method_definition(node)
        node.each_child_node(:def) do |definition|
          # We allow this pattern:
          #
          #     def f
          #       @f ||= true
          #     end
          if only_ivar_or_assignment?(definition)
            # We don't allow if any other ivar is used
            definition.each_descendant(:ivar) do |offense|
              add_offense(offense, :expression)
            end
          # We allow initialize method and single ivar
          elsif !initialize_method?(definition) && !single_ivar?(definition)
            definition.each_descendant(:ivar, :ivasgn) do |offense|
              add_offense(offense, :expression)
            end
          end
        end
      end

      def only_ivar_or_assignment?(definition)
        node = definition.child_nodes.last

        definition.child_nodes.size == 2 &&
          node.or_asgn_type? && node.child_nodes.first.ivasgn_type?
      end

      def single_ivar?(definition)
        node = definition.child_nodes.last

        definition.child_nodes.size == 2 && node.ivar_type?
      end

      def initialize_method?(definition)
        definition.children.first == :initialize
      end
    end
  end
end