rubocop 1.5.2 → 1.8.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -2
  4. data/config/default.yml +112 -16
  5. data/config/obsoletion.yml +196 -0
  6. data/lib/rubocop.rb +20 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +16 -44
  8. data/lib/rubocop/comment_config.rb +6 -6
  9. data/lib/rubocop/config.rb +8 -5
  10. data/lib/rubocop/config_loader.rb +11 -7
  11. data/lib/rubocop/config_loader_resolver.rb +21 -4
  12. data/lib/rubocop/config_obsoletion.rb +64 -262
  13. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  14. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  15. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  16. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  17. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  18. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  20. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  21. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  22. data/lib/rubocop/config_validator.rb +11 -4
  23. data/lib/rubocop/cop/base.rb +17 -15
  24. data/lib/rubocop/cop/cop.rb +2 -2
  25. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  26. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  27. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  28. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  29. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
  30. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  31. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  33. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  34. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  35. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  36. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  37. data/lib/rubocop/cop/layout/space_before_brackets.rb +62 -0
  38. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  39. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  40. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  41. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  42. data/lib/rubocop/cop/lint/deprecated_constants.rb +75 -0
  43. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  44. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  45. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  46. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  47. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  48. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  49. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  50. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  51. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  52. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  53. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  54. data/lib/rubocop/cop/mixin/comments_help.rb +1 -10
  55. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  56. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  57. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  58. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  59. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  60. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  61. data/lib/rubocop/cop/naming/variable_number.rb +1 -8
  62. data/lib/rubocop/cop/registry.rb +10 -0
  63. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  64. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  65. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  66. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  67. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  68. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  69. data/lib/rubocop/cop/style/explicit_block_argument.rb +10 -0
  70. data/lib/rubocop/cop/style/float_division.rb +44 -1
  71. data/lib/rubocop/cop/style/for.rb +2 -0
  72. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  73. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  74. data/lib/rubocop/cop/style/if_inside_else.rb +8 -3
  75. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  76. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  77. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  78. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  79. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
  80. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  81. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  82. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  83. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  84. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  85. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  86. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  87. data/lib/rubocop/cop/style/raise_args.rb +5 -2
  88. data/lib/rubocop/cop/style/redundant_argument.rb +21 -2
  89. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  90. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  91. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  92. data/lib/rubocop/cop/style/single_line_methods.rb +34 -2
  93. data/lib/rubocop/cop/style/sole_nested_conditional.rb +15 -9
  94. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  95. data/lib/rubocop/cop/style/string_concatenation.rb +20 -1
  96. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  97. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  98. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  99. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  100. data/lib/rubocop/cop/util.rb +3 -1
  101. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  102. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  103. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  104. data/lib/rubocop/lockfile.rb +40 -0
  105. data/lib/rubocop/options.rb +9 -9
  106. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  107. data/lib/rubocop/rspec/expect_offense.rb +34 -22
  108. data/lib/rubocop/runner.rb +16 -1
  109. data/lib/rubocop/target_finder.rb +4 -2
  110. data/lib/rubocop/target_ruby.rb +47 -11
  111. data/lib/rubocop/util.rb +16 -0
  112. data/lib/rubocop/version.rb +8 -2
  113. metadata +28 -7
@@ -66,7 +66,7 @@ module RuboCop
66
66
  end
67
67
 
68
68
  def correct_with_arguments(return_node, corrector)
69
- if return_node.arguments.size > 1
69
+ if return_node.children.size > 1
70
70
  add_brackets(corrector, return_node)
71
71
  elsif hash_without_braces?(return_node.first_argument)
72
72
  add_braces(corrector, return_node.first_argument)
@@ -29,6 +29,8 @@ module RuboCop
29
29
  # c + d
30
30
  # end
31
31
  class SingleLineBlockParams < Base
32
+ extend AutoCorrector
33
+
32
34
  MSG = 'Name `%<method>s` block params `|%<params>s|`.'
33
35
 
34
36
  def on_block(node)
@@ -37,20 +39,41 @@ module RuboCop
37
39
  return unless eligible_method?(node)
38
40
  return unless eligible_arguments?(node)
39
41
 
40
- return if args_match?(node.send_node.method_name, node.arguments)
42
+ method_name = node.send_node.method_name
43
+ return if args_match?(method_name, node.arguments)
44
+
45
+ preferred_block_arguments = build_preferred_arguments_map(node, target_args(method_name))
46
+ joined_block_arguments = preferred_block_arguments.values.join(', ')
41
47
 
