rubocop 1.32.0 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +104 -16
  4. data/config/obsoletion.yml +23 -1
  5. data/lib/rubocop/arguments_env.rb +17 -0
  6. data/lib/rubocop/arguments_file.rb +17 -0
  7. data/lib/rubocop/cache_config.rb +29 -0
  8. data/lib/rubocop/cli/command/{auto_genenerate_config.rb → auto_generate_config.rb} +2 -2
  9. data/lib/rubocop/cli/command/execute_runner.rb +7 -7
  10. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  11. data/lib/rubocop/cli/command/suggest_extensions.rb +53 -15
  12. data/lib/rubocop/config.rb +1 -1
  13. data/lib/rubocop/config_finder.rb +68 -0
  14. data/lib/rubocop/config_loader.rb +12 -40
  15. data/lib/rubocop/config_loader_resolver.rb +1 -5
  16. data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
  17. data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
  18. data/lib/rubocop/config_obsoletion.rb +7 -2
  19. data/lib/rubocop/cop/cop.rb +1 -1
  20. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +58 -0
  21. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  22. data/lib/rubocop/cop/generator/require_file_injector.rb +2 -2
  23. data/lib/rubocop/cop/generator.rb +1 -2
  24. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +69 -0
  25. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +62 -0
  26. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  27. data/lib/rubocop/cop/layout/block_alignment.rb +16 -12
  28. data/lib/rubocop/cop/layout/block_end_newline.rb +35 -5
  29. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +5 -2
  30. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +2 -0
  31. data/lib/rubocop/cop/layout/end_of_line.rb +4 -4
  32. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -1
  33. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  34. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  35. data/lib/rubocop/cop/layout/indentation_width.rb +6 -2
  36. data/lib/rubocop/cop/layout/line_length.rb +4 -1
  37. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  38. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  39. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  40. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  41. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  42. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  43. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
  44. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +25 -9
  45. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +28 -3
  46. data/lib/rubocop/cop/legacy/corrections_proxy.rb +1 -1
  47. data/lib/rubocop/cop/legacy/corrector.rb +1 -1
  48. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +21 -8
  49. data/lib/rubocop/cop/lint/debugger.rb +26 -16
  50. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  51. data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
  52. data/lib/rubocop/cop/lint/duplicate_methods.rb +11 -1
  53. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
  54. data/lib/rubocop/cop/lint/duplicate_require.rb +1 -1
  55. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  56. data/lib/rubocop/cop/lint/empty_class.rb +3 -1
  57. data/lib/rubocop/cop/lint/empty_conditional_body.rb +107 -1
  58. data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -9
  59. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -0
  60. data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
  61. data/lib/rubocop/cop/lint/next_without_accumulator.rb +25 -6
  62. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +6 -6
  63. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +12 -0
  64. data/lib/rubocop/cop/lint/number_conversion.rb +24 -8
  65. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
  66. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
  67. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
  68. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
  69. data/lib/rubocop/cop/lint/redundant_require_statement.rb +29 -9
  70. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +9 -3
  71. data/lib/rubocop/cop/lint/redundant_with_index.rb +13 -10
  72. data/lib/rubocop/cop/lint/redundant_with_object.rb +12 -11
  73. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  74. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
  75. data/lib/rubocop/cop/lint/shadowed_exception.rb +15 -10
  76. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +27 -3
  77. data/lib/rubocop/cop/lint/unreachable_loop.rb +9 -3
  78. data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
  79. data/lib/rubocop/cop/lint/useless_access_modifier.rb +8 -6
  80. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  81. data/lib/rubocop/cop/lint/void.rb +2 -0
  82. data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
  83. data/lib/rubocop/cop/metrics/block_length.rb +6 -7
  84. data/lib/rubocop/cop/metrics/method_length.rb +8 -8
  85. data/lib/rubocop/cop/mixin/allowed_methods.rb +20 -1
  86. data/lib/rubocop/cop/mixin/allowed_pattern.rb +17 -1
  87. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  88. data/lib/rubocop/cop/mixin/comments_help.rb +17 -1
  89. data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -1
  90. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
  91. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +82 -4
  92. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -6
  93. data/lib/rubocop/cop/mixin/method_complexity.rb +8 -13
  94. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  95. data/lib/rubocop/cop/mixin/range_help.rb +4 -5
  96. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
  97. data/lib/rubocop/cop/mixin/surrounding_space.rb +6 -5
  98. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  99. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  100. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
  101. data/lib/rubocop/cop/naming/predicate_name.rb +24 -3
  102. data/lib/rubocop/cop/style/access_modifier_declarations.rb +97 -1
  103. data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
  104. data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
  105. data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
  106. data/lib/rubocop/cop/style/case_equality.rb +40 -10
  107. data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
  108. data/lib/rubocop/cop/style/class_equality_comparison.rb +32 -7
  109. data/lib/rubocop/cop/style/class_methods_definitions.rb +2 -1
  110. data/lib/rubocop/cop/style/collection_compact.rb +6 -1
  111. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  112. data/lib/rubocop/cop/style/combinable_loops.rb +3 -1
  113. data/lib/rubocop/cop/style/double_negation.rb +2 -0
  114. data/lib/rubocop/cop/style/each_for_simple_loop.rb +41 -6
  115. data/lib/rubocop/cop/style/each_with_object.rb +39 -8
  116. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  117. data/lib/rubocop/cop/style/empty_heredoc.rb +15 -1
  118. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  119. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  120. data/lib/rubocop/cop/style/endless_method.rb +1 -1
  121. data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
  122. data/lib/rubocop/cop/style/for.rb +2 -0
  123. data/lib/rubocop/cop/style/format_string_token.rb +21 -8
  124. data/lib/rubocop/cop/style/guard_clause.rb +27 -16
  125. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -1
  126. data/lib/rubocop/cop/style/hash_except.rb +0 -4
  127. data/lib/rubocop/cop/style/hash_syntax.rb +17 -0
  128. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
  129. data/lib/rubocop/cop/style/inverse_methods.rb +8 -6
  130. data/lib/rubocop/cop/style/magic_comment_format.rb +307 -0
  131. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +15 -4
  132. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
  133. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
  134. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -6
  135. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
  136. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -1
  137. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  138. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
  139. data/lib/rubocop/cop/style/next.rb +3 -5
  140. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  141. data/lib/rubocop/cop/style/numeric_literals.rb +16 -1
  142. data/lib/rubocop/cop/style/numeric_predicate.rb +28 -8
  143. data/lib/rubocop/cop/style/object_then.rb +2 -0
  144. data/lib/rubocop/cop/style/operator_method_call.rb +39 -0
  145. data/lib/rubocop/cop/style/perl_backrefs.rb +22 -1
  146. data/lib/rubocop/cop/style/proc.rb +4 -1
  147. data/lib/rubocop/cop/style/redundant_begin.rb +3 -0
  148. data/lib/rubocop/cop/style/redundant_condition.rb +24 -6
  149. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  150. data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
  151. data/lib/rubocop/cop/style/redundant_parentheses.rb +19 -22
  152. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
  153. data/lib/rubocop/cop/style/redundant_self.rb +2 -0
  154. data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
  155. data/lib/rubocop/cop/style/redundant_sort_by.rb +24 -8
  156. data/lib/rubocop/cop/style/redundant_string_escape.rb +173 -0
  157. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  158. data/lib/rubocop/cop/style/safe_navigation.rb +4 -2
  159. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  160. data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
  161. data/lib/rubocop/cop/style/static_class.rb +32 -1
  162. data/lib/rubocop/cop/style/symbol_array.rb +3 -1
  163. data/lib/rubocop/cop/style/symbol_proc.rb +38 -12
  164. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -13
  165. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -1
  166. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  167. data/lib/rubocop/cop/style/word_array.rb +3 -1
  168. data/lib/rubocop/cop/util.rb +1 -1
  169. data/lib/rubocop/ext/range.rb +15 -0
  170. data/lib/rubocop/feature_loader.rb +94 -0
  171. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  172. data/lib/rubocop/formatter/disabled_config_formatter.rb +9 -3
  173. data/lib/rubocop/formatter/html_formatter.rb +3 -3
  174. data/lib/rubocop/formatter/markdown_formatter.rb +1 -1
  175. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  176. data/lib/rubocop/options.rb +13 -13
  177. data/lib/rubocop/result_cache.rb +22 -20
  178. data/lib/rubocop/rspec/shared_contexts.rb +13 -1
  179. data/lib/rubocop/runner.rb +4 -0
  180. data/lib/rubocop/server/cache.rb +41 -2
  181. data/lib/rubocop/server/cli.rb +26 -2
  182. data/lib/rubocop/server/client_command/exec.rb +5 -0
  183. data/lib/rubocop/server/core.rb +2 -1
  184. data/lib/rubocop/server/socket_reader.rb +5 -1
  185. data/lib/rubocop/server.rb +1 -1
  186. data/lib/rubocop/version.rb +8 -2
  187. data/lib/rubocop.rb +8 -3
  188. metadata +20 -9
  189. data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
