rubocop 1.5.2 → 1.6.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +5 -2
  4. data/config/obsoletion.yml +196 -0
  5. data/lib/rubocop.rb +10 -0
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +16 -44
  7. data/lib/rubocop/config_obsoletion.rb +63 -263
  8. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  9. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  10. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  11. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  12. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  13. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  14. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  15. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  16. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  17. data/lib/rubocop/config_validator.rb +11 -4
  18. data/lib/rubocop/cop/base.rb +17 -15
  19. data/lib/rubocop/cop/cop.rb +2 -2
  20. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  21. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  22. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  23. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  24. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  25. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  26. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  27. data/lib/rubocop/cop/style/float_division.rb +44 -1
  28. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  29. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  30. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  31. data/lib/rubocop/cop/style/redundant_argument.rb +14 -1
  32. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  33. data/lib/rubocop/cop/style/sole_nested_conditional.rb +12 -6
  34. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  35. data/lib/rubocop/cop/style/string_concatenation.rb +19 -0
  36. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  37. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  38. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  39. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  40. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  41. data/lib/rubocop/lockfile.rb +40 -0
  42. data/lib/rubocop/version.rb +1 -1
  43. metadata +14 -3
@@ -84,7 +84,7 @@ module RuboCop
84
84
  private
85
85
 
86
86
  def next_line_empty?(line)
87
- processed_source[line].blank?
87
+ processed_source[line].nil? || processed_source[line].blank?
88
88
  end
89
89
 
90
90
  def require_empty_line?(node)
@@ -58,12 +58,13 @@ module RuboCop
58
58
  # bar: "0000000000",
59
59
  # baz: "0000000000",
60
60
  # }
61
- class LineLength < Cop
61
+ class LineLength < Base
62
62
  include CheckLineBreakable
63
63
  include ConfigurableMax
64
64
  include IgnoredPattern
65
65
  include RangeHelp
66
66
  include LineLengthHelp
67
+ extend AutoCorrector
67
68
 
68
69
  MSG = 'Line is too long. [%<length>d/%<max>d]'
69
70
 
@@ -78,28 +79,16 @@ module RuboCop
78
79
  alias on_hash on_potential_breakable_node
79
80
  alias on_send on_potential_breakable_node
80
81
 
81
- def investigate(processed_source)
82
+ def on_new_investigation
82
83
  check_for_breakable_semicolons(processed_source)
83
84
  end
84
85
 
85
- def investigate_post_walk(processed_source)
86
+ def on_investigation_end
86
87
  processed_source.lines.each_with_index do |line, line_index|
87
88
  check_line(line, line_index)
88
89
  end
89
90
  end
90
91
 
91
- def correctable?
92
- super && !breakable_range.nil?
93
- end
94
-
95
- def autocorrect(range)
96
- return if range.nil?
97
-
98
- lambda do |corrector|
99
- corrector.insert_before(range, "\n")
100
- end
101
- end
102
-
103
92
  private
104
93
 
105
94
  attr_accessor :breakable_range
@@ -203,8 +192,9 @@ module RuboCop
203
192
 
204
193
  self.breakable_range = breakable_range_by_line_index[line_index]
205
194
 
206
- add_offense(breakable_range, location: loc, message: message) do
195
+ add_offense(loc, message: message) do |corrector|
207
196
  self.max = line_length(line)
197
+ corrector.insert_before(breakable_range, "\n") unless breakable_range.nil?
208
198
  end
209
199
  end
210
200
 
@@ -71,7 +71,7 @@ module RuboCop
71
71
  end
72
72
 
73
73
  def qualified_legacy_cop_name(cop_name)
74
- legacy_cop_names = RuboCop::ConfigObsoletion::OBSOLETE_COPS.keys
74
+ legacy_cop_names = RuboCop::ConfigObsoletion.legacy_cop_names
75
75
 
76
76
  legacy_cop_names.detect do |legacy_cop_name|
77
77
  legacy_cop_name.split('/')[1] == cop_name
@@ -14,7 +14,10 @@ module RuboCop
14
14
  return if part_of_ignored_node?(node)
15
15
 
16
16
  if offense?(node)
17
- add_offense(node) { opposite_style_detected }
17
+ add_offense(node) do |corrector|
18
+ opposite_style_detected
19
+ autocorrect(corrector, node) if respond_to?(:autocorrect, true)
20
+ end
18
21
  else
19
22
  correct_style_detected
20
23
  end
@@ -3,7 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # This cop makes sure that accessor methods are named properly.
6
+ # This cop makes sure that accessor methods are named properly. Applies
7
+ # to both instance and class methods.
8
+ #
9
+ # NOTE: Offenses are only registered for methods with the expected
10
+ # arity. Getters (`get_attribute`) must have no arguments to be
11
+ # registered, and setters (`set_attribute(value)`) must have exactly
12
+ # one.
7
13
  #
8
14
  # @example
9
15
  # # bad
@@ -21,6 +27,14 @@ module RuboCop
21
27
  # # good
22
28
  # def attribute
23
29
  # end
30
+ #
31
+ # # accepted, incorrect arity for getter
32
+ # def get_value(attr)
33
+ # end
34
+ #
35
+ # # accepted, incorrect arity for setter
36
+ # def set_value
37
+ # end
24
38
  class AccessorMethodName < Base
25
39
  MSG_READER = 'Do not prefix reader method names with `get_`.'
26
40
  MSG_WRITER = 'Do not prefix writer method names with `set_`.'
@@ -14,8 +14,9 @@ module RuboCop
14
14
  #
15
15
  # # good
16
16
  # ?\C-\M-d
