rubocop 0.93.1 → 1.6.1

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 (199) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -16
  3. data/config/default.yml +276 -82
  4. data/config/obsoletion.yml +196 -0
  5. data/exe/rubocop +1 -1
  6. data/lib/rubocop.rb +31 -2
  7. data/lib/rubocop/cli.rb +5 -1
  8. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  9. data/lib/rubocop/cli/command/execute_runner.rb +26 -11
  10. data/lib/rubocop/cli/command/suggest_extensions.rb +80 -0
  11. data/lib/rubocop/cli/command/version.rb +1 -1
  12. data/lib/rubocop/comment_config.rb +1 -1
  13. data/lib/rubocop/config.rb +4 -0
  14. data/lib/rubocop/config_loader.rb +34 -8
  15. data/lib/rubocop/config_loader_resolver.rb +12 -6
  16. data/lib/rubocop/config_obsoletion.rb +65 -247
  17. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  18. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  19. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  20. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  21. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  22. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  23. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  24. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  25. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  26. data/lib/rubocop/config_regeneration.rb +1 -1
  27. data/lib/rubocop/config_validator.rb +25 -10
  28. data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
  29. data/lib/rubocop/cop/badge.rb +9 -24
  30. data/lib/rubocop/cop/base.rb +33 -16
  31. data/lib/rubocop/cop/bundler/duplicated_gem.rb +26 -6
  32. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  33. data/lib/rubocop/cop/commissioner.rb +37 -23
  34. data/lib/rubocop/cop/cop.rb +2 -2
  35. data/lib/rubocop/cop/corrector.rb +3 -1
  36. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  37. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  38. data/lib/rubocop/cop/force.rb +1 -1
  39. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -3
  40. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +4 -5
  41. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  42. data/lib/rubocop/cop/generator.rb +3 -10
  43. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  44. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +1 -1
  45. data/lib/rubocop/cop/layout/block_alignment.rb +3 -4
  46. data/lib/rubocop/cop/layout/class_structure.rb +22 -3
  47. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  48. data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
  49. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +80 -10
  50. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  51. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  52. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  53. data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
  54. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  55. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
  56. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  57. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
  58. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +12 -0
  59. data/lib/rubocop/cop/layout/line_length.rb +10 -13
  60. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  61. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
  62. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  63. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  64. data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
  65. data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
  66. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
  67. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +26 -2
  68. data/lib/rubocop/cop/lint/debugger.rb +17 -28
  69. data/lib/rubocop/cop/lint/duplicate_branch.rb +93 -0
  70. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +2 -12
  71. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
  72. data/lib/rubocop/cop/lint/else_layout.rb +29 -3
  73. data/lib/rubocop/cop/lint/empty_block.rb +82 -0
  74. data/lib/rubocop/cop/lint/empty_class.rb +93 -0
  75. data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
  76. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  77. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +39 -7
  78. data/lib/rubocop/cop/lint/loop.rb +4 -4
  79. data/lib/rubocop/cop/lint/missing_super.rb +7 -4
  80. data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
  81. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
  82. data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
  83. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
  84. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +19 -16
  85. data/lib/rubocop/cop/lint/shadowed_exception.rb +4 -5
  86. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  87. data/lib/rubocop/cop/lint/to_enum_arguments.rb +86 -0
  88. data/lib/rubocop/cop/lint/to_json.rb +1 -1
  89. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  90. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +199 -0
  91. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  92. data/lib/rubocop/cop/lint/useless_method_definition.rb +2 -4
  93. data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
  94. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  95. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  96. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  97. data/lib/rubocop/cop/metrics/parameter_lists.rb +68 -2
  98. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  99. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  100. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  101. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  102. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  103. data/lib/rubocop/cop/mixin/configurable_numbering.rb +4 -3
  104. data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
  105. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  106. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  107. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  108. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  109. data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -4
  110. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  111. data/lib/rubocop/cop/mixin/visibility_help.rb +1 -3
  112. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  113. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
  114. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
  115. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
  116. data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
  117. data/lib/rubocop/cop/naming/variable_number.rb +100 -8
  118. data/lib/rubocop/cop/offense.rb +3 -3
  119. data/lib/rubocop/cop/security/open.rb +12 -10
  120. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  121. data/lib/rubocop/cop/style/and_or.rb +11 -3
  122. data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
  123. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
  124. data/lib/rubocop/cop/style/case_like_if.rb +0 -4
  125. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  126. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  127. data/lib/rubocop/cop/style/collection_compact.rb +91 -0
  128. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +169 -0
  129. data/lib/rubocop/cop/style/documentation.rb +12 -1
  130. data/lib/rubocop/cop/style/double_negation.rb +6 -1
  131. data/lib/rubocop/cop/style/float_division.rb +44 -1
  132. data/lib/rubocop/cop/style/format_string.rb +8 -3
  133. data/lib/rubocop/cop/style/format_string_token.rb +47 -2
  134. data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
  135. data/lib/rubocop/cop/style/identical_conditional_branches.rb +7 -2
  136. data/lib/rubocop/cop/style/if_inside_else.rb +37 -1
  137. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -3
  138. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  139. data/lib/rubocop/cop/style/infinite_loop.rb +4 -0
  140. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  141. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
  142. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
  143. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +8 -13
  144. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
  145. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  146. data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
  147. data/lib/rubocop/cop/style/multiple_comparison.rb +55 -7
  148. data/lib/rubocop/cop/style/negated_if_else_condition.rb +106 -0
  149. data/lib/rubocop/cop/style/nil_lambda.rb +52 -0
  150. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  151. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  152. data/lib/rubocop/cop/style/raise_args.rb +21 -6
  153. data/lib/rubocop/cop/style/redundant_argument.rb +88 -0
  154. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  155. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  156. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -1
  157. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  158. data/lib/rubocop/cop/style/redundant_self.rb +3 -0
  159. data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
  160. data/lib/rubocop/cop/style/semicolon.rb +3 -0
  161. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  162. data/lib/rubocop/cop/style/sole_nested_conditional.rb +65 -3
  163. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  164. data/lib/rubocop/cop/style/static_class.rb +97 -0
  165. data/lib/rubocop/cop/style/string_concatenation.rb +39 -2
  166. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  167. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  168. data/lib/rubocop/cop/style/swap_values.rb +108 -0
  169. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  170. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  171. data/lib/rubocop/cop/style/while_until_modifier.rb +9 -0
  172. data/lib/rubocop/cop/team.rb +6 -1
  173. data/lib/rubocop/cop/util.rb +6 -2
  174. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  175. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  176. data/lib/rubocop/core_ext/hash.rb +20 -0
  177. data/lib/rubocop/ext/regexp_node.rb +36 -11
  178. data/lib/rubocop/ext/regexp_parser.rb +95 -0
  179. data/lib/rubocop/formatter/disabled_config_formatter.rb +21 -6
  180. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  181. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  182. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
  183. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  184. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  185. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  186. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  187. data/lib/rubocop/lockfile.rb +40 -0
  188. data/lib/rubocop/magic_comment.rb +2 -2
  189. data/lib/rubocop/options.rb +11 -1
  190. data/lib/rubocop/rake_task.rb +2 -2
  191. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  192. data/lib/rubocop/runner.rb +1 -1
  193. data/lib/rubocop/target_finder.rb +1 -1
  194. data/lib/rubocop/target_ruby.rb +65 -1
  195. data/lib/rubocop/version.rb +56 -6
  196. metadata +50 -9
  197. data/bin/console +0 -10
  198. data/bin/rubocop-profile +0 -32
  199. data/bin/setup +0 -7
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for uses of `if-else` and ternary operators with a negated condition
7
+ # which can be simplified by inverting condition and swapping branches.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # if !x
12
+ # do_something
13
+ # else
14
+ # do_something_else
15
+ # end
16
+ #
17
+ # # good
18
+ # if x
19
+ # do_something_else
20
+ # else
21
+ # do_something
22
+ # end
23
+ #
24
+ # # bad
25
+ # !x ? do_something : do_something_else
26
+ #
27
+ # # good
28
+ # x ? do_something_else : do_something
29
+ #
30
+ class NegatedIfElseCondition < Base
31
+ include RangeHelp
32
+ extend AutoCorrector
33
+
34
+ MSG = 'Invert the negated condition and swap the %<type>s branches.'
35
+
36
+ NEGATED_EQUALITY_METHODS = %i[!= !~].freeze
37
+
38
+ def_node_matcher :double_negation?, '(send (send _ :!) :!)'
39
+
40
+ def self.autocorrect_incompatible_with
41
+ [Style::InverseMethods, Style::Not]
42
+ end
43
+
44
+ def on_new_investigation
45
+ @corrected_nodes = nil
46
+ end
47
+
48
+ def on_if(node)
49
+ return unless if_else?(node)
50
+
51
+ condition = node.condition
52
+ return if double_negation?(condition) || !negated_condition?(condition)
53
+
54
+ type = node.ternary? ? 'ternary' : 'if-else'
55
+ add_offense(node, message: format(MSG, type: type)) do |corrector|
56
+ unless corrected_ancestor?(node)
57
+ correct_negated_condition(corrector, condition)
58
+ swap_branches(corrector, node)
59
+
60
+ @corrected_nodes ||= Set.new.compare_by_identity
61
+ @corrected_nodes.add(node)
62
+ end
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def if_else?(node)
69
+ else_branch = node.else_branch
70
+ !node.elsif? && else_branch && (!else_branch.if_type? || !else_branch.elsif?)
71
+ end
72
+
73
+ def negated_condition?(node)
74
+ node.send_type? &&
75
+ (node.negation_method? || NEGATED_EQUALITY_METHODS.include?(node.method_name))
76
+ end
77
+
78
+ def corrected_ancestor?(node)
79
+ node.each_ancestor(:if).any? { |ancestor| @corrected_nodes&.include?(ancestor) }
80
+ end
81
+
82
+ def correct_negated_condition(corrector, node)
83
+ receiver, method_name, rhs = *node
84
+ replacement =
85
+ if node.negation_method?
86
+ receiver.source
87
+ else
88
+ inverted_method = method_name.to_s.sub('!', '=')
89
+ "#{receiver.source} #{inverted_method} #{rhs.source}"
90
+ end
91
+
92
+ corrector.replace(node, replacement)
93
+ end
94
+
95
+ def swap_branches(corrector, node)
96
+ if node.if_branch.nil?
97
+ corrector.remove(range_by_whole_lines(node.loc.else, include_final_newline: true))
98
+ else
99
+ corrector.replace(node.if_branch, node.else_branch.source)
100
+ corrector.replace(node.else_branch, node.if_branch.source)
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for lambdas that always return nil, which can be replaced
7
+ # with an empty lambda instead.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # -> { nil }
12
+ #
13
+ # lambda do
14
+ # next nil
15
+ # end
16
+ #
17
+ # # good
18
+ # -> {}
19
+ #
20
+ # lambda do
21
+ # end
22
+ #
23
+ # -> (x) { nil if x }
24
+ #
25
+ class NilLambda < Base
26
+ extend AutoCorrector
27
+ include RangeHelp
28
+
29
+ MSG = 'Use an empty lambda instead of always returning nil.'
30
+
31
+ def_node_matcher :nil_return?, <<~PATTERN
32
+ { ({return next break} nil) (nil) }
33
+ PATTERN
34
+
35
+ def on_block(node)
36
+ return unless node.lambda?
37
+ return unless nil_return?(node.body)
38
+
39
+ add_offense(node) do |corrector|
40
+ range = if node.single_line?
41
+ range_with_surrounding_space(range: node.body.loc.expression)
42
+ else
43
+ range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
44
+ end
45
+
46
+ corrector.remove(range)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -27,12 +27,13 @@ module RuboCop
27
27
  # # bad