@@ -0,0 +1,307 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Ensures magic comments are written consistently throughout your code base.
7
+ # Looks for discrepancies in separators (`-` vs `_`) and capitalization for
8
+ # both magic comment directives and values.
9
+ #
10
+ # Required capitalization can be set with the `DirectiveCapitalization` and
11
+ # `ValueCapitalization` configuration keys.
12
+ #
13
+ # NOTE: If one of these configuration is set to nil, any capitalization is allowed.
14
+ #
15
+ # @example EnforcedStyle: snake_case (default)
16
+ # # The `snake_case` style will enforce that the frozen string literal
17
+ # # comment is written in snake case. (Words separated by underscores)
18
+ # # bad
19
+ # # frozen-string-literal: true
20
+ #
21
+ # module Bar
22
+ # # ...
23
+ # end
24
+ #
25
+ # # good
26
+ # # frozen_string_literal: false
27
+ #
28
+ # module Bar
29
+ # # ...
30
+ # end
31
+ #
32
+ # @example EnforcedStyle: kebab_case
33
+ # # The `kebab_case` style will enforce that the frozen string literal
34
+ # # comment is written in kebab case. (Words separated by hyphens)
35
+ # # bad
36
+ # # frozen_string_literal: true
37
+ #
38
+ # module Baz
39
+ # # ...
40
+ # end
41
+ #
42
+ # # good
43
+ # # frozen-string-literal: true
44
+ #
45
+ # module Baz
46
+ # # ...
47
+ # end
48
+ #
49
+ # @example DirectiveCapitalization: lowercase (default)
50
+ # # bad
51
+ # # FROZEN-STRING-LITERAL: true
52
+ #
53
+ # # good
54
+ # # frozen-string-literal: true
55
+ #
56
+ # @example DirectiveCapitalization: uppercase
57
+ # # bad
58
+ # # frozen-string-literal: true
59
+ #
60
+ # # good
61
+ # # FROZEN-STRING-LITERAL: true
62
+ #
63
+ # @example DirectiveCapitalization: nil
64
+ # # any capitalization is accepted
65
+ #
66
+ # # good
67
+ # # frozen-string-literal: true
68
+ #
69
+ # # good
70
+ # # FROZEN-STRING-LITERAL: true
71
+ #
72
+ # @example ValueCapitalization: nil (default)
73
+ # # any capitalization is accepted
74
+ #
75
+ # # good
76
+ # # frozen-string-literal: true
77
+ #
78
+ # # good
79
+ # # frozen-string-literal: TRUE
80
+ #
81
+ # @example ValueCapitalization: lowercase
82
+ # # when a value is not given, any capitalization is accepted
83
+ #
84
+ # # bad
85
+ # # frozen-string-literal: TRUE
86
+ #
87
+ # # good
88
+ # # frozen-string-literal: TRUE
89
+ #
90
+ # @example ValueCapitalization: uppercase
91
+ # # bad
92
+ # # frozen-string-literal: true
93
+ #
94
+ # # good
95
+ # # frozen-string-literal: TRUE
96
+ #
97
+ class MagicCommentFormat < Base
98
+ include ConfigurableEnforcedStyle
99
+ extend AutoCorrector
100
+
101
+ SNAKE_SEPARATOR = '_'
102
+ KEBAB_SEPARATOR = '-'
103
+ MSG = 'Prefer %<style>s case for magic comments.'
104
+ MSG_VALUE = 'Prefer %<case>s for magic comment values.'
105
+
106
+ # Value object to extract source ranges for the different parts of a magic comment
107
+ class CommentRange
108
+ extend Forwardable
109
+
110
+ DIRECTIVE_REGEXP = Regexp.union(MagicComment::KEYWORDS.map do |_, v|
111
+ Regexp.new(v, Regexp::IGNORECASE)
112
+ end).freeze
113
+
114
+ VALUE_REGEXP = Regexp.new("(?:#{DIRECTIVE_REGEXP}:\s*)(.*?)(?=;|$)")
115
+
116
+ def_delegators :@comment, :text, :loc
117
+ attr_reader :comment
118
+
119
+ def initialize(comment)
120
+ @comment = comment
121
+ end
122
+
123
+ # A magic comment can contain one directive (normal style) or
124
+ # multiple directives (emacs style)
125
+ def directives
126
+ @directives ||= begin
127
+ matches = []
128
+
129
+ text.scan(DIRECTIVE_REGEXP) do
130
+ offset = Regexp.last_match.offset(0)
131
+ matches << loc.expression.adjust(begin_pos: offset.first)
132
+ .with(end_pos: loc.expression.begin_pos + offset.last)
133
+ end
134
+
135
+ matches
136
+ end
137
+ end
138
+
139
+ # A magic comment can contain one value (normal style) or
140
+ # multiple directives (emacs style)
141
+ def values
142
+ @values ||= begin
143
+ matches = []
144
+
145
+ text.scan(VALUE_REGEXP) do
146
+ offset = Regexp.last_match.offset(1)
147
+ matches << loc.expression.adjust(begin_pos: offset.first)
148
+ .with(end_pos: loc.expression.begin_pos + offset.last)
149
+ end
150
+
151
+ matches
152
+ end
153
+ end
154
+ end
155
+
156
+ def on_new_investigation
157
+ return unless processed_source.ast
158
+
159
+ magic_comments.each do |comment|
160
+ issues = find_issues(comment)
161
+ register_offenses(issues) if issues.any?
162
+ end
163
+ end
164
+
165
+ private
166
+
167
+ def magic_comments
168
+ processed_source.each_comment_in_lines(leading_comment_lines)
169
+ .select { |comment| MagicComment.parse(comment.text).valid? }
170
+ .map { |comment| CommentRange.new(comment) }
171
+ end
172
+
173
+ def leading_comment_lines
174
+ first_non_comment_token = processed_source.tokens.find { |token| !token.comment? }
175
+
176
+ if first_non_comment_token
177
+ 0...first_non_comment_token.line
178
+ else
179
+ (0..)
180
+ end
181
+ end
182
+
183
+ def find_issues(comment)
184
+ issues = { directives: [], values: [] }
185
+
186
+ comment.directives.each do |directive|
187
+ issues[:directives] << directive if directive_offends?(directive)
188
+ end
189
+
190
+ comment.values.each do |value| # rubocop:disable Style/HashEachMethods
191
+ issues[:values] << value if wrong_capitalization?(value.source, value_capitalization)
192
+ end
193
+
194
+ issues
195
+ end
196
+
197
+ def directive_offends?(directive)
198
+ incorrect_separator?(directive.source) ||
199
+ wrong_capitalization?(directive.source, directive_capitalization)
200
+ end
201
+
202
+ def register_offenses(issues)
203
+ fix_directives(issues[:directives])
204
+ fix_values(issues[:values])
205
+ end
206
+
207
+ def fix_directives(issues)
208
+ return if issues.empty?
209
+
210
+ msg = format(MSG, style: expected_style)
211
+
212
+ issues.each do |directive|
213
+ add_offense(directive, message: msg) do |corrector|
214
+ replacement = replace_separator(replace_capitalization(directive.source,
215
+ directive_capitalization))
216
+ corrector.replace(directive, replacement)
217
+ end
218
+ end
219
+ end
220
+
221
+ def fix_values(issues)
222
+ return if issues.empty?
223
+
224
+ msg = format(MSG_VALUE, case: value_capitalization)
225
+
226
+ issues.each do |value|
227
+ add_offense(value, message: msg) do |corrector|
228
+ corrector.replace(value, replace_capitalization(value.source, value_capitalization))
229
+ end
230
+ end
231
+ end
232
+
233
+ def expected_style
234
+ [directive_capitalization, style].compact.join(' ').gsub(/_?case\b/, '')
235
+ end
236
+
237
+ def wrong_separator
238
+ style == :snake_case ? KEBAB_SEPARATOR : SNAKE_SEPARATOR
239
+ end
240
+
241
+ def correct_separator
242
+ style == :snake_case ? SNAKE_SEPARATOR : KEBAB_SEPARATOR
243
+ end
244
+
245
+ def incorrect_separator?(text)
246
+ text[wrong_separator]
247
+ end
248
+
249
+ def wrong_capitalization?(text, expected_case)
250
+ return false unless expected_case
251
+
252
+ case expected_case
253
+ when :lowercase
254
+ text != text.downcase
255
+ when :uppercase
256
+ text != text.upcase
257
+ end
258
+ end
259
+
260
+ def replace_separator(text)
261
+ text.tr(wrong_separator, correct_separator)
262
+ end
263
+
264
+ def replace_capitalization(text, style)
265
+ return text unless style
266
+
267
+ case style
268
+ when :lowercase
269
+ text.downcase
270
+ when :uppercase
271
+ text.upcase
272
+ end
273
+ end
274
+
275
+ def line_range(line)
276
+ processed_source.buffer.line_range(line)
277
+ end
278
+
279
+ def directive_capitalization
280
+ cop_config['DirectiveCapitalization']&.to_sym.tap do |style|
281
+ unless valid_capitalization?(style)
282
+ raise "Unknown `DirectiveCapitalization` #{style} selected!"
283
+ end
284
+ end
285
+ end
286
+
287
+ def value_capitalization
288
+ cop_config['ValueCapitalization']&.to_sym.tap do |style|
289
+ unless valid_capitalization?(style)
290
+ raise "Unknown `ValueCapitalization` #{style} selected!"
291
+ end
292
+ end
293
+ end
294
+
295
+ def valid_capitalization?(style)
296
+ return true unless style
297
+
298
+ supported_capitalizations.include?(style)
299
+ end
300
+
301
+ def supported_capitalizations
302
+ cop_config['SupportedCapitalizations'].map(&:to_sym)
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
@@ -20,8 +20,8 @@ module RuboCop
20
20
  return if require_parentheses_for_hash_value_omission?(node)
