gitlab-styles 6.6.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab/changelog_config.yml +13 -0
  3. data/.gitlab/merge_request_templates/Release.md +9 -31
  4. data/.gitlab-ci.yml +3 -1
  5. data/Dangerfile +5 -0
  6. data/gitlab-styles.gemspec +1 -0
  7. data/lib/gitlab/styles/common/banned_constants.rb +28 -0
  8. data/lib/gitlab/styles/rubocop/model_helpers.rb +1 -1
  9. data/lib/gitlab/styles/rubocop.rb +2 -2
  10. data/lib/gitlab/styles/version.rb +1 -1
  11. data/lib/rubocop/cop/active_record_dependent.rb +32 -0
  12. data/lib/rubocop/cop/active_record_serialize.rb +20 -0
  13. data/lib/rubocop/cop/avoid_return_from_blocks.rb +77 -0
  14. data/lib/rubocop/cop/code_reuse/active_record.rb +80 -0
  15. data/lib/rubocop/cop/custom_error_class.rb +69 -0
  16. data/lib/rubocop/cop/fips/md5.rb +27 -0
  17. data/lib/rubocop/cop/fips/open_ssl.rb +31 -0
  18. data/lib/rubocop/cop/fips/sha1.rb +27 -0
  19. data/lib/rubocop/cop/gem_fetcher.rb +37 -0
  20. data/lib/rubocop/cop/in_batches.rb +18 -0
  21. data/lib/rubocop/cop/internal_affairs/deprecate_cop_helper.rb +39 -0
  22. data/lib/rubocop/cop/line_break_after_guard_clauses.rb +100 -0
  23. data/lib/rubocop/cop/line_break_around_conditional_block.rb +128 -0
  24. data/lib/rubocop/cop/migration/update_large_table.rb +60 -0
  25. data/lib/rubocop/cop/performance/rubyzip.rb +35 -0
  26. data/lib/rubocop/cop/polymorphic_associations.rb +25 -0
  27. data/lib/rubocop/cop/rails/include_url_helper.rb +27 -0
  28. data/lib/rubocop/cop/redirect_with_status.rb +46 -0
  29. data/lib/rubocop/cop/rspec/base.rb +14 -0
  30. data/lib/rubocop/cop/rspec/empty_line_after_final_let_it_be.rb +47 -0
  31. data/lib/rubocop/cop/rspec/empty_line_after_let_block.rb +61 -0
  32. data/lib/rubocop/cop/rspec/empty_line_after_shared_example.rb +61 -0
  33. data/lib/rubocop/cop/rspec/example_starting_character.rb +120 -0
  34. data/lib/rubocop/cop/rspec/have_link_parameters.rb +44 -0
  35. data/lib/rubocop/cop/rspec/single_line_hook.rb +41 -0
  36. data/lib/rubocop/cop/rspec/verbose_include_metadata.rb +71 -0
  37. data/lib/rubocop/cop/style/hash_transformation.rb +83 -0
  38. data/lib/rubocop/cop/style/open_struct_use.rb +39 -0
  39. data/lib/rubocop/cop/without_reactive_cache.rb +16 -0
  40. data/rubocop-default.yml +1 -0
  41. data/rubocop-fips.yml +15 -0
  42. data/rubocop-rspec.yml +3 -2
  43. metadata +49 -27
  44. data/lib/gitlab/styles/rubocop/cop/active_record_dependent.rb +0 -32
  45. data/lib/gitlab/styles/rubocop/cop/active_record_serialize.rb +0 -24
  46. data/lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb +0 -130
  47. data/lib/gitlab/styles/rubocop/cop/custom_error_class.rb +0 -73
  48. data/lib/gitlab/styles/rubocop/cop/gem_fetcher.rb +0 -41
  49. data/lib/gitlab/styles/rubocop/cop/in_batches.rb +0 -22
  50. data/lib/gitlab/styles/rubocop/cop/internal_affairs/deprecate_cop_helper.rb +0 -43
  51. data/lib/gitlab/styles/rubocop/cop/line_break_after_guard_clauses.rb +0 -104
  52. data/lib/gitlab/styles/rubocop/cop/line_break_around_conditional_block.rb +0 -132
  53. data/lib/gitlab/styles/rubocop/cop/migration/update_large_table.rb +0 -64
  54. data/lib/gitlab/styles/rubocop/cop/performance/rubyzip.rb +0 -39
  55. data/lib/gitlab/styles/rubocop/cop/polymorphic_associations.rb +0 -29
  56. data/lib/gitlab/styles/rubocop/cop/rails/include_url_helper.rb +0 -31
  57. data/lib/gitlab/styles/rubocop/cop/redirect_with_status.rb +0 -50
  58. data/lib/gitlab/styles/rubocop/cop/rspec/base.rb +0 -18
  59. data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_final_let_it_be.rb +0 -51
  60. data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_let_block.rb +0 -65
  61. data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_shared_example.rb +0 -65
  62. data/lib/gitlab/styles/rubocop/cop/rspec/example_starting_character.rb +0 -124
  63. data/lib/gitlab/styles/rubocop/cop/rspec/have_link_parameters.rb +0 -48
  64. data/lib/gitlab/styles/rubocop/cop/rspec/single_line_hook.rb +0 -45
  65. data/lib/gitlab/styles/rubocop/cop/rspec/verbose_include_metadata.rb +0 -75
  66. data/lib/gitlab/styles/rubocop/cop/style/hash_transformation.rb +0 -87
  67. data/lib/gitlab/styles/rubocop/cop/style/open_struct_use.rb +0 -43
  68. data/lib/gitlab/styles/rubocop/cop/without_reactive_cache.rb +0 -20
