rubocop 0.92.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -7
  3. data/config/default.yml +169 -59
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop.rb +15 -3
  6. data/lib/rubocop/cached_data.rb +2 -1
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  8. data/lib/rubocop/cli/command/version.rb +1 -1
  9. data/lib/rubocop/comment_config.rb +1 -1
  10. data/lib/rubocop/config.rb +4 -0
  11. data/lib/rubocop/config_loader.rb +19 -2
  12. data/lib/rubocop/config_loader_resolver.rb +7 -5
  13. data/lib/rubocop/config_validator.rb +7 -6
  14. data/lib/rubocop/cop/badge.rb +9 -24
  15. data/lib/rubocop/cop/base.rb +16 -1
  16. data/lib/rubocop/cop/bundler/duplicated_gem.rb +23 -3
  17. data/lib/rubocop/cop/commissioner.rb +36 -22
  18. data/lib/rubocop/cop/corrector.rb +3 -1
  19. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  20. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  21. data/lib/rubocop/cop/force.rb +1 -1
  22. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
  23. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  24. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  25. data/lib/rubocop/cop/layout/dot_position.rb +6 -9
  26. data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
  27. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -7
  28. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  29. data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
  30. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
  31. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
  32. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
  33. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -11
  34. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  35. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
  36. data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
  37. data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
  38. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
  39. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
  40. data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
  41. data/lib/rubocop/cop/lint/debugger.rb +2 -3
  42. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
  43. data/lib/rubocop/cop/lint/else_layout.rb +29 -3
  44. data/lib/rubocop/cop/lint/empty_block.rb +59 -0
  45. data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
  46. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
  47. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +17 -3
  48. data/lib/rubocop/cop/lint/loop.rb +0 -4
  49. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  50. data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
  51. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
  52. data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
  53. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
  54. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  55. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
  56. data/lib/rubocop/cop/lint/to_enum_arguments.rb +95 -0
  57. data/lib/rubocop/cop/lint/to_json.rb +1 -1
  58. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +185 -0
  59. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  60. data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
  61. data/lib/rubocop/cop/metrics/block_length.rb +3 -1
  62. data/lib/rubocop/cop/metrics/class_length.rb +14 -6
  63. data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -1
  64. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
  65. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  66. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  67. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
  68. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
  69. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
  70. data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
  71. data/lib/rubocop/cop/naming/variable_number.rb +82 -8
  72. data/lib/rubocop/cop/offense.rb +18 -5
  73. data/lib/rubocop/cop/security/open.rb +12 -10
  74. data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
  75. data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
  76. data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
  77. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
  78. data/lib/rubocop/cop/style/case_like_if.rb +18 -6
  79. data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
  80. data/lib/rubocop/cop/style/collection_compact.rb +85 -0
  81. data/lib/rubocop/cop/style/combinable_loops.rb +8 -1
  82. data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
  83. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +67 -0
  84. data/lib/rubocop/cop/style/double_negation.rb +6 -1
  85. data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
  86. data/lib/rubocop/cop/style/for.rb +0 -4
  87. data/lib/rubocop/cop/style/format_string_token.rb +48 -3
  88. data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
  89. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
  90. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
  91. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -11
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
  93. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  94. data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
  95. data/lib/rubocop/cop/style/multiple_comparison.rb +54 -7
  96. data/lib/rubocop/cop/style/negated_if_else_condition.rb +99 -0
  97. data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
  98. data/lib/rubocop/cop/style/raise_args.rb +21 -9
  99. data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
  100. data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
  101. data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
  102. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  103. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +45 -24
  104. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
  105. data/lib/rubocop/cop/style/redundant_self.rb +3 -0
  106. data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
  107. data/lib/rubocop/cop/style/semicolon.rb +3 -0
  108. data/lib/rubocop/cop/style/string_concatenation.rb +14 -2
  109. data/lib/rubocop/cop/style/swap_values.rb +108 -0
  110. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  111. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  112. data/lib/rubocop/cop/team.rb +6 -1
  113. data/lib/rubocop/cop/util.rb +5 -1
  114. data/lib/rubocop/cop/variable_force/branch.rb +0 -4
  115. data/lib/rubocop/ext/regexp_node.rb +35 -11
  116. data/lib/rubocop/ext/regexp_parser.rb +84 -0
  117. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  118. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
  119. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  120. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  121. data/lib/rubocop/magic_comment.rb +2 -2
  122. data/lib/rubocop/options.rb +6 -1
  123. data/lib/rubocop/result_cache.rb +8 -2
  124. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  125. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  126. data/lib/rubocop/runner.rb +4 -4
  127. data/lib/rubocop/target_finder.rb +23 -25
  128. data/lib/rubocop/version.rb +56 -6
  129. metadata +22 -8
  130. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop enforces the use of `Object#instance_of?` instead of class comparison