21
21
  return if syntax_like_method_call?(node)
22
22
  return if super_call_without_arguments?(node)
23
- return if allowed_camel_case_method_call?(node)
24
23
  return if legitimate_call_with_parentheses?(node)
24
+ return if allowed_camel_case_method_call?(node)
25
25
  return if allowed_string_interpolation_method_call?(node)
26
26
 
27
27
  add_offense(offense_range(node), message: OMIT_MSG) do |corrector|
@@ -97,7 +97,8 @@ module RuboCop
97
97
  call_in_optional_arguments?(node) ||
98
98
  call_in_single_line_inheritance?(node) ||
99
99
  allowed_multiline_call_with_parentheses?(node) ||
100
- allowed_chained_call_with_parentheses?(node)
100
+ allowed_chained_call_with_parentheses?(node) ||
101
+ assignment_in_condition?(node)
101
102
  end
102
103
 
103
104
  def call_in_literals?(node)
@@ -130,7 +131,7 @@ module RuboCop
130
131
  call_as_argument_or_chain?(node) ||
131
132
  hash_literal_in_arguments?(node) ||
132
133
  node.descendants.any? do |n|
133
- n.forwarded_args_type? || ambigious_literal?(n) || logical_operator?(n) ||
134
+ n.forwarded_args_type? || ambiguous_literal?(n) || logical_operator?(n) ||
134
135
  call_with_braced_block?(n)