42
- message = message(node.arguments)
48
+ message = format(MSG, method: method_name, params: joined_block_arguments)
43
49
 
44
- add_offense(node.arguments, message: message)
50
+ add_offense(node.arguments, message: message) do |corrector|
51
+ autocorrect(corrector, node, preferred_block_arguments, joined_block_arguments)
52
+ end
45
53
  end
46
54
 
47
55
  private
48
56
 
49
- def message(node)
50
- method_name = node.parent.send_node.method_name
51
- arguments = target_args(method_name).join(', ')
57
+ def build_preferred_arguments_map(node, preferred_arguments)
58
+ preferred_arguments_map = {}
59
+ node.arguments.each_with_index do |current_lvar, index|
60
+ preferred_argument = preferred_arguments[index]
61
+ current_argument = current_lvar.source
62
+ preferred_argument = "_#{preferred_argument}" if current_argument.start_with?('_')
63
+ preferred_arguments_map[current_argument] = preferred_argument
64
+ end
65
+
66
+ preferred_arguments_map
67
+ end
68
+
69
+ def autocorrect(corrector, node, preferred_block_arguments, joined_block_arguments)
70
+ corrector.replace(node.arguments, "|#{joined_block_arguments}|")
52
71
 
53
- format(MSG, method: method_name, params: arguments)
72
+ node.each_descendant(:lvar) do |lvar|
73
+ if (preferred_lvar = preferred_block_arguments[lvar.source])
74
+ corrector.replace(lvar, preferred_lvar)
75
+ end
76
+ end
54
77
  end
55
78
 
56
79
  def eligible_arguments?(node)
@@ -6,6 +6,12 @@ module RuboCop
6
6
  # This cop checks for single-line method definitions that contain a body.
7
7
  # It will accept single-line methods with no body.
8
8
  #
9
+ # Endless methods added in Ruby 3.0 are also accepted by this cop.
10
+ #
11
+ # If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow` or
12
+ # `allow_always`, single-line methods will be auto-corrected to endless
13
+ # methods if there is only one statement in the body.
14
+ #
9
15
  # @example
10
16
  # # bad
11
17
  # def some_method; body end
@@ -15,6 +21,7 @@ module RuboCop
15
21
  # # good
16
22
  # def self.resource_class=(klass); end
17
23
  # def @table.columns; end
24
+ # def some_method() = body
18
25
  #
19
26
  # @example AllowIfMethodIsEmpty: true (default)
20
27
  # # good
@@ -32,6 +39,7 @@ module RuboCop
32
39
 
33
40
  def on_def(node)
34
41
  return unless node.single_line?
42
+ return if node.endless?
35
43
  return if allow_empty? && !node.body
36
44
 
37
45
  add_offense(node) do |corrector|
@@ -43,6 +51,28 @@ module RuboCop
43
51
  private
44
52
 
45
53
  def autocorrect(corrector, node)
54
+ if correct_to_endless?(node.body)
55
+ correct_to_endless(corrector, node)
56
+ else
57
+ correct_to_multiline(corrector, node)
58
+ end
59
+ end
60
+
61
+ def allow_empty?
62
+ cop_config['AllowIfMethodIsEmpty']
63
+ end
64
+
65
+ def correct_to_endless?(body_node)
66
+ endless_method_config = config.for_cop('Style/EndlessMethod')
67
+
68
+ return false unless endless_method_config['Enabled']
69
+ return false if endless_method_config['EnforcedStyle'] == 'disallow'
70
+ return false unless body_node
71
+
72
+ !(body_node.begin_type? || body_node.kwbegin_type?)
73
+ end
74
+
75
+ def correct_to_multiline(corrector, node)
46
76
  each_part(node.body) do |part|