28
28
  # 10_000_00 # typical representation of $10,000 in cents
29
29
  #
30
- class NumericLiterals < Cop
30
+ class NumericLiterals < Base
31
31
  # The parameter is called MinDigits (meaning the minimum number of
32
32
  # digits for which an offense can be registered), but essentially it's
33
33
  # a Max parameter (the maximum number of something that's allowed).
34
34
  include ConfigurableMax
35
35
  include IntegerNode
36
+ extend AutoCorrector
36
37
 
37
38
  MSG = 'Use underscores(_) as thousands separator and ' \
38
39
  'separate every 3 digits with them.'
@@ -46,12 +47,6 @@ module RuboCop
46
47
  check(node)
47
48
  end
48
49
 
49
- def autocorrect(node)
50
- lambda do |corrector|
51
- corrector.replace(node, format_number(node))
52
- end
53
- end
54
-
55
50
  private
56
51
 
57
52
  def max_parameter_name
@@ -67,11 +62,19 @@ module RuboCop
67
62
 
68
63
  case int
69
64
  when /^\d+$/
70
- add_offense(node) { self.max = int.size + 1 }
65
+ return unless (self.max = int.size + 1)
66
+
67
+ register_offense(node)
71
68
  when /\d{4}/, short_group_regex
72
- add_offense(node) do
73
- self.config_to_allow_offenses = { 'Enabled' => false }
74
- end
69
+ return unless (self.config_to_allow_offenses = { 'Enabled' => false })
70
+
71
+ register_offense(node)
72
+ end
73
+ end
74
+
75
+ def register_offense(node)
76
+ add_offense(node) do |corrector|
77
+ corrector.replace(node, format_number(node))
75
78
  end