135
136
  end
136
137
  end
@@ -166,7 +167,7 @@ module RuboCop
166
167
  previous.parenthesized? || allowed_chained_call_with_parentheses?(previous)
167
168
  end
168
169
 
169
- def ambigious_literal?(node)
170
+ def ambiguous_literal?(node)
170
171
  splat?(node) || ternary_if?(node) || regexp_slash_literal?(node) || unary_literal?(node)
171
172
  end
172
173
 
@@ -202,6 +203,16 @@ module RuboCop
202
203
  def inside_string_interpolation?(node)
203
204
  node.ancestors.drop_while { |a| !a.begin_type? }.any?(&:dstr_type?)
204
205
  end
206
+
207
+ def assignment_in_condition?(node)
208
+ parent = node.parent
209
+ return false unless parent
210
+
211
+ grandparent = parent.parent
212
+ return false unless grandparent
213
+
214
+ parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
215
+ end
205
216
  end
206
217
  # rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
207
218
  end
@@ -12,7 +12,7 @@ module RuboCop
12
12
  private
13
13
 
14
14
  def require_parentheses(node)
15
- return if ignored_method?(node.method_name)
15
+ return if allowed_method_name?(node.method_name)
16
16
  return if matches_allowed_pattern?(node.method_name)
17
17
  return if eligible_for_parentheses_omission?(node)
