rubocop 1.39.0 → 1.41.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +65 -9
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/comment_config.rb +5 -0
  6. data/lib/rubocop/config.rb +33 -9
  7. data/lib/rubocop/config_loader.rb +14 -5
  8. data/lib/rubocop/config_loader_resolver.rb +1 -1
  9. data/lib/rubocop/config_validator.rb +1 -1
  10. data/lib/rubocop/cop/badge.rb +9 -4
  11. data/lib/rubocop/cop/base.rb +26 -17
  12. data/lib/rubocop/cop/commissioner.rb +8 -3
  13. data/lib/rubocop/cop/cop.rb +1 -1
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  15. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  16. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  17. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  18. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  19. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  20. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  21. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  22. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  23. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  24. data/lib/rubocop/cop/layout/indentation_style.rb +3 -1
  25. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  26. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  27. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  28. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  29. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  30. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  31. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  32. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  33. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  34. data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -2
  35. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  36. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  37. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  38. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  39. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  40. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  41. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  42. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  43. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  44. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  45. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  46. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  47. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +13 -3
  48. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  49. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -12
  50. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  51. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  52. data/lib/rubocop/cop/lint/void.rb +6 -6
  53. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  54. data/lib/rubocop/cop/metrics/class_length.rb +10 -5
  55. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  56. data/lib/rubocop/cop/metrics/module_length.rb +10 -5
  57. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
  58. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  59. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  60. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  61. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  62. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  63. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +28 -5
  64. data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
  65. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  66. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  67. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  68. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  69. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  70. data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
  71. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  72. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  73. data/lib/rubocop/cop/registry.rb +29 -14
  74. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  75. data/lib/rubocop/cop/style/concat_array_literals.rb +66 -0
  76. data/lib/rubocop/cop/style/documentation.rb +1 -1
  77. data/lib/rubocop/cop/style/guard_clause.rb +36 -5
  78. data/lib/rubocop/cop/style/if_with_semicolon.rb +4 -4
  79. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  80. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  81. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  82. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  83. data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
  84. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
  85. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  86. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  87. data/lib/rubocop/cop/style/require_order.rb +140 -0
  88. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  89. data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
  90. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  91. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  92. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  93. data/lib/rubocop/cop/team.rb +1 -1
  94. data/lib/rubocop/cop/util.rb +32 -5
  95. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  96. data/lib/rubocop/cop/variable_force.rb +20 -29
  97. data/lib/rubocop/cops_documentation_generator.rb +22 -3
  98. data/lib/rubocop/directive_comment.rb +1 -1
  99. data/lib/rubocop/file_patterns.rb +43 -0
  100. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  101. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  102. data/lib/rubocop/formatter.rb +3 -1
  103. data/lib/rubocop/options.rb +8 -0
  104. data/lib/rubocop/path_util.rb +34 -16
  105. data/lib/rubocop/result_cache.rb +1 -1
  106. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  107. data/lib/rubocop/rspec/support.rb +2 -2
  108. data/lib/rubocop/server/core.rb +1 -1
  109. data/lib/rubocop/target_finder.rb +1 -1
  110. data/lib/rubocop/target_ruby.rb +1 -1
  111. data/lib/rubocop/version.rb +1 -1
  112. data/lib/rubocop.rb +16 -6
  113. metadata +10 -3
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Sort `require` and `require_relative` in alphabetical order.
7
+ #
8
+ # @safety
9
+ # This cop's autocorrection is unsafe because it will obviously change the execution order.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # require 'b'
14
+ # require 'a'
15
+ #
16
+ # # good
17
+ # require 'a'
18
+ # require 'b'
19
+ #
20
+ # # bad
21
+ # require_relative 'b'
22
+ # require_relative 'a'
23
+ #
24
+ # # good
25
+ # require_relative 'a'
26
+ # require_relative 'b'
27
+ #
28
+ # # good (sorted within each section separated by a blank line)
29
+ # require 'a'
30
+ # require 'd'
31
+ #
32
+ # require 'b'
33
+ # require 'c'
34
+ #
35
+ # # good
36
+ # require 'b'
37
+ # require_relative 'c'
38
+ # require 'a'
39
+ #
40
+ # # bad
41
+ # require 'a'
42
+ # require 'c' if foo
43
+ # require 'b'
44
+ #
45
+ # # good
46
+ # require 'a'
47
+ # require 'b'
48
+ # require 'c' if foo
49
+ #
50
+ # # bad
51
+ # require 'c'
52
+ # if foo
53
+ # require 'd'
54
+ # require 'b'
55
+ # end
56
+ # require 'a'
57
+ #
58
+ # # good
59
+ # require 'c'
60
+ # if foo
61
+ # require 'b'
62
+ # require 'd'
63
+ # end
64
+ # require 'a'
65
+ #
66
+ class RequireOrder < Base
67
+ extend AutoCorrector
68
+
69
+ include RangeHelp
70
+
71
+ RESTRICT_ON_SEND = %i[require require_relative].freeze
72
+
73
+ MSG = 'Sort `%<name>s` in alphabetical order.'
74
+
75
+ # @!method if_inside_only_require(node)
76
+ def_node_matcher :if_inside_only_require, <<~PATTERN
77
+ {
78
+ (if _ _ $(send nil? {:require :require_relative} _))
79
+ (if _ $(send nil? {:require :require_relative} _) _)
80
+ }
81
+ PATTERN
82
+
83
+ def on_send(node)
84
+ return unless node.arguments?
85
+ return if not_modifier_form?(node.parent)
86
+
87
+ previous_older_sibling = find_previous_older_sibling(node)
88
+ return unless previous_older_sibling
89
+
90
+ add_offense(node, message: format(MSG, name: node.method_name)) do |corrector|
91
+ swap(
92
+ range_with_comments_and_lines(previous_older_sibling),
93
+ range_with_comments_and_lines(node.parent.if_type? ? node.parent : node),
94
+ corrector: corrector
95
+ )
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ def not_modifier_form?(node)
102
+ node.if_type? && !node.modifier_form?
103
+ end
104
+
105
+ def find_previous_older_sibling(node) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
106
+ search_node(node).left_siblings.reverse.find do |sibling|
107
+ sibling = sibling_node(sibling)
108
+ break unless sibling&.send_type? && sibling&.method?(node.method_name)
109
+ break unless sibling.arguments? && !sibling.receiver
110
+ break unless in_same_section?(sibling, node)
111
+
112
+ node.first_argument.source < sibling.first_argument.source
113
+ end
114
+ end
115
+
116
+ def search_node(node)
117
+ node.parent.if_type? ? node.parent : node
118
+ end
119
+
120
+ def sibling_node(node)
121
+ return if not_modifier_form?(node)
122
+
123
+ node.if_type? ? if_inside_only_require(node) : node
124
+ end
125
+
126
+ def in_same_section?(node1, node2)
127
+ !node1.location.expression.with(
128
+ end_pos: node2.location.expression.end_pos
129
+ ).source.include?("\n\n")
130
+ end
131
+
132
+ def swap(range1, range2, corrector:)
133
+ inserted = range2.source
134
+ corrector.insert_before(range1, inserted)
135
+ corrector.remove(range2)
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -50,6 +50,11 @@ module RuboCop
50
50
  # foo && foo.bar { |e| e.something }