17
- class CharacterLiteral < Cop
17
+ class CharacterLiteral < Base
18
18
  include StringHelp
19
+ extend AutoCorrector
19
20
 
20
21
  MSG = 'Do not use the character literal - ' \
21
22
  'use string literal instead.'
@@ -26,17 +27,15 @@ module RuboCop
26
27
  node.source.size.between?(2, 3)
27
28
  end
28
29
 
29
- def autocorrect(node)
30
- lambda do |corrector|
31
- string = node.source[1..-1]
30
+ def autocorrect(corrector, node)
31
+ string = node.source[1..-1]
32
32
 
33
- # special character like \n
34
- # or ' which needs to use "" or be escaped.
35
- if string.length == 2 || string == "'"
36
- corrector.replace(node, %("#{string}"))
37
- elsif string.length == 1 # normal character
38
- corrector.replace(node, "'#{string}'")
39
- end
33
+ # special character like \n
34
+ # or ' which needs to use "" or be escaped.
35
+ if string.length == 2 || string == "'"
36
+ corrector.replace(node, %("#{string}"))
37
+ elsif string.length == 1 # normal character
38
+ corrector.replace(node, "'#{string}'")
40
39
  end
41
40
  end
42
41
 
@@ -41,6 +41,8 @@ module RuboCop
41
41
  # a.fdiv(b)
42
42
  class FloatDivision < Base
43
43
  include ConfigurableEnforcedStyle
44
+ extend AutoCorrector
45
+
44
46
  MESSAGES = {
45
47
  left_coerce: 'Prefer using `.to_f` on the left side.',
46
48
  right_coerce: 'Prefer using `.to_f` on the right side.',
@@ -64,7 +66,20 @@ module RuboCop
64
66
  PATTERN
65
67
 
66
68
  def on_send(node)
67
- add_offense(node) if offense_condition?(node)
69
+ return unless offense_condition?(node)
70
+
71
+ add_offense(node) do |corrector|
72
+ case style
73
+ when :left_coerce, :single_coerce
74
+ add_to_f_method(corrector, node.receiver)
75
+ remove_to_f_method(corrector, node.first_argument)
76
+ when :right_coerce
77
+ remove_to_f_method(corrector, node.receiver)
78
+ add_to_f_method(corrector, node.first_argument)
79
+ when :fdiv
80
+ correct_from_slash_to_fdiv(corrector, node, node.receiver, node.first_argument)
81
+ end
82
+ end
68
83
  end
69
84
 
70
85
  private
@@ -87,6 +102,34 @@ module RuboCop
87
102
  def message(_node)
88
103
  MESSAGES[style]
89
104
  end
105
+
106
+ def add_to_f_method(corrector, node)
107
+ corrector.insert_after(node, '.to_f') unless node.send_type? && node.method?(:to_f)
108
+ end
109
+
110
+ def remove_to_f_method(corrector, send_node)
111
+ corrector.remove(send_node.loc.dot)
112
+ corrector.remove(send_node.loc.selector)
113
+ end
114
+
115
+ def correct_from_slash_to_fdiv(corrector, node, receiver, argument)
116
+ receiver_source = extract_receiver_source(receiver)
117
+ argument_source = extract_receiver_source(argument)
118
+
119
+ if argument.respond_to?(:parenthesized?) && !argument.parenthesized?
120
+ argument_source = "(#{argument_source})"
121
+ end
122
+
123
+ corrector.replace(node, "#{receiver_source}.fdiv#{argument_source}")
124
+ end
125
+
126
+ def extract_receiver_source(node)
127
+ if node.send_type? && node.method?(:to_f)
128
+ node.receiver.source
129
+ else
130
+ node.source
131
+ end
132
+ end
90
133
  end
91
134
  end
92
135
  end
@@ -46,6 +46,10 @@ module RuboCop
46
46
  MSG_USE_NORMAL =
47
47
  'Modifier form of `%<keyword>s` makes the line too long.'
48
48
 
49
+ def self.autocorrect_incompatible_with
50
+ [Style::SoleNestedConditional]
51
+ end
52
+
49
53
  def on_if(node)
50
54
  msg = if single_line_as_modifier?(node) && !named_capture_in_condition?(node)
51
55
  MSG_USE_MODIFIER
@@ -18,7 +18,7 @@ module RuboCop
18
18
  #
19
19
  # # good
20
20
  # ip_address = ENV['DEPLOYMENT_IP_ADDRESS']
21
- class IpAddresses < Cop
21
+ class IpAddresses < Base
22
22
  include StringHelp
23
23
 
24
24
  IPV6_MAX_SIZE = 45 # IPv4-mapped IPv6 is the longest
@@ -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
@@ -37,6 +37,9 @@ module RuboCop
37
37
  # "first second".split
38
38
  # A.foo
39
39
  class RedundantArgument < Base
40
+ include RangeHelp
41
+ extend AutoCorrector
42
+
40
43
  MSG = 'Argument %<arg>s is redundant because it is implied by default.'
41
44
 
42
45
  def on_send(node)
@@ -44,7 +47,9 @@ module RuboCop
44
47
  return if node.arguments.count != 1
45
48
  return unless redundant_argument?(node)
46
49
 
47
- add_offense(node, message: format(MSG, arg: node.arguments.first.source))
50
+ add_offense(node, message: format(MSG, arg: node.arguments.first.source)) do |corrector|
51
+ corrector.remove(argument_range(node))
52
+ end
48
53
  end
49
54
 
50
55
  private
@@ -69,6 +74,14 @@ module RuboCop
69
74
  Parser::CurrentRuby.new(builder).parse(buffer)
70
75
  end
71
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
72
85
  end
73
86
  end
74
87
  end
@@ -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)