47
77
  LineBreakCorrector.break_line_before(
48
78
  range: part, node: node, corrector: corrector,
@@ -58,8 +88,10 @@ module RuboCop
58
88
  move_comment(node, corrector)
59
89
  end
60
90
 
61
- def allow_empty?
62
- cop_config['AllowIfMethodIsEmpty']
91
+ def correct_to_endless(corrector, node)
92
+ arguments = node.arguments.any? ? node.arguments.source : '()'
93
+ replacement = "def #{node.method_name}#{arguments} = #{node.body.source}"
94
+ corrector.replace(node, replacement)
63
95
  end
64
96
 
65
97
  def each_part(body)
@@ -63,24 +63,23 @@ module RuboCop
63
63
  end
64
64
 
65
65
  def autocorrect(corrector, node, if_branch)
66
+ corrector.wrap(node.condition, '(', ')') if node.condition.or_type?
67
+
66
68
  if node.unless?
67
69
  corrector.replace(node.loc.keyword, 'if')
68
70
  corrector.insert_before(node.condition, '!')
69
71
  end
70
72
 
71
- corrector.wrap(node.condition, '(', ')') if node.condition.or_type?
72
-
73
73
  and_operator = if_branch.unless? ? ' && !' : ' && '
74
74
  if if_branch.modifier_form?
75
- correct_for_gurad_condition_style(corrector, node, if_branch, and_operator)
75
+ correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
76
76
  else
77
77
  correct_for_basic_condition_style(corrector, node, if_branch, and_operator)
78
+ correct_for_comment(corrector, node, if_branch)
78
79
  end
79
-
80
- correct_for_comment(corrector, node, if_branch)
81
80
  end
82
81
 
83
- def correct_for_gurad_condition_style(corrector, node, if_branch, and_operator)
82
+ def correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
84
83
  condition = if_branch.condition
85
84
  corrector.insert_after(node.condition, replacement_condition(and_operator, condition))
86
85
 
@@ -95,18 +94,25 @@ module RuboCop
95
94
  )
96
95
  corrector.replace(range, and_operator)
97
96
  corrector.remove(range_by_whole_lines(node.loc.end, include_final_newline: true))
98
- corrector.wrap(if_branch.condition, '(', ')') if if_branch.condition.or_type?
97
+ corrector.wrap(if_branch.condition, '(', ')') if wrap_condition?(if_branch.condition)
99
98
  end
100
99
 
101
100
  def correct_for_comment(corrector, node, if_branch)
102
- comments = processed_source.comments_before_line(if_branch.source_range.line)
101
+ return if config.for_cop('Style/IfUnlessModifier')['Enabled']
102
+
103
+ comments = processed_source.ast_with_comments[if_branch]
103
104
  comment_text = comments.map(&:text).join("\n") << "\n"
104
105
 
105
106
  corrector.insert_before(node.loc.keyword, comment_text) unless comments.empty?
106
107
  end
107
108
 
109
+ def wrap_condition?(node)
110
+ node.or_type? ||
111
+ (node.send_type? && node.arguments.any? && !node.parenthesized?)
112
+ end
113
+
108
114
  def replacement_condition(and_operator, condition)
109
- if condition.or_type?
115
+ if wrap_condition?(condition)
110
116
  "#{and_operator}(#{condition.source})"
111
117
  else
112
118
  "#{and_operator}#{condition.source}"
@@ -26,10 +26,6 @@ module RuboCop
26
26
  # puts $LAST_MATCH_INFO
27
27
  # puts $IGNORECASE
28
28
  # puts $ARGV # or ARGV
29
- # puts $MATCH
30
- # puts $PREMATCH
31
- # puts $POSTMATCH
32
- # puts $LAST_PAREN_MATCH
33
29
  #
34
30
  # @example EnforcedStyle: use_perl_names
35
31
  # # good
@@ -51,10 +47,6 @@ module RuboCop
51
47
  # puts $~
52
48
  # puts $=
53
49
  # puts $*
54
- # puts $&
55
- # puts $`
56
- # puts $'
57
- # puts $+
58
50
  #
59
51
  class SpecialGlobalVars < Base
60
52
  include ConfigurableEnforcedStyle
@@ -85,11 +77,7 @@ module RuboCop
85
77
  :$? => [:$CHILD_STATUS],
86
78
  :$~ => [:$LAST_MATCH_INFO],
87
79
  :$= => [:$IGNORECASE],