51
51
  # foo && foo.bar(param) { |e| e.something }
52
52
  #
53
+ # foo ? foo.bar : nil
54
+ # foo.nil? ? nil : foo.bar
55
+ # !foo.nil? ? foo.bar : nil
56
+ # !foo ? nil : foo.bar
57
+ #
53
58
  # # good
54
59
  # foo&.bar
55
60
  # foo&.bar&.baz
@@ -105,6 +110,17 @@ module RuboCop
105
110
  }
106
111
  PATTERN
107
112
 
113
+ # @!method ternary_safe_navigation_candidate(node)
114
+ def_node_matcher :ternary_safe_navigation_candidate, <<~PATTERN
115
+ {
116
+ (if (send $_ {:nil? :!}) nil $_)
117
+
118
+ (if (send (send $_ :nil?) :!) $_ nil)
119
+
120
+ (if $_ $_ nil)
121
+ }
122
+ PATTERN
123
+
108
124
  # @!method not_nil_check?(node)
109
125
  def_node_matcher :not_nil_check?, '(send (send $_ :nil?) :!)'
110
126
 
@@ -118,9 +134,11 @@ module RuboCop
118
134
  check_node(node)
119
135
  end
120
136
 
137
+ private
138
+
121
139
  def check_node(node)
122
140
  checked_variable, receiver, method_chain, method = extract_parts(node)