18
18
  return unless node.arguments? && !node.parenthesized?
@@ -24,6 +24,10 @@ module RuboCop
24
24
  end
25
25
  end
26
26
 
27
+ def allowed_method_name?(name)
28
+ allowed_method?(name) || matches_allowed_pattern?(name)
29
+ end
30
+
27
31
  def eligible_for_parentheses_omission?(node)
28
32
  node.operator_method? || node.setter_method? || ignored_macro?(node)
29
33
  end
@@ -6,8 +6,8 @@ module RuboCop
6
6
  # Enforces the presence (default) or absence of parentheses in
7
7
  # method calls containing parameters.
8
8
  #
9
- # In the default style (require_parentheses), macro methods are ignored.
10
- # Additional methods can be added to the `IgnoredMethods`
9
+ # In the default style (require_parentheses), macro methods are allowed.
10
+ # Additional methods can be added to the `AllowedMethods`
11
11
  # or `AllowedPatterns` list. These options are
12
12
  # valid only in the default style. Macros can be included by
13
13
  # either setting `IgnoreMacros` to false or adding specific macros to
@@ -15,13 +15,13 @@ module RuboCop
15
15
  #
16
16
  # Precedence of options is all follows:
17
17
  #
18
- # 1. `IgnoredMethods`
18
+ # 1. `AllowedMethods`
19
19
  # 2. `AllowedPatterns`