76
79
  end
77
80
 
@@ -4,7 +4,8 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # This cop looks for uses of Perl-style regexp match
7
- # backreferences like $1, $2, etc.
7
+ # backreferences and their English versions like
8
+ # $1, $2, $&, &+, $MATCH, $PREMATCH, etc.
8
9
  #
9
10
  # @example
10
11
  # # bad
@@ -15,19 +16,95 @@ module RuboCop
15
16
  class PerlBackrefs < Base
16
17
  extend AutoCorrector
17
18
 
18
- MSG = 'Avoid the use of Perl-style backrefs.'
19
+ MESSAGE_FORMAT = 'Prefer `%<preferred_expression>s` over `%<original_expression>s`.'
20
+
21
+ def on_back_ref(node)
22
+ on_back_ref_or_gvar_or_nth_ref(node)
23
+ end
24
+
25
+ def on_gvar(node)
26
+ on_back_ref_or_gvar_or_nth_ref(node)
27
+ end
19
28
 
20
29
  def on_nth_ref(node)
21
- add_offense(node) do |corrector|
22
- backref, = *node
23
- parent_type = node.parent ? node.parent.type : nil
30
+ on_back_ref_or_gvar_or_nth_ref(node)
31
+ end
24
32
 
25
- if %i[dstr xstr regexp].include?(parent_type)
26
- corrector.replace(node, "{Regexp.last_match(#{backref})}")
33
+ private
34
+
35
+ # @private
36
+ # @param [RuboCop::AST::Node] node
37
+ # @return [Boolean]
38
+ def derived_from_braceless_interpolation?(node)
39
+ %i[
40
+ dstr
41
+ regexp
42
+ xstr
43
+ ].include?(node.parent&.type)
44
+ end
45
+
46
+ # @private
47
+ # @param [RuboCop::AST::Node] node
48
+ # @param [String] preferred_expression
49
+ # @return [String]
50
+ def format_message(node:, preferred_expression:)
51
+ original_expression = original_expression_of(node)
52
+ format(
53
+ MESSAGE_FORMAT,
54
+ original_expression: original_expression,
55
+ preferred_expression: preferred_expression
56
+ )
57
+ end
27
58
 