123
- return unless receiver == checked_variable
141
+ return if receiver != checked_variable || receiver.nil?
124
142
  return if use_var_only_in_unless_modifier?(node, checked_variable)
125
143
  return if chain_length(method_chain, method) > max_chain_length
126
144
  return if unsafe_method_used?(method_chain, method)
@@ -133,10 +151,8 @@ module RuboCop
133
151
  node.if_type? && node.unless? && !method_called?(variable)
134
152
  end
135
153
 
136
- private
137
-
138
154
  def autocorrect(corrector, node)
139
- body = node.node_parts[1]
155
+ body = extract_body(node)
140
156
  method_call = method_call(node)
141
157
 
142
158
  corrector.remove(begin_range(node, body))
@@ -147,6 +163,14 @@ module RuboCop
147
163
  add_safe_nav_to_all_methods_in_chain(corrector, method_call, body)
148
164
  end
149
165
 
166
+ def extract_body(node)
167
+ if node.if_type? && node.ternary?
168
+ node.branches.find { |branch| !branch.nil_type? }
169
+ else
170
+ node.node_parts[1]
171
+ end
172
+ end
173
+
150
174
  def handle_comments(corrector, node, method_call)
151
175
  comments = comments(node)
152
176
  return if comments.empty?
@@ -174,7 +198,7 @@ module RuboCop
174
198
  end
175
199
 
176
200
  def allowed_if_condition?(node)
177
- node.else? || node.elsif? || node.ternary?
201
+ node.else? || node.elsif?
178
202
  end
179
203
 
180
204
  def method_call(node)
@@ -192,7 +216,12 @@ module RuboCop
192
216
  end
193
217
 
194
218
  def extract_parts_from_if(node)
195
- variable, receiver = modifier_if_safe_navigation_candidate(node)
219
+ variable, receiver =
220
+ if node.ternary?
221
+ ternary_safe_navigation_candidate(node)
222
+ else
223
+ modifier_if_safe_navigation_candidate(node)
224
+ end
196
225
 
197
226
  checked_variable, matching_receiver, method = extract_common_parts(receiver, variable)
198
227
 
@@ -49,7 +49,8 @@ module RuboCop
49
49
  MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
50
50
  RESTRICT_ON_SEND = %i[select find_all reject].freeze