7
+ # for equality.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # var.class == Date
12
+ # var.class.equal?(Date)
13
+ # var.class.eql?(Date)
14
+ # var.class.name == 'Date'
15
+ #
16
+ # # good
17
+ # var.instance_of?(Date)
18
+ #
19
+ class ClassEqualityComparison < Base
20
+ include RangeHelp
21
+ include IgnoredMethods
22
+ extend AutoCorrector
23
+
24
+ MSG = 'Use `instance_of?(%<class_name>s)` instead of comparing classes.'
25
+
26
+ RESTRICT_ON_SEND = %i[== equal? eql?].freeze
27
+
28
+ def_node_matcher :class_comparison_candidate?, <<~PATTERN
29
+ (send
30
+ {$(send _ :class) (send $(send _ :class) :name)}
31
+ {:== :equal? :eql?} $_)
32
+ PATTERN
33
+
34
+ def on_send(node)
35
+ def_node = node.each_ancestor(:def, :defs).first
36
+ return if def_node && ignored_method?(def_node.method_name)
37
+
38
+ class_comparison_candidate?(node) do |receiver_node, class_node|
39
+ range = offense_range(receiver_node, node)
40
+ class_name = class_name(class_node, node)
41
+
42
+ add_offense(range, message: format(MSG, class_name: class_name)) do |corrector|
43
+ corrector.replace(range, "instance_of?(#{class_name})")
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def class_name(class_node, node)
51
+ if node.children.first.method?(:name)
52
+ class_node.source.delete('"').delete("'")
53
+ else
54
+ class_node.source
55
+ end
56
+ end
57
+
58
+ def offense_range(receiver_node, node)
59
+ range_between(receiver_node.loc.selector.begin_pos, node.source_range.end_pos)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for places where custom logic on rejection nils from arrays
7
+ # and hashes can be replaced with `{Array,Hash}#{compact,compact!}`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # array.reject { |e| e.nil? }
12
+ # array.select { |e| !e.nil? }
13
+ #
14
+ # # good
15
+ # array.compact
16
+ #
17
+ # # bad
18
+ # hash.reject! { |k, v| v.nil? }
19
+ # hash.select! { |k, v| !v.nil? }
20
+ #
21
+ # # good
22
+ # hash.compact!
23
+ #
24
+ class CollectionCompact < Base
25
+ include RangeHelp
26
+ extend AutoCorrector
27
+
28
+ MSG = 'Use `%<good>s` instead of `%<bad>s`.'
29
+
30
+ RESTRICT_ON_SEND = %i[reject reject! select select!].freeze
31
+
32
+ def_node_matcher :reject_method?, <<~PATTERN
33
+ (block
34
+ (send
35
+ _ ${:reject :reject!})
36
+ $(args ...)
37
+ (send
38
+ $(lvar _) :nil?))
39
+ PATTERN
40
+
41
+ def_node_matcher :select_method?, <<~PATTERN
42
+ (block
43
+ (send
44
+ _ ${:select :select!})
45
+ $(args ...)
46
+ (send
47
+ (send
48
+ $(lvar _) :nil?) :!))
49
+ PATTERN
50
+
51
+ def on_send(node)
52
+ block_node = node.parent
53
+ return unless block_node&.block_type?
54
+
55
+ return unless (method_name, args, receiver =
56
+ reject_method?(block_node) || select_method?(block_node))
57
+
58
+ return unless args.last.source == receiver.source
59
+
60
+ range = offense_range(node, block_node)
61
+ good = good_method_name(method_name)
62
+ message = format(MSG, good: good, bad: range.source)
63
+
64
+ add_offense(range, message: message) do |corrector|
65
+ corrector.replace(range, good)
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def good_method_name(method_name)
72
+ if method_name.to_s.end_with?('!')
73
+ 'compact!'
74
+ else
75
+ 'compact'
76
+ end
77
+ end
78
+
79
+ def offense_range(send_node, block_node)
80
+ range_between(send_node.loc.selector.begin_pos, block_node.loc.end.end_pos)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -49,6 +49,12 @@ module RuboCop
49
49
  # end