20
20
  # 3. `IncludedMacros`
21
21
  #
22
22
  # eg. If a method is listed in both
23
- # `IncludedMacros` and `IgnoredMethods`, then the latter takes
24
- # precedence (that is, the method is ignored).
23
+ # `IncludedMacros` and `AllowedMethods`, then the latter takes
24
+ # precedence (that is, the method is allowed).
25
25
  #
26
26
  # In the alternative style (omit_parentheses), there are three additional
27
27
  # options.
@@ -65,7 +65,7 @@ module RuboCop
65
65
  # # Setter methods don't need parens
66
66
  # foo.bar = baz
67
67
  #
68
- # # okay with `puts` listed in `IgnoredMethods`
68
+ # # okay with `puts` listed in `AllowedMethods`
69
69
  # puts 'test'
70
70
  #
71
71
  # # okay with `^assert` listed in `AllowedPatterns`
@@ -197,7 +197,7 @@ module RuboCop
197
197
  require_relative 'method_call_with_args_parentheses/require_parentheses'
198
198
 
199
199
  include ConfigurableEnforcedStyle
200
- include IgnoredMethods
200
+ include AllowedMethods
201
201
  include AllowedPattern
202
202
  include RequireParentheses
203
203
  include OmitParentheses
@@ -5,8 +5,8 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for unwanted parentheses in parameterless method calls.
7
7
  #