@@ -1,130 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- module Styles
5
- module Rubocop
6
- module Cop
7
- module CodeReuse
8
- # Cop that denies the use of ActiveRecord methods outside of models.
9
- class ActiveRecord < RuboCop::Cop::Cop
10
- MSG = 'This method can only be used inside an ActiveRecord model: ' \
11
- 'https://gitlab.com/gitlab-org/gitlab-foss/issues/49653'
12
-
13
- # Various methods from ActiveRecord::Querying that are denied. We
14
- # exclude some generic ones such as `any?` and `first`, as these may
15
- # lead to too many false positives, since `Array` also supports these
16
- # methods.
17
- #
18
- # The keys of this Hash are the denied method names. The values are
19
- # booleans that indicate if the method should only be denied if any
20
- # arguments are provided.
21
- NOT_ALLOWED = {
22
- average: true,
23
- calculate: true,
24
- count_by_sql: true,
25
- create_with: true,
26
- distinct: false,
27
- eager_load: true,
28
- exists?: true,
29
- find_by: true,
30
- find_by!: true,
31
- find_by_sql: true,
32
- find_each: true,
33
- find_in_batches: true,
34
- find_or_create_by: true,
35
- find_or_create_by!: true,
36
- find_or_initialize_by: true,
37
- first!: false,
38
- first_or_create: true,
39
- first_or_create!: true,
40
- first_or_initialize: true,
41
- from: true,
42
- group: true,
43
- having: true,
44
- ids: false,
45
- includes: true,
46
- joins: true,
47
- lock: false,
48
- many?: false,
49
- offset: true,
50
- order: true,
51
- pluck: true,
52
- preload: true,
53
- readonly: false,
54
- references: true,
55
- reorder: true,
56
- rewhere: true,
57
- take: false,
58
- take!: false,
59
- unscope: false,
60
- where: false,
61
- with: true
62
- }.freeze
63
-
64
- def on_send(node)
65
- receiver = node.children[0]
66
- send_name = node.children[1]
67
- first_arg = node.children[2]
68
-
69
- return unless receiver && NOT_ALLOWED.key?(send_name)
70
-
71
- # If the rule requires an argument to be given, but none are
72
- # provided, we won't register an offense. This prevents us from
73
- # adding offenses for `project.group`, while still covering
74
- # `Project.group(:name)`.
75
- return if NOT_ALLOWED[send_name] && !first_arg
76
-
77
- add_offense(node, location: :selector)
78
- end
79
-
80
- # We can not auto correct code like this, as it requires manual
81
- # refactoring. Instead, we'll just allow the surrounding scope.
82
- #
83
- # Despite this method's presence, you should not use it. This method
84
- # exists to make it possible to allow large chunks of offenses we
85
- # can't fix in the short term. If you are writing new code, follow the
86
- # code reuse guidelines, instead of allowing any new offenses.
87
- def autocorrect(node)
88
- scope = surrounding_scope_of(node)
89
- indent = indentation_of(scope)
90
-
91
- lambda do |corrector|
92
- # This prevents us from inserting the same enable/disable comment
93
- # for a method or block that has multiple offenses.
94
- next if allowed_scopes.include?(scope)
95
-
96
- corrector.insert_before(
97
- scope.source_range,
98
- "# rubocop: disable #{cop_name}\n#{indent}"
99
- )
100
-
101
- corrector.insert_after(
102
- scope.source_range,
103
- "\n#{indent}# rubocop: enable #{cop_name}"
104
- )
105
-
106
- allowed_scopes << scope
107
- end
108
- end
109
-
110
- def indentation_of(node)
111
- ' ' * node.loc.expression.source_line[/\A */].length
112
- end
113
-
114
- def surrounding_scope_of(node)
115
- %i[def defs block begin].each do |type|
116
- if (found = node.each_ancestor(type).first)
117
- return found
118
- end
119
- end
120
- end
121
-
122
- def allowed_scopes
123
- @allowed_scopes ||= Set.new
124
- end
125
- end
126
- end
127
- end
128
- end
129
- end
130
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- module Styles
5
- module Rubocop
6
- module Cop
7
- # This cop makes sure that custom error classes, when empty, are declared
8
- # with Class.new.
9
- #
10
- # @example
11
- # # bad
12
- # class FooError < StandardError
13
- # end
14
- #
15
- # # okish
16
- # class FooError < StandardError; end
17
- #
18
- # # good
19
- # FooError = Class.new(StandardError)
20
- class CustomErrorClass < RuboCop::Cop::Cop
21
- MSG = 'Use `Class.new(SuperClass)` to define an empty custom error class.'
22
-
23
- def on_class(node)
24
- parent = node.parent_class
25
- body = node.body
26
-
27
- return if body
28
-
29
- parent_klass = class_name_from_node(parent)
30
-
31
- return unless parent_klass&.to_s&.end_with?('Error')
32
-
33
- add_offense(node)
34
- end
35
-
36
- def autocorrect(node)
37
- klass = node.identifier
38
- parent = node.parent_class
39
-
40
- replacement = "#{class_name_from_node(klass)} = Class.new(#{class_name_from_node(parent)})"
41
-
42
- lambda do |corrector|
43
- corrector.replace(node.source_range, replacement)
44
- end
45
- end
46
-
47
- private
48
-
49
- # The nested constant `Foo::Bar::Baz` looks like:
50
- #
51
- # s(:const,
52
- # s(:const,
53
- # s(:const, nil, :Foo), :Bar), :Baz)
54
- #
55
- # So recurse through that to get the name as written in the source.
56
- #
57
- def class_name_from_node(node, suffix = nil)
58
- return unless node&.type == :const
59
-
60
- name = node.children[1].to_s
61
- name = "#{name}::#{suffix}" if suffix
62
-
63
- if node.children[0]
64
- class_name_from_node(node.children[0], name)
65
- else
66
- name
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- module Styles
5
- module Rubocop
6
- module Cop
7
- # This cop prevents usage of the `git` and `github` arguments to `gem` in a
8
- # `Gemfile` in order to avoid additional points of failure beyond
9
- # rubygems.org.
10
- class GemFetcher < RuboCop::Cop::Cop
11
- MSG = 'Do not use gems from git repositories, only use gems from RubyGems.'
12
-
13
- GIT_KEYS = [:git, :github].freeze
14
-
15
- def on_send(node)
16
- return unless gemfile?(node)
17
-
18
- func_name = node.children[1]
19
- return unless func_name == :gem
20
-
21
- node.children.last.each_node(:pair) do |pair|
22
- key_name = pair.children[0].children[0].to_sym
23
- add_offense(node, location: pair.source_range) if GIT_KEYS.include?(key_name)
24
- end
25
- end
26
-
27
- private
28
-
29
- def gemfile?(node)
30
- node
31
- .location
32
- .expression
33
- .source_buffer
34
- .name
35
- .end_with?("Gemfile")
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../model_helpers'
4
-
5
- module Gitlab
6
- module Styles
7
- module Rubocop
8
- module Cop
9
- # Cop that prevents the use of `in_batches`
10
- class InBatches < RuboCop::Cop::Cop
11
- MSG = 'Do not use `in_batches`, use `each_batch` from the EachBatch module instead'
12
-
13
- def on_send(node)
14
- return unless node.children[1] == :in_batches
15
-
16
- add_offense(node, location: :selector)
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- module Styles
5
- module Rubocop
6
- module Cop
7
- module InternalAffairs
8
- # Cop that denies the use of CopHelper.
9
- class DeprecateCopHelper < RuboCop::Cop::Cop
10
- MSG = 'Do not use `CopHelper` or methods from it, use improved patterns described in https://www.rubydoc.info/gems/rubocop/RuboCop/RSpec/ExpectOffense'
11
-
12
- def_node_matcher :cop_helper, <<~PATTERN
13
- (send nil? ${:include :extend :prepend}
14
- (const _ {:CopHelper}))
15
- PATTERN
16
-
17
- def_node_search :cop_helper_method, <<~PATTERN
18
- (send nil? {:inspect_source :inspect_source_file :parse_source :autocorrect_source_file :autocorrect_source :_investigate} ...)
19
- PATTERN
20
-
21
- def_node_search :cop_helper_method_on_instance, <<~PATTERN
22
- (send (send nil? _) {:messages :highlights :offenses} ...)
23
- PATTERN
24
-
25
- def on_send(node)
26
- cop_helper(node) do
27
- add_offense(node)
28
- end
29
-
30
- cop_helper_method(node) do
31
- add_offense(node)
32
- end
33
-
34
- cop_helper_method_on_instance(node) do
35
- add_offense(node)
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- module Styles
5
- module Rubocop
6
- module Cop
7
- # Ensures a line break after guard clauses.
8
- #
9
- # @example
10
- # # bad
11
- # return unless condition
12
- # do_stuff
13
- #
14
- # # good
15
- # return unless condition
16
- #
17
- # do_stuff
18
- #
19
- # # bad
20
- # raise if condition
21
- # do_stuff
22
- #
23
- # # good
24
- # raise if condition
25
- #
26
- # do_stuff
27
- #
28
- # Multiple guard clauses are allowed without
29
- # line break.
30
- #
31
- # # good
32
- # return unless condition_a
33
- # return unless condition_b
34
- #
35
- # do_stuff
36
- #
37
- # Guard clauses in case statement are allowed without
38
- # line break.
39
- #
40
- # # good
41
- # case model
42
- # when condition_a
43
- # return true unless condition_b
44
- # when
45
- # ...
46
- # end
47
- #
48
- # Guard clauses before end are allowed without
49
- # line break.
50
- #
51
- # # good
52
- # if condition_a
53
- # do_something
54
- # else
55
- # do_something_else
56
- # return unless condition
57
- # end
58
- #
59
- # do_something_more
60
- class LineBreakAfterGuardClauses < RuboCop::Cop::Cop
61
- MSG = 'Add a line break after guard clauses'
62
-
63
- def_node_matcher :guard_clause_node?, <<-PATTERN
64
- [{(send nil? {:raise :fail :throw} ...) return break next} single_line?]
65
- PATTERN
66
-
67
- def on_if(node)
68
- return unless node.single_line?
69
- return unless guard_clause?(node)
70
- return if next_line(node).blank? || clause_last_line?(next_line(node)) || guard_clause?(next_sibling(node))
71
-
72
- add_offense(node)
73
- end
74
-
75
- def autocorrect(node)
76
- lambda do |corrector|
77
- corrector.insert_after(node.loc.expression, "\n")
78
- end
79
- end
80
-
81
- private
82
-
83
- def guard_clause?(node)
84
- return false unless node.if_type?
85
-
86
- guard_clause_node?(node.if_branch)
87
- end
88
-
89
- def next_sibling(node)
90
- node.parent.children[node.sibling_index + 1]
91
- end
92
-
93
- def next_line(node)
94
- processed_source[node.loc.line]
95
- end
96
-
97
- def clause_last_line?(line)
98
- line =~ /^\s*(?:end|elsif|else|when|rescue|ensure)/
99
- end
100
- end
101
- end
102
- end
103
- end
104
- end
@@ -1,132 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- module Styles
5
- module Rubocop
6
- module Cop
7
- # Ensures a line break around conditional blocks.
8
- #
9
- # @example
10
- # # bad
11
- # do_something
12
- # if condition
13
- # do_extra_stuff
14
- # end
15
- # do_something_more
16
- #
17
- # # good
18
- # do_something
19
- #
20
- # if condition
21
- # do_extra_stuff
22
- # end
23
- #
24
- # do_something_more
25
- #
26
- # # bad
27
- # do_something
28
- # unless condition
29
- # do_extra_stuff
30
- # end
31
- #
32
- # do_something_more
33
- #
34
- # # good
35
- # def a_method
36
- # if condition
37
- # do_something
38
- # end
39
- # end
40
- #
41
- # # good
42
- # on_block do
43
- # if condition
44
- # do_something
45
- # end
46
- # end
47
- class LineBreakAroundConditionalBlock < RuboCop::Cop::Cop
48
- include RuboCop::Cop::RangeHelp
49
-
50
- MSG = 'Add a line break around conditional blocks'
51
-
52
- def on_if(node)
53
- # This cop causes errors in haml files, so let's skip those
54
- return if in_haml?(node)
55
- return if node.single_line?
56
- return unless node.if? || node.unless?
57
-
58
- add_offense(node) unless previous_line_valid?(node)
59
- add_offense(node) unless last_line_valid?(node)
60
- end
61
-
62
- def autocorrect(node)
63
- lambda do |corrector|
64
- line = range_by_whole_lines(node.source_range)
65
-
66
- corrector.insert_before(line, "\n") unless previous_line_valid?(node)
67
- corrector.insert_after(line, "\n") unless last_line_valid?(node)
68
- end
69
- end
70
-
71
- private
72
-
73
- def previous_line_valid?(node)
74
- previous_line(node).empty? ||
75
- start_clause_line?(previous_line(node)) ||
76
- block_start?(previous_line(node)) ||
77
- begin_line?(previous_line(node)) ||
78
- assignment_line?(previous_line(node)) ||
79
- rescue_line?(previous_line(node))
80
- end
81
-
82
- def last_line_valid?(node)
83
- last_line(node).empty? ||
84
- end_line?(last_line(node)) ||
85
- end_clause_line?(last_line(node))
86
- end
87
-
88
- def previous_line(node)
89
- processed_source[node.loc.line - 2]
90
- end
91
-
92
- def last_line(node)
93
- processed_source[node.loc.last_line]
94
- end
95
-
96
- def start_clause_line?(line)
97
- line =~ /^\s*(def|=end|#|module|class|if|unless|else|elsif|ensure|when)/
98
- end
99
-
100
- def end_clause_line?(line)
101
- line =~ /^\s*(#|rescue|else|elsif|when)/
102
- end
103
-
104
- def begin_line?(line)
105
- # an assignment followed by a begin or ust a begin
106
- line =~ /^\s*(@?(\w|\|+|=|\[|\]|\s)+begin|begin)/
107
- end
108
-
109
- def assignment_line?(line)
110
- line =~ /^\s*.*=/
111
- end
112
-
113
- def rescue_line?(line)
114
- line =~ /^\s*rescue/
115
- end
116
-
117
- def block_start?(line)
118
- line.match(/ (do|{)( \|.*?\|)?\s?(#.+)?\z/)
119
- end
120
-
121
- def end_line?(line)
122
- line =~ /^\s*(end|})/
123
- end
124
-
125
- def in_haml?(node)
126
- node.location.expression.source_buffer.name.end_with?('.haml.rb')
127
- end
128
- end
129
- end
130
- end
131
- end
132
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative '../../migration_helpers'
3
-
4
- module Gitlab
5
- module Styles
6
- module Rubocop
7
- module Cop
8
- module Migration
9
- # This cop checks for methods that may lead to batch type issues on a table that's been
10
- # explicitly denied because of its size.
11
- #
12
- # Even though though these methods perform functions to avoid
13
- # downtime, using it with tables with millions of rows still causes a
14
- # significant delay in the deploy process and is best avoided.
15
- #
16
- # See https://gitlab.com/gitlab-com/infrastructure/issues/1602 for more
17
- # information.
18
- class UpdateLargeTable < RuboCop::Cop::Cop
19
- include MigrationHelpers
20
-
21
- MSG = 'Using `%s` on the `%s` table will take a long time to ' \
22
- 'complete, and should be avoided unless absolutely ' \
23
- 'necessary'
24
-
25
- def_node_matcher :batch_update?, <<~PATTERN
26
- (send nil? ${#denied_method?}
27
- (sym $...)
28
- ...)
29
- PATTERN
30
-
31
- def on_send(node)
32
- return if denied_tables.empty? || denied_methods.empty?
33
- return unless in_migration?(node)
34
-
35
- matches = batch_update?(node)
36
- return unless matches
37
-
38
- update_method = matches.first
39
- table = matches.last.to_a.first
40
-
41
- return unless denied_tables.include?(table)
42
-
43
- add_offense(node, message: format(MSG, update_method, table))
44
- end
45
-
46
- private
47
-
48
- def denied_tables
49
- cop_config['DeniedTables'] || []
50
- end
51
-
52
- def denied_method?(method_name)
53
- denied_methods.include?(method_name)
54
- end
55
-
56
- def denied_methods
57
- cop_config['DeniedMethods'] || []
58
- end
59
- end
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- module Styles
5
- module Rubocop
6
- module Cop
7
- module Performance
8
- # This cop flags inefficient uses of rubyzip's Zip::File, since when instantiated
9
- # it reads the file's Central Directory into memory entirely. For zips with many
10
- # files and directories, this can be very expensive even when the archive's size
11
- # in bytes is small.
12
- #
13
- # See also:
14
- # - https://github.com/rubyzip/rubyzip/issues/506
15
- # - https://github.com/rubyzip/rubyzip#notes-on-zipinputstream
16
- class Rubyzip < RuboCop::Cop::Cop
17
- MSG = 'Be careful when opening or iterating zip files via Zip::File. ' \
18
- 'Zip archives may contain many entries, and their file index is ' \
19
- 'read into memory upon construction, which can lead to ' \
20
- 'high memory use and poor performance. ' \
21
- 'Consider iterating archive entries via Zip::InputStream instead.'
22
-
23
- def_node_matcher :reads_central_directory?, <<-PATTERN
24
- (send
25
- (const
26
- (const {nil? (cbase)} :Zip) :File) {:new :open :foreach} ...)
27
- PATTERN
28
-
29
- def on_send(node)
30
- return unless reads_central_directory?(node)
31
-
32
- add_offense(node)
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../model_helpers'
4
-
5
- module Gitlab
6
- module Styles
7
- module Rubocop
8
- module Cop
9
- # Cop that prevents the use of polymorphic associations
10
- class PolymorphicAssociations < RuboCop::Cop::Cop
11
- include ModelHelpers
12
-
13
- MSG = 'Do not use polymorphic associations, use separate tables instead'
14
-
15
- def on_send(node)
16
- return unless in_model?(node)
17
- return unless node.children[1] == :belongs_to
18
-
19
- node.children.last.each_node(:pair) do |pair|
20
- key_name = pair.children[0].children[0]
21
-
22
- add_offense(pair) if key_name == :polymorphic
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
29
- end