50
50
  # end
51
51
  #
52
+ # # good
53
+ # def method
54
+ # each_slice(2) { |slice| do_something(slice) }
55
+ # each_slice(3) { |slice| do_something(slice) }
56
+ # end
57
+ #
52
58
  class CombinableLoops < Base
53
59
  MSG = 'Combine this loop with the previous loop.'
54
60
 
@@ -76,7 +82,8 @@ module RuboCop
76
82
  def same_collection_looping?(node, sibling)
77
83
  sibling&.block_type? &&
78
84
  sibling.send_node.method?(node.method_name) &&
79
- sibling.send_node.receiver == node.send_node.receiver
85
+ sibling.send_node.receiver == node.send_node.receiver &&
86
+ sibling.send_node.arguments == node.send_node.arguments
80
87
  end
81
88
  end
82
89
  end
@@ -6,6 +6,12 @@ module RuboCop
6
6
  # This cop checks that comment annotation keywords are written according
7
7
  # to guidelines.
8
8
  #
9
+ # NOTE: With a multiline comment block (where each line is only a
10
+ # comment), only the first line will be able to register an offense, even
11
+ # if an annotation keyword starts another line. This is done to prevent
12
+ # incorrect registering of keywords (eg. `review`) inside a paragraph as an
13
+ # annotation.
14
+ #
9
15
  # @example
10
16
  # # bad