8
- # This cop can be customized ignored methods with `IgnoredMethods`.
9
- # By default, there are no methods to ignored.
8
+ # This cop can be customized allowed methods with `AllowedMethods`.
9
+ # By default, there are no methods to allowed.
10
10
  #
11
11
  # @example
12
12
  # # bad
@@ -15,16 +15,17 @@ module RuboCop
15
15
  # # good
16
16
  # object.some_method
17
17
  #
18
- # @example IgnoredMethods: [] (default)
18
+ # @example AllowedMethods: [] (default)
19
19
  # # bad
20
20
  # object.foo()
21
21
  #
22
- # @example IgnoredMethods: [foo]
22
+ # @example AllowedMethods: [foo]
23
23
  # # good
24
24
  # object.foo()
25
25
  #
26
26
  class MethodCallWithoutArgsParentheses < Base
27
- include IgnoredMethods
27
+ include AllowedMethods
28
+ include AllowedPattern
28
29
  extend AutoCorrector
29
30
 
30
31
  MSG = 'Do not use parentheses for method calls with no arguments.'
@@ -33,7 +34,7 @@ module RuboCop
33
34
  return unless !node.arguments? && node.parenthesized?
34
35
  return if ineligible_node?(node)
35
36
  return if default_argument?(node)
36
- return if ignored_method?(node.method_name)
37
+ return if allowed_method_name?(node.method_name)
37
38
  return if same_name_assignment?(node)
38
39
 
39
40
  register_offense(node)
@@ -56,6 +57,10 @@ module RuboCop
56
57
  node.parent&.optarg_type?
57
58
  end
58
59
 
60
+ def allowed_method_name?(name)
61
+ allowed_method?(name) || matches_allowed_pattern?(name)
62
+ end
63
+
59
64
  def same_name_assignment?(node)
60
65
  any_assignment?(node) do |asgn_node|
61
66
  next variable_in_mass_assignment?(node.method_name, asgn_node) if asgn_node.masgn_type?
@@ -35,12 +35,15 @@ module RuboCop
35
35
  ignore_node(node.send_node)
36
36
  end
37
37
 
38
+ alias on_numblock on_block
39
+
38
40
  def on_send(node)
39
41
  return if ignored_node?(node)
40
42
 
41
43
  receiver = node.receiver
42
44
 
43
- return unless receiver&.block_type? && receiver.loc.end.is?('end')
45
+ return unless (receiver&.block_type? || receiver&.numblock_type?) &&
46
+ receiver.loc.end.is?('end')
44
47
 
45
48
  range = range_between(receiver.loc.end.begin_pos, node.source_range.end_pos)
46
49
 
@@ -31,7 +31,7 @@ module RuboCop
31
31
  node.send_node.each_node(:send) do |send_node|
32
32
  receiver = send_node.receiver
33
33
 
34
- next unless receiver&.block_type? && receiver&.multiline?
34
+ next unless (receiver&.block_type? || receiver&.numblock_type?) && receiver&.multiline?
35
35
 
36
36
  range = range_between(receiver.loc.end.begin_pos, node.send_node.source_range.end_pos)
37
37
 
@@ -42,6 +42,8 @@ module RuboCop
42
42
  break
43
43
  end
44
44
  end
45
+
46
+ alias on_numblock on_block
45
47
  end
46
48
  end
47
49
  end
@@ -49,7 +49,7 @@ module RuboCop
49
49
 
50
50
  # Requires `then` for write `in` and its body on the same line.
51
51
  def require_then?(in_pattern_node)
52
- return true if in_pattern_node.pattern.first_line != in_pattern_node.pattern.last_line
52
+ return true unless in_pattern_node.pattern.single_line?
53
53
  return false unless in_pattern_node.body