51
51
  REPLACEMENTS = { select: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
52
- REGEXP_METHODS = %i[match? =~].to_set.freeze
52
+ OPPOSITE_REPLACEMENTS = { select: 'grep_v', find_all: 'grep_v', reject: 'grep' }.freeze
53
+ REGEXP_METHODS = %i[match? =~ !~].to_set.freeze
53
54
 
54
55
  # @!method regexp_match?(node)
55
56
  def_node_matcher :regexp_match?, <<~PATTERN
@@ -90,8 +91,10 @@ module RuboCop
90
91
  return unless (regexp_method_send_node = extract_send_node(block_node))
91
92
  return if match_predicate_without_receiver?(regexp_method_send_node)
92
93
 
94
+ opposite = regexp_method_send_node.send_type? && regexp_method_send_node.method?(:!~)
93
95
  regexp = find_regexp(regexp_method_send_node, block_node)
94
- register_offense(node, block_node, regexp)
96
+
97
+ register_offense(node, block_node, regexp, opposite)
95
98
  end
96
99
 
97
100
  private
@@ -102,8 +105,9 @@ module RuboCop
102
105
  node.hash_type? || creates_hash?(node) || env_const?(node)
103
106
  end
104
107
 
105
- def register_offense(node, block_node, regexp)
106
- replacement = REPLACEMENTS[node.method_name.to_sym]
108
+ def register_offense(node, block_node, regexp, opposite)
109
+ method_name = node.method_name.to_sym
110
+ replacement = opposite ? OPPOSITE_REPLACEMENTS[method_name] : REPLACEMENTS[method_name]
107
111
  message = format(MSG, replacement: replacement, original_method: node.method_name)
108
112
 
109
113
  add_offense(block_node, message: message) do |corrector|
@@ -37,13 +37,14 @@ module RuboCop
37
37
  end
38
38
 
39
39
  def on_new_investigation
40
- return if processed_source.blank?
40
+ return if processed_source.blank? || !processed_source.raw_source.include?(';')
41
41
 
42
42
  check_for_line_terminator_or_opener
43
43
  end
44
44
 
45
45
  def on_begin(node)
46
46
  return if cop_config['AllowAsExpressionSeparator']
47
+ return unless node.source.include?(';')
47
48
 
48
49
  exprs = node.children
49
50
 
@@ -95,11 +95,7 @@ module RuboCop
95
95
  end
96
96
 
97
97
  def offense?(node)
98
- # If it's a string within an interpolation, then it's not an offense
99
- # for this cop.
100
- return false if inside_interpolation?(node)
101
-
102
- wrong_quotes?(node)
98
+ wrong_quotes?(node) && !inside_interpolation?(node)
103
99
  end
104
100
 
105
101
  def consistent_multiline?
@@ -7,7 +7,7 @@ module RuboCop
7
7
  #
8
8
  # If you prefer a style that allows block for method with arguments,
9
9
  # please set `true` to `AllowMethodsWithArguments`.
10
- # respond_to , and `define_method?` methods are allowed by default.
10
+ # `define_method?` methods are allowed by default.
11
11
  # These are customizable with `AllowedMethods` option.
12
12
  #
13
13
  # @safety
@@ -72,12 +72,10 @@ module RuboCop
72
72
  # # some comment
73
73
  # end
74
74
  #
75
- # @example AllowedMethods: [respond_to, define_method] (default)
75
+ # @example AllowedMethods: [define_method] (default)
76
76
  # # good
77
- # respond_to { |foo| foo.bar }
78
77
  # define_method(:foo) { |foo| foo.bar }
79
78
  #
80
- #
81
79
  # @example AllowedPatterns: [] (default)
82
80
  # # bad
83
81
  # something.map { |s| s.upcase }
@@ -38,7 +38,7 @@ module RuboCop
38
38
  new(cops, config, options)
39
39
  end
40
40
 
41
- # @return [Array<Cop::Cop>]
41
+ # @return [Array<Cop::Base>]
42
42
  def self.mobilize_cops(cop_classes, config, options = {})
43
43
  cop_classes = Registry.new(cop_classes.to_a, options) unless cop_classes.is_a?(Registry)
44
44
 
@@ -52,6 +52,21 @@ module RuboCop
52
52
  end
53
53
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
54
54
 
55
+ def any_descendant?(node, *types)
56
+ if block_given?
57
+ node.each_descendant(*types) do |descendant|
58
+ return true if yield(descendant)
59
+ end
60
+ else
61
+ # Use a block version to avoid allocating enumerators.
62
+ node.each_descendant do # rubocop:disable Lint/UnreachableLoop
63
+ return true
64
+ end
65
+ end
66
+
67
+ false
68
+ end
69
+
55
70
  def args_begin(node)
56
71
  loc = node.loc
57
72
  selector = if node.super_type? || node.yield_type?
@@ -71,14 +86,19 @@ module RuboCop
71
86
  def on_node(syms, sexp, excludes = [], &block)
72
87
  return to_enum(:on_node, syms, sexp, excludes) unless block
73
88
 
74
- yield sexp if Array(syms).include?(sexp.type)
75
- return if Array(excludes).include?(sexp.type)
89
+ yield sexp if include_or_equal?(syms, sexp.type)
90
+ return if include_or_equal?(excludes, sexp.type)
76
91
 
77
92
  sexp.each_child_node { |elem| on_node(syms, elem, excludes, &block) }
78
93
  end
79
94
 
95
+ LINE_BEGINS_REGEX_CACHE = Hash.new do |hash, index|
96
+ hash[index] = /^\s{#{index}}\S/
97
+ end
98
+ private_constant :LINE_BEGINS_REGEX_CACHE
99
+
80
100
  def begins_its_line?(range)
81
- range.source_line.index(/\S/) == range.column
101
+ range.source_line.match?(LINE_BEGINS_REGEX_CACHE[range.column])
82
102
  end
83
103
 
84
104
  # Returns, for example, a bare `if` node if the given node is an `if`
@@ -152,16 +172,23 @@ module RuboCop
152
172
  ' ' * (node.loc.column + offset)
153
173
  end
154
174
 
175
+ @to_supported_styles_cache = {}
176
+
155
177
  def to_supported_styles(enforced_style)
156
- enforced_style.sub(/^Enforced/, 'Supported').sub('Style', 'Styles')
178
+ @to_supported_styles_cache[enforced_style] ||=
179
+ enforced_style.sub(/^Enforced/, 'Supported').sub('Style', 'Styles')
157
180
  end
158
181
 
159
182
  private
160
183
 
161
184
  def compatible_external_encoding_for?(src)
162
- src = src.dup if RUBY_VERSION < '2.3' || RUBY_ENGINE == 'jruby'
185
+ src = src.dup if RUBY_ENGINE == 'jruby'
163
186
  src.force_encoding(Encoding.default_external).valid_encoding?
164
187
  end
188
+
189
+ def include_or_equal?(source, target)
190
+ source == target || (source.is_a?(Array) && source.include?(target))
191
+ end
165
192
  end
166
193
  end
167
194
  end
@@ -83,7 +83,7 @@ module RuboCop
83
83
  end
84
84
 
85
85
  def multiple_assignment_node
86
- grandparent_node = node.parent ? node.parent.parent : nil
86
+ grandparent_node = node.parent&.parent
87
87
  return nil unless grandparent_node
88
88
  return nil unless grandparent_node.type == MULTIPLE_ASSIGNMENT_TYPE
89
89
  return nil unless node.parent.type == MULTIPLE_LEFT_HAND_SIDE_TYPE
@@ -108,34 +108,26 @@ module RuboCop
108
108
  :skip_children
109
109
  end
110
110
 
111
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
111
+ # rubocop:disable Layout/ClassStructure
112
+ NODE_HANDLER_METHOD_NAMES = [
113
+ [VARIABLE_ASSIGNMENT_TYPE, :process_variable_assignment],
114
+ [REGEXP_NAMED_CAPTURE_TYPE, :process_regexp_named_captures],
115
+ [MULTIPLE_ASSIGNMENT_TYPE, :process_variable_multiple_assignment],
116
+ [VARIABLE_REFERENCE_TYPE, :process_variable_referencing],
117
+ [RESCUE_TYPE, :process_rescue],
118
+ [ZERO_ARITY_SUPER_TYPE, :process_zero_arity_super],
119
+ [SEND_TYPE, :process_send],
120
+ *ARGUMENT_DECLARATION_TYPES.product([:process_variable_declaration]),
121
+ *OPERATOR_ASSIGNMENT_TYPES.product([:process_variable_operator_assignment]),
122
+ *LOOP_TYPES.product([:process_loop]),
123
+ *SCOPE_TYPES.product([:process_scope])
124
+ ].to_h.freeze
125
+ private_constant :NODE_HANDLER_METHOD_NAMES
126
+ # rubocop:enable Layout/ClassStructure
127
+
112
128
  def node_handler_method_name(node)
113
- case node.type
114
- when VARIABLE_ASSIGNMENT_TYPE
115
- :process_variable_assignment
116
- when REGEXP_NAMED_CAPTURE_TYPE
117
- :process_regexp_named_captures
118
- when MULTIPLE_ASSIGNMENT_TYPE
119
- :process_variable_multiple_assignment
120
- when VARIABLE_REFERENCE_TYPE
121
- :process_variable_referencing
122
- when RESCUE_TYPE
123
- :process_rescue
124
- when ZERO_ARITY_SUPER_TYPE
125
- :process_zero_arity_super
126
- when SEND_TYPE
127
- :process_send
128
- when *ARGUMENT_DECLARATION_TYPES
129
- :process_variable_declaration
130
- when *OPERATOR_ASSIGNMENT_TYPES
131
- :process_variable_operator_assignment
132
- when *LOOP_TYPES
133
- :process_loop
134
- when *SCOPE_TYPES
135
- :process_scope
136
- end
129
+ NODE_HANDLER_METHOD_NAMES[node.type]
137
130
  end
138
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
139
131
 
140
132
  def process_variable_declaration(node)
141
133
  variable_name = node.children.first
@@ -358,13 +350,12 @@ module RuboCop
358
350
  end
359
351
  end
360
352
 
361
- # Use Node#equal? for accurate check.
362
353
  def scanned_node?(node)
363
- scanned_nodes.any? { |scanned_node| scanned_node.equal?(node) }
354
+ scanned_nodes.include?(node)
364
355
  end
365
356
 
366
357
  def scanned_nodes
367
- @scanned_nodes ||= []
358
+ @scanned_nodes ||= Set.new.compare_by_identity
368
359
  end
369
360
 
370
361
  # Hooks invoked by VariableTable.
@@ -42,7 +42,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
42
42
  content << "#{description}\n"
43
43
  content << safety_object(safety_objects) if safety_objects.any? { |s| !s.text.blank? }
44
44
  content << examples(examples_objects) if examples_objects.any?
45
- content << configurations(pars)
45
+ content << configurations(cop.department, pars)
46
46
  content << references(cop)
47
47
  content
48
48
  end
@@ -136,7 +136,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
136
136
  content
137
137
  end
138
138
 
139
- def configurations(pars)
139
+ def configurations(department, pars)
140
140
  return '' if pars.empty?
141
141
 
142
142
  header = ['Name', 'Default value', 'Configurable values']
@@ -147,12 +147,20 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
147
147
  content = configs.map do |name|
148
148
  configurable = configurable_values(pars, name)
149
149
  default = format_table_value(pars[name])
150
- [name, default, configurable]
150
+
151
+ [configuration_name(department, name), default, configurable]
151
152
  end
152
153
 
153
154
  h3('Configurable attributes') + to_table(header, content)
154
155
  end
155
156
 
157
+ def configuration_name(department, name)
158
+ return name unless name == 'AllowMultilineFinalElement'
159
+
160
+ filename = "#{department_to_basename(department)}.adoc"
161
+ "xref:#{filename}#allowmultilinefinalelement[AllowMultilineFinalElement]"
162
+ end
163
+
156
164
  # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
157
165
  def configurable_values(pars, name)
158
166
  case name
@@ -227,10 +235,21 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
227
235
  content
228
236
  end
229
237
 
238
+ def footer_for_department(department)
239
+ return '' unless department == :Layout
240
+
241
+ filename = "#{department_to_basename(department)}_footer.adoc"
242
+ file = "#{Dir.pwd}/docs/modules/ROOT/partials/#{filename}"
243
+ return '' unless File.exist?(file)
244
+
245
+ "\ninclude::../partials/#{filename}[]\n"
246
+ end
247
+
230
248
  def print_cops_of_department(department)
231
249
  selected_cops = cops_of_department(department)
232
250
  content = +"= #{department}\n"
233
251
  selected_cops.each { |cop| content << print_cop_with_doc(cop) }
252
+ content << footer_for_department(department)
234
253
  file_name = "#{Dir.pwd}/docs/modules/ROOT/pages/#{department_to_basename(department)}.adoc"
235
254
  File.open(file_name, 'w') do |file|
236
255
  puts "* generated #{file_name}"
@@ -35,7 +35,7 @@ module RuboCop
35
35
 
36
36
  # Checks if this directive relates to single line
37
37
  def single_line?
38
- !self.class.before_comment(comment.text).empty?
38
+ !comment.text.start_with?(DIRECTIVE_COMMENT_REGEXP)
39
39
  end
40
40
 
41
41
  # Checks if this directive contains all the given cop names
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # A wrapper around patterns array to perform optimized search.
5
+ #
6
+ # For projects with a large set of rubocop todo files, most items in `Exclude`/`Include`
7
+ # are exact file names. It is wasteful to linearly check the list of patterns over and over
8
+ # to check if the file is relevant to the cop.
9
+ #
10
+ # This class partitions an array of patterns into a set of exact match strings and the rest
11
+ # of the patterns. This way we can firstly do a cheap check in the set and then proceed via
12
+ # the costly patterns check, if needed.
13
+ # @api private
14
+ class FilePatterns
15
+ @cache = {}.compare_by_identity
16
+
17
+ def self.from(patterns)
18
+ @cache[patterns] ||= new(patterns)
19
+ end
20
+
21
+ def initialize(patterns)
22
+ @strings = Set.new
23
+ @patterns = []
24
+ partition_patterns(patterns)
25
+ end
26
+
27
+ def match?(path)
28
+ @strings.include?(path) || @patterns.any? { |pattern| PathUtil.match_path?(pattern, path) }
29
+ end
30
+
31
+ private
32
+
33
+ def partition_patterns(patterns)
34
+ patterns.each do |pattern|
35
+ if pattern.is_a?(String) && !pattern.match?(/[*{\[?]/)
36
+ @strings << pattern
37
+ else
38
+ @patterns << pattern
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -65,6 +65,10 @@ module RuboCop
65
65
  @options.fetch(:offense_counts, true)
66
66
  end
67
67
 
68
+ def auto_gen_enforced_style?
69
+ @options.fetch(:auto_gen_enforced_style, true)
70
+ end
71
+
68
72
  def command
69
73
  command = 'rubocop --auto-gen-config'
70
74
 
@@ -79,6 +83,8 @@ module RuboCop
79
83
 
80
84
  command += ' --no-auto-gen-timestamp' unless show_timestamp?
81
85
 
86
+ command += ' --no-auto-gen-enforced-style' unless auto_gen_enforced_style?
87
+
82
88
  command
83
89
  end
84
90
 
@@ -172,17 +178,22 @@ module RuboCop
172
178
  end
173
179
 
174
180
  def output_cop_config(output_buffer, cfg, cop_name)
175
- # 'Enabled' option will be put into file only if exclude
176
- # limit is exceeded.
177
- cfg_without_enabled = cfg.reject { |key| key == 'Enabled' }
178
-
181
+ filtered_cfg = filtered_config(cfg)
179
182
  output_buffer.puts "#{cop_name}:"
180
- cfg_without_enabled.each do |key, value|
183
+ filtered_cfg.each do |key, value|
181
184
  value = value[0] if value.is_a?(Array)
182
185
  output_buffer.puts " #{key}: #{value}"
183
186
  end
184
187
 
185
- output_offending_files(output_buffer, cfg_without_enabled, cop_name)
188
+ output_offending_files(output_buffer, filtered_cfg, cop_name)
189
+ end
190
+
191
+ def filtered_config(cfg)
192
+ # 'Enabled' option will be put into file only if exclude
193
+ # limit is exceeded.
194
+ rejected_keys = ['Enabled']
195
+ rejected_keys << 'EnforcedStyle' unless auto_gen_enforced_style?
196
+ cfg.reject { |key| rejected_keys.include?(key) }
186
197
  end
187
198
 
188
199
  def output_offending_files(output_buffer, cfg, cop_name)
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
3
4
  require 'cgi'
4
5
  require 'erb'
5
6
  require 'ostruct'
6
- require 'base64'
7
7
 
8
8
  module RuboCop
9
9
  module Formatter
@@ -6,6 +6,7 @@ module RuboCop
6
6
 
7
7
  require_relative 'formatter/base_formatter'
8
8
  require_relative 'formatter/simple_text_formatter'
9
+
9
10
  # relies on simple text
10
11
  require_relative 'formatter/clang_style_formatter'
11
12
  require_relative 'formatter/disabled_config_formatter'
@@ -18,11 +19,12 @@ module RuboCop
18
19
  require_relative 'formatter/junit_formatter'
19
20
  require_relative 'formatter/markdown_formatter'
20
21
  require_relative 'formatter/offense_count_formatter'
22
+ require_relative 'formatter/pacman_formatter'
21
23
  require_relative 'formatter/progress_formatter'
22
24
  require_relative 'formatter/quiet_formatter'
23
25
  require_relative 'formatter/tap_formatter'
24
26
  require_relative 'formatter/worst_offenders_formatter'
25
- require_relative 'formatter/pacman_formatter'
27
+
26
28
  # relies on progress formatter
27
29
  require_relative 'formatter/auto_gen_config_formatter'
28
30