88
- :$* => %i[$ARGV ARGV],
89
- :$& => [:$MATCH],
90
- :$` => [:$PREMATCH],
91
- :$' => [:$POSTMATCH],
92
- :$+ => [:$LAST_PAREN_MATCH]
80
+ :$* => %i[$ARGV ARGV]
93
81
  }
94
82
 
95
83
  PERL_VARS =
@@ -11,6 +11,10 @@ module RuboCop
11
11
  # In those cases, it might be useful to extract statements to local
12
12
  # variables or methods which you can then interpolate in a string.
13
13
  #
14
+ # NOTE: When concatenation between two strings is broken over multiple
15
+ # lines, this cop does not register an offense; instead,
16
+ # `Style/LineEndConcatenation` will pick up the offense if enabled.
17
+ #
14
18
  # @example
15
19
  # # bad
16
20
  # email_with_name = user.name + ' <' + user.email + '>'
@@ -19,6 +23,10 @@ module RuboCop
19
23
  # email_with_name = "#{user.name} <#{user.email}>"
20
24
  # email_with_name = format('%s <%s>', user.name, user.email)
21
25
  #
26
+ # # accepted, line-end concatenation
27
+ # name = 'First' +
28
+ # 'Last'
29
+ #
22
30
  class StringConcatenation < Base
23
31
  include Util
24
32
  extend AutoCorrector
@@ -39,6 +47,7 @@ module RuboCop
39
47
 
40
48
  def on_send(node)
41
49
  return unless string_concatenation?(node)
50
+ return if line_end_concatenation?(node)
42
51
 
43
52
  topmost_plus_node = find_topmost_plus_node(node)
44
53
 
@@ -58,6 +67,16 @@ module RuboCop
58
67
 
59
68
  private
60
69
 
70
+ def line_end_concatenation?(node)
71
+ # If the concatenation happens at the end of the line,
72
+ # and both the receiver and argument are strings, allow
73
+ # `Style/LineEndConcatenation` to handle it instead.
74
+ node.receiver.str_type? &&
75
+ node.first_argument.str_type? &&
76
+ node.multiline? &&
77
+ node.source =~ /\+\s*\n/
78
+ end
79
+
61
80
  def find_topmost_plus_node(node)
62
81
  current = node
63
82
  while (parent = current.parent) && plus_node?(parent)
@@ -97,7 +116,7 @@ module RuboCop
97
116
  parts.map do |part|
98
117
  if part.str_type?
99
118
  if single_quoted?(part)
100
- part.value.gsub('\\') { '\\\\' }
119
+ part.value.gsub(/(\\|")/, '\\\\\&')
101
120
  else
102
121
  part.value.inspect[1..-2]
103
122
  end
@@ -26,9 +26,10 @@ module RuboCop
26
26
  # "Just some text"
27
27
  # "No special chars or interpolation"
28
28
  # "Every string in #{project} uses double_quotes"
29
- class StringLiterals < Cop
29
+ class StringLiterals < Base
30
30
  include ConfigurableEnforcedStyle
31
31
  include StringLiteralsHelp
32
+ extend AutoCorrector
32
33
 
33
34
  MSG_INCONSISTENT = 'Inconsistent quote style.'
34
35
 
@@ -46,7 +47,7 @@ module RuboCop
46
47
  quote_styles = detect_quote_styles(node)
47
48
 
48
49
  if quote_styles.size > 1
49
- add_offense(node, message: MSG_INCONSISTENT)
50
+ register_offense(node, message: MSG_INCONSISTENT)
50
51
  else
51
52
  check_multiline_quote_style(node, quote_styles[0])
52
53
  end
@@ -54,11 +55,17 @@ module RuboCop
54
55
  ignore_node(node)
55
56
  end
56
57
 
57
- def autocorrect(node)
58
- StringLiteralCorrector.correct(node, style)
58
+ private
59
+
60
+ def autocorrect(corrector, node)
61
+ StringLiteralCorrector.correct(corrector, node, style)
59
62
  end
60
63
 
61
- private
64
+ def register_offense(node, message: nil)
65
+ add_offense(node, message: message || message(node)) do |corrector|
66
+ autocorrect(corrector, node)
67
+ end
68
+ end
62
69
 
63
70
  def all_string_literals?(nodes)
64
71
  nodes.all? { |n| n.str_type? || n.dstr_type? }
@@ -99,14 +106,13 @@ module RuboCop
99
106
  end
100
107
 
101
108
  def check_multiline_quote_style(node, quote)
102
- range = node.source_range
103
109
  children = node.children
104
110
  if unexpected_single_quotes?(quote)
105
111
  all_children_with_quotes = children.all? { |c| wrong_quotes?(c) }
106
- add_offense(node, location: range) if all_children_with_quotes
112
+ register_offense(node) if all_children_with_quotes
107
113
  elsif unexpected_double_quotes?(quote) &&
108
114
  !accept_child_double_quotes?(children)
109
- add_offense(node, location: range)
115
+ register_offense(node)
110
116
  end
111
117
  end
112
118
 
@@ -19,12 +19,13 @@ module RuboCop
19
19
  #
20
20
  # # good
21
21
  # result = "Tests #{success ? "PASS" : "FAIL"}"
22
- class StringLiteralsInInterpolation < Cop
22
+ class StringLiteralsInInterpolation < Base
23
23
  include ConfigurableEnforcedStyle
24
24
  include StringLiteralsHelp
25
+ extend AutoCorrector
25
26
 
26
- def autocorrect(node)
27
- StringLiteralCorrector.correct(node, style)
27
+ def autocorrect(corrector, node)
28
+ StringLiteralCorrector.correct(corrector, node, style)
28
29
  end
29
30
 
30
31
  private
@@ -22,11 +22,12 @@ module RuboCop
22
22
  SUPER_TYPES = %i[super zsuper].freeze
23
23
 
24
24
  def_node_matcher :proc_node?, '(send (const {nil? cbase} :Proc) :new)'
25
+ def_node_matcher :symbol_proc_receiver?, '{(send ...) (super ...) zsuper}'
25
26
  def_node_matcher :symbol_proc?, <<~PATTERN
26
- ({block numblock}
27
- ${(send ...) (super ...) zsuper}
28
- ${(args (arg _)) %Integer}
29
- (send (lvar _var) $_))
27
+ {
28
+ (block $#symbol_proc_receiver? $(args (arg _var)) (send (lvar _var) $_))
29
+ (numblock $#symbol_proc_receiver? $1 (send (lvar :_1) $_))
30
+ }
30
31
  PATTERN
31
32
 
32
33
  def self.autocorrect_incompatible_with
@@ -41,12 +41,10 @@ module RuboCop
41
41
  'having a single-line body.'
42
42
 
43
43
  def on_while(node)
44
- return unless node.multiline? && single_line_as_modifier?(node)
44
+ return unless single_line_as_modifier?(node)
45
45
 
46
46
  add_offense(node.loc.keyword, message: format(MSG, keyword: node.keyword)) do |corrector|
47
- oneline = "#{node.body.source} #{node.keyword} #{node.condition.source}"
48
-
49
- corrector.replace(node, oneline)
47
+ corrector.replace(node, to_modifier_form(node))
50
48
  end
51
49
  end
52
50
  alias on_until on_while
@@ -33,7 +33,9 @@ module RuboCop
33
33
  end
34
34
 
35
35
  def add_parentheses(node, corrector)
36
- if node.arguments.empty?
36
+ if !node.respond_to?(:arguments)
37
+ corrector.wrap(node, '(', ')')
38
+ elsif node.arguments.empty?
37
39
  corrector.insert_after(node, '()')
38
40
  else
39
41
  corrector.replace(args_begin(node), '(')
@@ -27,6 +27,8 @@ module RuboCop
27
27
  "[Todo] #{offense.message}"
28
28
  elsif offense.corrected?
29
29
  "[Corrected] #{offense.message}"
30
+ elsif offense.correctable?
31
+ "[Correctable] #{offense.message}"
30
32
  else
31
33
  offense.message
32
34
  end
@@ -90,6 +90,8 @@ module RuboCop
90
90
  green('[Todo] ')
91
91
  elsif offense.corrected?
92
92
  green('[Corrected] ')
93
+ elsif offense.correctable?
94
+ yellow('[Correctable] ')
93
95
  else
94
96
  ''
95
97
  end
@@ -71,6 +71,8 @@ module RuboCop
71
71
  '[Todo] '
72
72
  elsif offense.corrected?
73
73
  '[Corrected] '
74
+ elsif offense.correctable?
75
+ '[Correctable] '
74
76
  else
75
77
  ''
76
78
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # Encapsulation of a lockfile for use when checking for gems.
5
+ # Does not actually resolve gems, just parses the lockfile.
6
+ # @api private
7
+ class Lockfile
8
+ # Gems that the bundle depends on
9
+ def dependencies
10
+ return [] unless parser
11
+
12
+ parser.dependencies.values
13
+ end
14
+
15
+ # All activated gems, including transitive dependencies
16
+ def gems
17
+ return [] unless parser
18
+
19
+ # `Bundler::LockfileParser` returns `Bundler::LazySpecification` objects
20
+ # which are not resolved, so extract the dependencies from them
21
+ parser.dependencies.values.concat(parser.specs.flat_map(&:dependencies))
22
+ end
23
+
24
+ def includes_gem?(name)
25
+ gems.any? { |gem| gem.name == name }
26
+ end
27
+
28
+ private
29
+
30
+ def parser
31
+ return unless defined?(Bundler) && Bundler.default_lockfile
32
+ return @parser if defined?(@parser)
33
+
34
+ lockfile = Bundler.read_file(Bundler.default_lockfile)
35
+ @parser = lockfile ? Bundler::LockfileParser.new(lockfile) : nil
36
+ rescue Bundler::BundlerError
37
+ nil
38
+ end
39
+ end
40
+ end