54
54
 
55
55
  same_line?(in_pattern_node, in_pattern_node.body)
@@ -49,7 +49,8 @@ module RuboCop
49
49
  def on_if(node)
50
50
  return unless if_else?(node)
51
51
 
52
- condition = node.condition
52
+ condition = unwrap_begin_nodes(node.condition)
53
+
53
54
  return if double_negation?(condition) || !negated_condition?(condition)
54
55
 
55
56
  type = node.ternary? ? 'ternary' : 'if-else'
@@ -71,6 +72,11 @@ module RuboCop
71
72
  !node.elsif? && else_branch && (!else_branch.if_type? || !else_branch.elsif?)
72
73
  end
73
74
 
75
+ def unwrap_begin_nodes(node)
76
+ node = node.children.first while node.begin_type? || node.kwbegin_type?
77
+ node
78
+ end
79
+
74
80
  def negated_condition?(node)
75
81
  node.send_type? &&
76
82
  (node.negation_method? || NEGATED_EQUALITY_METHODS.include?(node.method_name))
@@ -71,6 +71,8 @@ module RuboCop
71
71
  check(node)
72
72
  end
73
73
 
74
+ alias on_numblock on_block
75
+
74
76
  def on_while(node)
75
77
  check(node)
76
78
  end
@@ -223,11 +225,7 @@ module RuboCop
223
225
  adjustment = delta + @reindented_lines[lineno]
224
226
  @reindented_lines[lineno] = adjustment
225
227
 
226
- if adjustment.positive?
227
- corrector.remove_leading(buffer.line_range(lineno), adjustment)
228
- elsif adjustment.negative?
229
- corrector.insert_before(buffer.line_range(lineno), ' ' * -adjustment)
230
- end
228
+ corrector.remove_leading(buffer.line_range(lineno), adjustment) if adjustment.positive?
231
229
  end
232
230
  end
233
231
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
  { ({return next break} nil) (nil) }
44
44
  PATTERN
45
45
 
46
- def on_block(node)
46
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
47
47
  return unless node.lambda? || node.proc?
48
48
  return unless nil_return?(node.body)
49
49
 
@@ -3,9 +3,17 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for big numeric literals without _ between groups
6
+ # Checks for big numeric literals without `_` between groups
7
7
  # of digits in them.
8
8
  #
9
+ # Additional allowed patterns can be added by adding regexps to
10
+ # the `AllowedPatterns` configuration. All regexps are treated
11
+ # as anchored even if the patterns do not contain anchors (so
12
+ # `\d{4}_\d{4}` will allow `1234_5678` but not `1234_5678_9012`).
13
+ #
14
+ # NOTE: Even if `AllowedPatterns` are given, autocorrection will
15
+ # only correct to the standard pattern of an `_` every 3 digits.
16
+ #
9
17
  # @example
10
18
  #
11
19
  # # bad
@@ -34,6 +42,7 @@ module RuboCop
34
42
  #
35
43
  class NumericLiterals < Base
36
44
  include IntegerNode
45
+ include AllowedPattern
37
46
  extend AutoCorrector
38
47
 
39
48
  MSG = 'Use underscores(_) as thousands separator and separate every 3 digits with them.'
@@ -59,6 +68,7 @@ module RuboCop
59
68
  # TODO: handle non-decimal literals as well
60
69
  return if int.start_with?('0')
61
70
  return if allowed_numbers.include?(int)
71
+ return if matches_allowed_pattern?(int)
62
72
  return unless int.size >= min_digits
63
73
 
64
74
  case int
@@ -108,6 +118,11 @@ module RuboCop
108
118
  def allowed_numbers
109
119
  cop_config.fetch('AllowedNumbers', []).map(&:to_s)
110
120
  end
121
+
122
+ def allowed_patterns
123
+ # Convert the patterns to be anchored
124
+ super.map { |regexp| Regexp.new(/\A#{regexp}\z/) }
125
+ end
111
126
  end
112
127
  end
113
128
  end