11
17
  # # TODO make better
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # When using `class_eval` (or other `eval`) with string interpolation,
7
+ # add a comment block showing its appearance if interpolated (a practice used in Rails code).
8
+ #
9
+ # @example
10
+ # # from activesupport/lib/active_support/core_ext/string/output_safety.rb
11
+ #
12
+ # # bad
13
+ # UNSAFE_STRING_METHODS.each do |unsafe_method|
14
+ # if 'String'.respond_to?(unsafe_method)
15
+ # class_eval <<-EOT, __FILE__, __LINE__ + 1
16
+ # def #{unsafe_method}(*params, &block)
17
+ # to_str.#{unsafe_method}(*params, &block)
18
+ # end
19
+ #
20
+ # def #{unsafe_method}!(*params)
21
+ # @dirty = true
22
+ # super
23
+ # end
24
+ # EOT
25
+ # end
26
+ # end
27
+ #
28
+ # # good
29
+ # UNSAFE_STRING_METHODS.each do |unsafe_method|
30
+ # if 'String'.respond_to?(unsafe_method)
31
+ # class_eval <<-EOT, __FILE__, __LINE__ + 1
32
+ # def #{unsafe_method}(*params, &block) # def capitalize(*params, &block)
33
+ # to_str.#{unsafe_method}(*params, &block) # to_str.capitalize(*params, &block)
34
+ # end # end
35
+ #
36
+ # def #{unsafe_method}!(*params) # def capitalize!(*params)
37
+ # @dirty = true # @dirty = true
38
+ # super # super
39
+ # end # end
40
+ # EOT
41
+ # end
42
+ # end
43
+ #
44
+ class DocumentDynamicEvalDefinition < Base
45
+ MSG = 'Add a comment block showing its appearance if interpolated.'
46
+
47
+ RESTRICT_ON_SEND = %i[eval class_eval module_eval instance_eval].freeze
48
+
49
+ def on_send(node)
50
+ arg_node = node.first_argument
51
+ return unless arg_node&.dstr_type?
52
+
53
+ add_offense(node.loc.selector) unless comment_docs?(arg_node)
54
+ end
55
+
56
+ private
57
+
58
+ def comment_docs?(node)
59
+ node.each_child_node(:begin).all? do |begin_node|
60
+ source_line = processed_source.lines[begin_node.first_line - 1]
61
+ source_line.match?(/\s*#[^{]+/)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -34,6 +34,7 @@ module RuboCop
34
34
  # this is rarely a problem in practice.
35
35
  class DoubleNegation < Base
36
36
  include ConfigurableEnforcedStyle
37
+ extend AutoCorrector
37
38
 
38
39
  MSG = 'Avoid the use of double negation (`!!`).'
39
40
  RESTRICT_ON_SEND = %i[!].freeze
@@ -44,7 +45,11 @@ module RuboCop
44
45
  return unless double_negative?(node) && node.prefix_bang?
45
46
  return if style == :allowed_in_returns && allowed_in_returns?(node)
46
47
 
47
- add_offense(node.loc.selector)
48
+ location = node.loc.selector
49
+ add_offense(location) do |corrector|
50
+ corrector.remove(location)
51
+ corrector.insert_after(node, '.nil?')
52
+ end
48
53
  end
49
54
 
50
55
  private
@@ -57,12 +57,16 @@ module RuboCop
57
57
  yielding_block?(block_node) do |send_node, block_args, yield_args|
58
58
  return unless yielding_arguments?(block_args, yield_args)
59
59
 
60
+ def_node = block_node.each_ancestor(:def, :defs).first
61
+ # if `yield` is being called outside of a method context, ignore
62
+ # this is not a valid ruby pattern, but can happen in haml or erb,
63
+ # so this can cause crashes in haml_lint
64
+ return unless def_node
65
+
60
66
  add_offense(block_node) do |corrector|
61
67
  corrector.remove(block_body_range(block_node, send_node))
62
68
 
63
69
  add_block_argument(send_node, corrector)
64
-
65
- def_node = block_node.each_ancestor(:def, :defs).first
66
70
  add_block_argument(def_node, corrector) if @def_nodes.add?(def_node)
67
71
  end
68
72
  end
@@ -49,8 +49,6 @@ module RuboCop
49
49
 
50
50
  def on_for(node)
51
51
  if style == :each
52
- return unless opposite_style_detected
53
-
54
52
  add_offense(node, message: PREFER_EACH) do |corrector|
55
53
  ForToEachCorrector.new(node).call(corrector)
56
54
  end
@@ -63,8 +61,6 @@ module RuboCop
63
61
  return unless suspect_enumerable?(node)
64
62
 
65
63
  if style == :for
66
- return unless opposite_style_detected
67
-
68
64
  add_offense(node, message: PREFER_FOR) do |corrector|
69
65
  EachToForCorrector.new(node).call(corrector)
70
66
  end
@@ -33,10 +33,31 @@ module RuboCop
33
33
  #
34
34
  # # bad
35
35
  # format('%<greeting>s', greeting: 'Hello')
36
- # format('%{greeting}', 'Hello')
36
+ # format('%{greeting}', greeting: 'Hello')
37
37
  #
38
38
  # # good
39
39
  # format('%s', 'Hello')
40
+ #
41
+ # It is allowed to contain unannotated token
42
+ # if the number of them is less than or equals to
43
+ # `MaxUnannotatedPlaceholdersAllowed`.
44
+ #
45
+ # @example MaxUnannotatedPlaceholdersAllowed: 0
46
+ #
47
+ # # bad
48
+ # format('%06d', 10)
49
+ # format('%s %s.', 'Hello', 'world')
50
+ #
51
+ # # good
52
+ # format('%<number>06d', number: 10)
53
+ #
54
+ # @example MaxUnannotatedPlaceholdersAllowed: 1 (default)
55
+ #
56
+ # # bad
57
+ # format('%s %s.', 'Hello', 'world')
58
+ #
59
+ # # good
60
+ # format('%06d', 10)
40
61
  class FormatStringToken < Base
41
62
  include ConfigurableEnforcedStyle
42
63
 
@@ -44,8 +65,12 @@ module RuboCop
44
65
  return unless node.value.include?('%')
45
66
  return if node.each_ancestor(:xstr, :regexp).any?
46
67
 
47
- tokens(node) do |detected_style, token_range|
48
- if detected_style == style || unannotated_format?(node, detected_style)
68
+ detections = collect_detections(node)
69
+ return if detections.empty?
70
+ return if allowed_unannotated?(detections)
71
+
72
+ detections.each do |detected_style, token_range|
73
+ if detected_style == style
49
74
  correct_style_detected
50
75
  else
51
76
  style_detected(detected_style)
@@ -112,6 +137,26 @@ module RuboCop
112
137
  yield(detected_style, token)
113
138
  end
114
139
  end
140
+
141
+ def collect_detections(node)
142
+ detections = []
143
+ tokens(node) do |detected_style, token_range|
144
+ unless unannotated_format?(node, detected_style)
145
+ detections << [detected_style, token_range]
146
+ end
147
+ end
148
+ detections
149
+ end
150
+
151
+ def allowed_unannotated?(detections)
152
+ return false if detections.size > max_unannotated_placeholders_allowed
153
+
154
+ detections.all? { |detected_style,| detected_style == :unannotated }
155
+ end
156
+
157
+ def max_unannotated_placeholders_allowed
158
+ cop_config['MaxUnannotatedPlaceholdersAllowed']
159
+ end
115
160
  end
116
161
  end
117
162
  end
@@ -97,10 +97,10 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def no_mixed_keys_check(pairs)
100
- if !sym_indices?(pairs)
101
- check(pairs, ':', MSG_NO_MIXED_KEYS)
102
- else
100
+ if sym_indices?(pairs)
103
101
  check(pairs, pairs.first.inverse_delimiter, MSG_NO_MIXED_KEYS)
102
+ else
103
+ check(pairs, ':', MSG_NO_MIXED_KEYS)
104
104
  end
105
105
  end
106
106
 
@@ -34,6 +34,10 @@ module RuboCop
34
34
  add_offense(node) do |corrector|
35
35
  if node.parent.find(&:kwoptarg_type?) == node
36
36
  corrector.insert_before(node, "#{kwarg_nodes.map(&:source).join(', ')}, ")
37
+
38
+ arguments = node.each_ancestor(:def, :defs).first.arguments
39
+ append_newline_to_last_kwoptarg(arguments, corrector) unless parentheses?(arguments)
40
+
37
41
  remove_kwargs(kwarg_nodes, corrector)
38
42
  end
39
43
  end
@@ -41,6 +45,14 @@ module RuboCop
41
45
 
42
46
  private
43
47
 
48
+ def append_newline_to_last_kwoptarg(arguments, corrector)
49
+ last_argument = arguments.last
50
+ return if last_argument.kwrestarg_type? || last_argument.blockarg_type?
51
+
52
+ last_kwoptarg = arguments.reverse.find(&:kwoptarg_type?)
53
+ corrector.insert_after(last_kwoptarg, "\n")
54
+ end
55
+
44
56
  def remove_kwargs(kwarg_nodes, corrector)
45
57
  kwarg_nodes.each do |kwarg|
46
58
  with_space = range_with_surrounding_space(range: kwarg.source_range)
@@ -144,25 +144,22 @@ module RuboCop
144
144
  # # good
145
145
  # Array 1
146
146
  class MethodCallWithArgsParentheses < Base
147
+ require_relative 'method_call_with_args_parentheses/omit_parentheses'
148
+ require_relative 'method_call_with_args_parentheses/require_parentheses'
149
+
147
150
  include ConfigurableEnforcedStyle
148
151
  include IgnoredMethods
149
152
  include IgnoredPattern
153
+ include RequireParentheses
154
+ include OmitParentheses
150
155
  extend AutoCorrector
151
156
 
152
- def initialize(*)
153
- super
154
- return unless style_configured?
155
-
156
- case style
157
- when :require_parentheses
158
- extend RequireParentheses
159
- when :omit_parentheses
160
- extend OmitParentheses
161
- end
157
+ def on_send(node)
158
+ send(style, node) # call require_parentheses or omit_parentheses
162
159
  end
163
-
164
- # @abstract Overridden in style modules
165
- def autocorrect(_node); end
160
+ alias on_csend on_send
161
+ alias on_super on_send
162
+ alias on_yield on_send
166
163
 
167
164
  private
168
165