28
- else
29
- corrector.replace(node, "Regexp.last_match(#{backref})")
59
+ # @private
60
+ # @param [RuboCop::AST::Node] node
61
+ # @return [String]
62
+ def original_expression_of(node)
63
+ first = node.to_a.first
64
+ if first.is_a?(::Integer)
65
+ "$#{first}"
66
+ else
67
+ first.to_s
68
+ end
69
+ end
70
+
71
+ # @private
72
+ # @param [RuboCop::AST::Node] node
73
+ # @return [String, nil]
74
+ def preferred_expression_to(node)
75
+ first = node.to_a.first
76
+ case first
77
+ when ::Integer
78
+ "Regexp.last_match(#{first})"
79
+ when :$&, :$MATCH
80
+ 'Regexp.last_match(0)'
81
+ when :$`, :$PREMATCH
82
+ 'Regexp.last_match.pre_match'
83
+ when :$', :$POSTMATCH
84
+ 'Regexp.last_match.post_match'
85
+ when :$+, :$LAST_PAREN_MATCH
86
+ 'Regexp.last_match(-1)'
87
+ end
88
+ end
89
+
90
+ # @private
91
+ # @param [RuboCop::AST::Node] node
92
+ def on_back_ref_or_gvar_or_nth_ref(node)
93
+ preferred_expression = preferred_expression_to(node)
94
+ return unless preferred_expression
95
+
96
+ add_offense(
97
+ node,
98
+ message: format_message(
99
+ node: node,
100
+ preferred_expression: preferred_expression
101
+ )
102
+ ) do |corrector|
103
+ if derived_from_braceless_interpolation?(node)
104
+ preferred_expression = "{#{preferred_expression}}"
30
105
  end
106
+
107
+ corrector.replace(node, preferred_expression)
31
108
  end
32
109
  end
33
110
  end
@@ -13,25 +13,32 @@ module RuboCop
13
13
  # will also suggest constructing error objects when the exception is
14
14
  # passed multiple arguments.
15
15
  #
16
+ # The exploded style has an `AllowedCompactTypes` configuration
17
+ # option that takes an Array of exception name Strings.
18
+ #
16
19
  # @example EnforcedStyle: exploded (default)
17
20
  # # bad
18
- # raise StandardError.new("message")
21
+ # raise StandardError.new('message')
19
22
  #
20
23
  # # good
21
- # raise StandardError, "message"
22
- # fail "message"
24
+ # raise StandardError, 'message'
25
+ # fail 'message'
23
26
  # raise MyCustomError.new(arg1, arg2, arg3)
24
27
  # raise MyKwArgError.new(key1: val1, key2: val2)
25
28
  #
29
+ # # With `AllowedCompactTypes` set to ['MyWrappedError']
30
+ # raise MyWrappedError.new(obj)
31
+ # raise MyWrappedError.new(obj), 'message'
32
+ #
26
33
  # @example EnforcedStyle: compact
27
34
  # # bad
28
- # raise StandardError, "message"
35
+ # raise StandardError, 'message'
29
36
  # raise RuntimeError, arg1, arg2, arg3
30
37
  #
31
38
  # # good
32
- # raise StandardError.new("message")
39
+ # raise StandardError.new('message')
33
40
  # raise MyCustomError.new(arg1, arg2, arg3)
34
- # fail "message"
41
+ # fail 'message'
35
42
  class RaiseArgs < Base
36
43
  include ConfigurableEnforcedStyle
37
44
  extend AutoCorrector
@@ -102,6 +109,8 @@ module RuboCop
102
109
  return unless first_arg.send_type? && first_arg.method?(:new)
103
110
  return if acceptable_exploded_args?(first_arg.arguments)
104
111
 
112
+ return if allowed_non_exploded_type?(first_arg)
113
+
105
114
  add_offense(node, message: format(EXPLODED_MSG, method: node.method_name)) do |corrector|
106
115
  replacement = correction_compact_to_exploded(node)
107
116
 
@@ -123,6 +132,12 @@ module RuboCop
123
132
  arg.hash_type? || arg.splat_type?
124
133
  end
125
134
 
135
+ def allowed_non_exploded_type?(arg)
136
+ type = arg.receiver.const_name
137
+
138
+ Array(cop_config['AllowedCompactTypes']).include?(type)
139
+ end
140
+
126
141
  def requires_parens?(parent)
127
142
  parent.and_type? || parent.or_type? ||
128
143
  parent.if_type? && parent.ternary?
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parser/current'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Style
8
+ # This cop checks for a redundant argument passed to certain methods.
9
+ #
10
+ # Limitations:
11
+ #
12
+ # 1. This cop matches for method names only and hence cannot tell apart
13
+ # methods with same name in different classes.
14
+ # 2. This cop is limited to methods with single parameter.
15
+ # 3. This cop is unsafe if certain special global variables (e.g. `$;`) are set.
16
+ # That depends on the nature of the target methods, of course.
17
+ #
18
+ # Method names and their redundant arguments can be configured like this:
19
+ #
20
+ # Methods:
21
+ # join: ''
22
+ # split: ' '
23
+ # foo: 2
24
+ #
25
+ # @example
26
+ # # bad
27
+ # array.join('')
28
+ # [1, 2, 3].join("")
29
+ # string.split(" ")
30
+ # "first\nsecond".split(" ")
31
+ # A.foo(2)
32
+ #
33
+ # # good
34
+ # array.join
35
+ # [1, 2, 3].join
36
+ # string.split
37
+ # "first second".split
38
+ # A.foo
39
+ class RedundantArgument < Base
40
+ include RangeHelp
41
+ extend AutoCorrector
42
+
43
+ MSG = 'Argument %<arg>s is redundant because it is implied by default.'
44
+
45
+ def on_send(node)
46
+ return if node.receiver.nil?
47
+ return if node.arguments.count != 1
48
+ return unless redundant_argument?(node)
49
+
50
+ add_offense(node, message: format(MSG, arg: node.arguments.first.source)) do |corrector|
51
+ corrector.remove(argument_range(node))
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def redundant_argument?(node)
58
+ redundant_argument = redundant_arg_for_method(node.method_name.to_s)
59
+ return false if redundant_argument.nil?
60
+
61
+ node.arguments.first == redundant_argument
62
+ end
63
+
64
+ def redundant_arg_for_method(method_name)
65
+ return nil unless cop_config['Methods'].key?(method_name)
66
+
67
+ @mem ||= {}
68
+ @mem[method_name] ||=
69
+ begin
70
+ arg = cop_config['Methods'].fetch(method_name)
71
+ buffer = Parser::Source::Buffer.new('(string)', 1)
72
+ buffer.source = arg.inspect
73
+ builder = RuboCop::AST::Builder.new
74
+ Parser::CurrentRuby.new(builder).parse(buffer)
75
+ end
76
+ end
77
+
78
+ def argument_range(node)
79
+ if node.parenthesized?
80
+ range_between(node.loc.begin.begin_pos, node.loc.end.end_pos)
81
+ else
82
+ range_with_surrounding_space(range: node.first_argument.source_range, newlines: false)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end