rubocop 0.91.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +100 -54
  4. data/lib/rubocop.rb +10 -6
  5. data/lib/rubocop/cached_data.rb +2 -1
  6. data/lib/rubocop/cli/command/version.rb +1 -1
  7. data/lib/rubocop/comment_config.rb +9 -5
  8. data/lib/rubocop/config.rb +4 -0
  9. data/lib/rubocop/config_loader.rb +19 -2
  10. data/lib/rubocop/config_loader_resolver.rb +7 -5
  11. data/lib/rubocop/config_regeneration.rb +33 -0
  12. data/lib/rubocop/config_validator.rb +7 -6
  13. data/lib/rubocop/cop/badge.rb +9 -24
  14. data/lib/rubocop/cop/base.rb +16 -1
  15. data/lib/rubocop/cop/commissioner.rb +34 -20
  16. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  17. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  18. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
  19. data/lib/rubocop/cop/layout/array_alignment.rb +1 -0
  20. data/lib/rubocop/cop/layout/case_indentation.rb +4 -7
  21. data/lib/rubocop/cop/layout/class_structure.rb +8 -1
  22. data/lib/rubocop/cop/layout/dot_position.rb +6 -9
  23. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
  24. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +4 -13
  25. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +13 -8
  26. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -2
  27. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -2
  28. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +10 -1
  29. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +4 -13
  30. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  31. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -7
  32. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
  33. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -18
  34. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -2
  35. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +2 -2
  36. data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
  37. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
  38. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
  39. data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
  40. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +23 -3
  41. data/lib/rubocop/cop/lint/duplicate_rescue_exception.rb +2 -4
  42. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
  43. data/lib/rubocop/cop/lint/identity_comparison.rb +5 -3
  44. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +2 -5
  45. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  46. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  47. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +22 -12
  48. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +14 -4
  49. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
  50. data/lib/rubocop/cop/lint/rescue_type.rb +0 -1
  51. data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -6
  52. data/lib/rubocop/cop/lint/to_json.rb +1 -1
  53. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -5
  54. data/lib/rubocop/cop/lint/useless_access_modifier.rb +3 -9
  55. data/lib/rubocop/cop/lint/useless_times.rb +11 -2
  56. data/lib/rubocop/cop/metrics/block_length.rb +3 -1
  57. data/lib/rubocop/cop/metrics/class_length.rb +14 -6
  58. data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -1
  59. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +25 -16
  60. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
  61. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  62. data/lib/rubocop/cop/mixin/rescue_node.rb +1 -0
  63. data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -3
  64. data/lib/rubocop/cop/mixin/visibility_help.rb +4 -16
  65. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  66. data/lib/rubocop/cop/offense.rb +15 -2
  67. data/lib/rubocop/cop/security/open.rb +12 -10
  68. data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
  69. data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
  70. data/lib/rubocop/cop/style/array_coercion.rb +4 -0
  71. data/lib/rubocop/cop/style/case_like_if.rb +20 -4
  72. data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
  73. data/lib/rubocop/cop/style/combinable_loops.rb +13 -11
  74. data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
  75. data/lib/rubocop/cop/style/commented_keyword.rb +7 -8
  76. data/lib/rubocop/cop/style/date_time.rb +12 -1
  77. data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
  78. data/lib/rubocop/cop/style/for.rb +0 -4
  79. data/lib/rubocop/cop/style/format_string_token.rb +48 -3
  80. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +15 -6
  81. data/lib/rubocop/cop/style/if_unless_modifier.rb +0 -4
  82. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -6
  83. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
  84. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -11
  85. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
  86. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  87. data/lib/rubocop/cop/style/mixin_usage.rb +7 -27
  88. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -2
  89. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -0
  90. data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
  91. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -1
  92. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +12 -1
  93. data/lib/rubocop/cop/style/raise_args.rb +0 -3
  94. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  95. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -9
  96. data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
  97. data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
  98. data/lib/rubocop/cop/style/redundant_conditional.rb +4 -5
  99. data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
  100. data/lib/rubocop/cop/style/redundant_parentheses.rb +6 -3
  101. data/lib/rubocop/cop/style/redundant_percent_q.rb +9 -11
  102. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +39 -24
  103. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
  104. data/lib/rubocop/cop/style/redundant_return.rb +17 -17
  105. data/lib/rubocop/cop/style/redundant_self.rb +10 -9
  106. data/lib/rubocop/cop/style/redundant_sort.rb +13 -24
  107. data/lib/rubocop/cop/style/redundant_sort_by.rb +5 -9
  108. data/lib/rubocop/cop/style/rescue_standard_error.rb +20 -16
  109. data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
  110. data/lib/rubocop/cop/style/string_concatenation.rb +14 -2
  111. data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -3
  112. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +4 -3
  113. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  114. data/lib/rubocop/cop/util.rb +0 -1
  115. data/lib/rubocop/cop/variable_force/branch.rb +0 -4
  116. data/lib/rubocop/directive_comment.rb +32 -0
  117. data/lib/rubocop/ext/regexp_node.rb +20 -4
  118. data/lib/rubocop/formatter/disabled_config_formatter.rb +12 -5
  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/options.rb +22 -17
  122. data/lib/rubocop/result_cache.rb +8 -2
  123. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  124. data/lib/rubocop/rspec/expect_offense.rb +5 -5
  125. data/lib/rubocop/runner.rb +9 -5
  126. data/lib/rubocop/target_finder.rb +27 -26
  127. data/lib/rubocop/target_ruby.rb +1 -1
  128. data/lib/rubocop/version.rb +61 -6
  129. metadata +14 -17
  130. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
  131. data/lib/rubocop/cop/tokens_util.rb +0 -84
@@ -51,7 +51,12 @@ module RuboCop
51
51
  end
52
52
 
53
53
  def single_variable_interpolation?(node)
54
- node.children.one? && variable_interpolation?(node.children.first)
54
+ return false unless node.children.one?
55
+
56
+ first_child = node.children.first
57
+
58
+ variable_interpolation?(first_child) ||
59
+ first_child.send_type? && !first_child.operator_method?
55
60
  end
56
61
 
57
62
  def interpolation?(node)
@@ -104,9 +104,13 @@ module RuboCop
104
104
  return offense(begin_node, 'a variable') if node.variable?
105
105
  return offense(begin_node, 'a constant') if node.const_type?
106
106
 
107
+ return offense(begin_node, 'an interpolated expression') if interpolation?(begin_node)
108
+
107
109
  check_send(begin_node, node) if node.call_type?
108
110
  end
109
111
 
112
+ def_node_matcher :interpolation?, '[^begin ^^dstr]'
113
+
110
114
  def check_send(begin_node, node)
111
115
  return check_unary(begin_node, node) if node.unary_operation?
112
116
 
@@ -175,10 +179,9 @@ module RuboCop
175
179
  def raised_to_power_negative_numeric?(begin_node, node)
176
180
  return false unless node.numeric_type?
177
181
 
178
- siblings = begin_node.parent&.children
179
- return false if siblings.nil?
182
+ next_sibling = begin_node.right_sibling
183
+ return false unless next_sibling
180
184
 
181
- next_sibling = siblings[begin_node.sibling_index + 1]
182
185
  base_value = node.children.first
183
186
 
184
187
  base_value.negative? && next_sibling == :**
@@ -17,7 +17,9 @@ module RuboCop
17
17
  # time = "8 o'clock"
18
18
  # question = '"What did you say?"'
19
19
  #
20
- class RedundantPercentQ < Cop
20
+ class RedundantPercentQ < Base
21
+ extend AutoCorrector
22
+
21
23
  MSG = 'Use `%<q_type>s` only for strings that contain both ' \
22
24
  'single quotes and double quotes%<extra>s.'
23
25
  DYNAMIC_MSG = ', or for dynamic strings that contain ' \
@@ -45,22 +47,18 @@ module RuboCop
45
47
  check(node)
46
48
  end
47
49
 
48
- def autocorrect(node)
49
- delimiter =
50
- /^%Q[^"]+$|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
51
- lambda do |corrector|
52
- corrector.replace(node.loc.begin, delimiter)
53
- corrector.replace(node.loc.end, delimiter)
54
- end
55
- end
56
-
57
50
  private
58
51
 
59
52
  def check(node)
60
53
  return unless start_with_percent_q_variant?(node)
61
54
  return if interpolated_quotes?(node) || allowed_percent_q?(node)
62
55
 
63
- add_offense(node)
56
+ add_offense(node) do |corrector|
57
+ delimiter = /^%Q[^"]+$|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
58
+
59
+ corrector.replace(node.loc.begin, delimiter)
60
+ corrector.replace(node.loc.end, delimiter)
61
+ end
64
62
  end
65
63
 
66
64
  def interpolated_quotes?(node)
@@ -22,32 +22,14 @@ module RuboCop
22
22
  # # good
23
23
  # r = /[ab]/
24
24
  class RedundantRegexpCharacterClass < Base
25
- include MatchRange
26
- include RegexpLiteralHelp
27
25
  extend AutoCorrector
28
26
 
27
+ REQUIRES_ESCAPE_OUTSIDE_CHAR_CLASS_CHARS = '.*+?{}()|$'.chars.freeze
29
28
  MSG_REDUNDANT_CHARACTER_CLASS = 'Redundant single-element character class, ' \
30
29
  '`%<char_class>s` can be replaced with `%<element>s`.'
31
30
 
32
- PATTERN = /
33
- (
34
- (?<!\\) # No \-prefix (i.e. not escaped)
35
- \[ # Literal [
36
- (?!\#\{) # Not (the start of) an interpolation
37
- (?: # Either...
38
- \\[^b] | # Any escaped character except b (which would change behaviour)
39
- [^.*+?{}()|$] | # or one that doesn't require escaping outside the character class
40
- \\[upP]\{[^}]+\} # or a unicode code-point or property
41
- )
42
- (?<!\\) # No \-prefix (i.e. not escaped)
43
- \] # Literal ]
44
- )
45
- /x.freeze
46
-
47
31
  def on_regexp(node)
48
32
  each_redundant_character_class(node) do |loc|
49
- next if whitespace_in_free_space_mode?(node, loc)
50
-
51
33
  add_offense(
52
34
  loc, message: format(
53
35
  MSG_REDUNDANT_CHARACTER_CLASS,
@@ -63,19 +45,52 @@ module RuboCop
63
45
  private
64
46
 
65
47
  def each_redundant_character_class(node)
66
- pattern_source(node).scan(PATTERN) do
67
- yield match_range(node.loc.begin.end, Regexp.last_match)
48
+ each_single_element_character_class(node) do |char_class|
49
+ next unless redundant_single_element_character_class?(node, char_class)
50
+
51
+ yield node.loc.begin.adjust(begin_pos: 1 + char_class.ts, end_pos: char_class.te)
52
+ end
53
+ end
54
+
55
+ def each_single_element_character_class(node)
56
+ node.parsed_tree&.each_expression do |expr|
57
+ next if expr.type != :set || expr.expressions.size != 1
58
+ next if expr.negative?
59
+ next if %i[set posixclass nonposixclass].include?(expr.expressions.first.type)
60
+
61
+ yield expr
68
62
  end
69
63
  end
70
64
 
65
+ def redundant_single_element_character_class?(node, char_class)
66
+ class_elem = char_class.expressions.first.text
67
+
68
+ non_redundant =
69
+ whitespace_in_free_space_mode?(node, class_elem) ||
70
+ backslash_b?(class_elem) ||
71
+ requires_escape_outside_char_class?(class_elem)
72
+
73
+ !non_redundant
74
+ end
75
+
71
76
  def without_character_class(loc)
72
77
  loc.source[1..-2]
73
78
  end
74
79
 
75
- def whitespace_in_free_space_mode?(node, loc)
76
- return false unless freespace_mode_regexp?(node)
80
+ def whitespace_in_free_space_mode?(node, elem)
81
+ return false unless node.extended?
82
+
83
+ /\s/.match?(elem)
84
+ end
85
+
86
+ def backslash_b?(elem)
87
+ # \b's behaviour is different inside and outside of a character class, matching word
88
+ # boundaries outside but backspace (0x08) when inside.
89
+ elem == '\b'
90
+ end
77
91
 
78
- /\[\s\]/.match?(loc.source)
92
+ def requires_escape_outside_char_class?(elem)
93
+ REQUIRES_ESCAPE_OUTSIDE_CHAR_CLASS_CHARS.include?(elem)
79
94
  end
80
95
  end
81
96
  end
@@ -34,7 +34,6 @@ module RuboCop
34
34
  # /[+\-]\d/
35
35
  class RedundantRegexpEscape < Base
36
36
  include RangeHelp
37
- include RegexpLiteralHelp
38
37
  extend AutoCorrector
39
38
 
40
39
  MSG_REDUNDANT_ESCAPE = 'Redundant escape inside regexp literal'
@@ -59,9 +58,9 @@ module RuboCop
59
58
 
60
59
  def allowed_escape?(node, char, within_character_class)
61
60
  # Strictly speaking a few single-letter metachars are currently
62
- # unnecessary to "escape", e.g. g, i, E, F, but enumerating them is
61
+ # unnecessary to "escape", e.g. i, E, F, but enumerating them is
63
62
  # rather difficult, and their behaviour could change over time with
64
- # different versions of Ruby so that e.g. /\g/ != /g/
63
+ # different versions of Ruby so that e.g. /\i/ != /i/
65
64
  return true if /[[:alnum:]]/.match?(char)
66
65
  return true if ALLOWED_ALWAYS_ESCAPES.include?(char) || delimiter?(node, char)
67
66
 
@@ -82,19 +81,13 @@ module RuboCop
82
81
  end
83
82
 
84
83
  def each_escape(node)
85
- pattern_source(node).each_char.with_index.reduce(
86
- [nil, 0]
87
- ) do |(previous, char_class_depth), (current, index)|
88
- if previous == '\\'
89
- yield [current, index - 1, !char_class_depth.zero?]
90
-
91
- [nil, char_class_depth]
92
- elsif previous == '['
93
- [current, char_class_depth + 1]
94
- elsif current == ']'
95
- [current, char_class_depth - 1]
84
+ node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
85
+ yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
86
+
87
+ if expr.type == :set
88
+ char_class_depth + (event == :enter ? 1 : -1)
96
89
  else
97
- [current, char_class_depth]
90
+ char_class_depth
98
91
  end
99
92
  end
100
93
  end
@@ -47,8 +47,9 @@ module RuboCop
47
47
  # return x, y
48
48
  # end
49
49
  #
50
- class RedundantReturn < Cop
50
+ class RedundantReturn < Base
51
51
  include RangeHelp
52
+ extend AutoCorrector
52
53
 
53
54
  MSG = 'Redundant `return` detected.'
54
55
  MULTI_RETURN_MSG = 'To return multiple values, use an array.'
@@ -58,16 +59,6 @@ module RuboCop
58
59
  end
59
60
  alias on_defs on_def
60
61
 
61
- def autocorrect(node)
62
- lambda do |corrector|
63
- if node.arguments?
64
- correct_with_arguments(node, corrector)
65
- else
66
- correct_without_arguments(node, corrector)
67
- end
68
- end
69
- end
70
-
71
62
  private
72
63
 
73
64
  def correct_without_arguments(return_node, corrector)
@@ -108,8 +99,8 @@ module RuboCop
108
99
  when :return then check_return_node(node)
109
100
  when :case then check_case_node(node)
110
101
  when :if then check_if_node(node)
111
- when :rescue, :resbody
112
- check_rescue_node(node)
102
+ when :rescue then check_rescue_node(node)
103
+ when :resbody then check_resbody_node(node)
113
104
  when :ensure then check_ensure_node(node)
114
105
  when :begin, :kwbegin
115
106
  check_begin_node(node)
@@ -121,7 +112,13 @@ module RuboCop
121
112
  return if cop_config['AllowMultipleReturnValues'] &&
122
113
  node.children.size > 1
123
114
 
124
- add_offense(node, location: :keyword)
115
+ add_offense(node.loc.keyword, message: message(node)) do |corrector|
116
+ if node.arguments?
117
+ correct_with_arguments(node, corrector)
118
+ else
119
+ correct_without_arguments(node, corrector)
120
+ end
121
+ end
125
122
  end
126
123
 
127
124
  def check_case_node(node)
@@ -137,9 +134,12 @@ module RuboCop
137
134
  end
138
135
 
139
136
  def check_rescue_node(node)
140
- node.child_nodes.each do |child_node|
141
- check_branch(child_node)
142
- end
137
+ node.branches.each { |branch| check_branch(branch) }
138
+ check_branch(node.body) unless node.else?
139
+ end
140
+
141
+ def check_resbody_node(node)
142
+ check_branch(node.body)
143
143
  end
144
144
 
145
145
  def check_ensure_node(node)
@@ -41,7 +41,9 @@ module RuboCop
41
41
  # self.bar == bar # Resolves name clash with argument of the block.
42
42
  # end
43
43
  # end
44
- class RedundantSelf < Cop
44
+ class RedundantSelf < Base
45
+ extend AutoCorrector
46
+
45
47
  MSG = 'Redundant `self` detected.'
46
48
  KERNEL_METHODS = Kernel.methods(false)
47
49
  KEYWORDS = %i[alias and begin break case class def defined? do
@@ -106,20 +108,16 @@ module RuboCop
106
108
 
107
109
  return if allowed_send_node?(node)
108
110
 
109
- add_offense(node)
111
+ add_offense(node) do |corrector|
112
+ corrector.remove(node.receiver)
113
+ corrector.remove(node.loc.dot)
114
+ end
110
115
  end
111
116
 
112
117
  def on_block(node)
113
118
  add_scope(node, @local_variables_scopes[node])
114
119
  end
115
120
 
116
- def autocorrect(node)
117
- lambda do |corrector|
118
- corrector.remove(node.receiver)
119
- corrector.remove(node.loc.dot)
120
- end
121
- end
122
-
123
121
  private
124
122
 
125
123
  def add_scope(node, local_variables = [])
@@ -131,6 +129,9 @@ module RuboCop
131
129
  def allowed_send_node?(node)
132
130
  @allowed_send_nodes.include?(node) ||
133
131
  @local_variables_scopes[node].include?(node.method_name) ||
132
+ node.each_ancestor.any? do |ancestor|
133
+ @local_variables_scopes[ancestor].include?(node.method_name)
134
+ end ||
134
135
  KERNEL_METHODS.include?(node.method_name)
135
136
  end
136
137
 
@@ -49,8 +49,9 @@ module RuboCop
49
49
  # # good
50
50
  # arr.max_by(&:foo)
51
51
  #
52
- class RedundantSort < Cop
52
+ class RedundantSort < Base
53
53
  include RangeHelp
54
+ extend AutoCorrector
54
55
 
55
56
  MSG = 'Use `%<suggestion>s` instead of '\
56
57
  '`%<sorter>s...%<accessor_source>s`.'
@@ -82,35 +83,23 @@ module RuboCop
82
83
  return
83
84
  end
84
85
 
85
- add_offense(ancestor,
86
- location: offense_range(sort_node, ancestor),
87
- message: message(ancestor,
88
- sorter,
89
- accessor))
90
- end
91
-
92
- def autocorrect(node)
93
- sort_node, sorter, accessor = redundant_sort?(node)
94
-
95
- lambda do |corrector|
96
- # Remove accessor, e.g. `first` or `[-1]`.
97
- corrector.remove(
98
- range_between(
99
- accessor_start(node),
100
- node.loc.expression.end_pos
101
- )
102
- )
86
+ message = message(ancestor, sorter, accessor)
103
87
 
104
- # Replace "sort" or "sort_by" with the appropriate min/max method.
105
- corrector.replace(
106
- sort_node.loc.selector,
107
- suggestion(sorter, accessor, arg_value(node))
108
- )
88
+ add_offense(offense_range(sort_node, ancestor), message: message) do |corrector|
89
+ autocorrect(corrector, ancestor, sort_node, sorter, accessor)
109
90
  end
110
91
  end
111
92
 
112
93
  private
113
94
 
95
+ def autocorrect(corrector, node, sort_node, sorter, accessor)
96
+ # Remove accessor, e.g. `first` or `[-1]`.
97
+ corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
98
+
99
+ # Replace "sort" or "sort_by" with the appropriate min/max method.
100
+ corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
101
+ end
102
+
114
103
  def offense_range(sort_node, ancestor)
115
104
  range_between(sort_node.loc.selector.begin_pos, ancestor.loc.expression.end_pos)
116
105
  end
@@ -15,8 +15,9 @@ module RuboCop
15
15
  #
16
16
  # # good
17
17
  # array.sort
18
- class RedundantSortBy < Cop
18
+ class RedundantSortBy < Base
19
19
  include RangeHelp
20
+ extend AutoCorrector
20
21
 
21
22
  MSG = 'Use `sort` instead of `sort_by { |%<var>s| %<var>s }`.'
22
23
 
@@ -28,17 +29,12 @@ module RuboCop
28
29
  redundant_sort_by(node) do |send, var_name|
29
30
  range = sort_by_range(send, node)
30
31
 
31
- add_offense(node,
32
- location: range,
33
- message: format(MSG, var: var_name))
32
+ add_offense(range, message: format(MSG, var: var_name)) do |corrector|
33
+ corrector.replace(range, 'sort')
34
+ end
34
35
  end
35
36
  end
36
37
 
37
- def autocorrect(node)
38
- send = node.send_node
39
- ->(corrector) { corrector.replace(sort_by_range(send, node), 'sort') }
40
- end
41
-
42
38
  private
43
39
 
44
40
  def sort_by_range(send, node)
@@ -70,10 +70,11 @@ module RuboCop
70
70
  # rescue StandardError, SecurityError
71
71
  # bar
72
72
  # end
73
- class RescueStandardError < Cop
73
+ class RescueStandardError < Base
74
74
  include RescueNode
75
75
  include ConfigurableEnforcedStyle
76
76
  include RangeHelp
77
+ extend AutoCorrector
77
78
 
78
79
  MSG_IMPLICIT = 'Omit the error class when rescuing ' \
79
80
  '`StandardError` by itself.'
@@ -94,28 +95,31 @@ module RuboCop
94
95
  case style
95
96
  when :implicit
96
97
  rescue_standard_error?(node) do |error|
97
- add_offense(node,
98
- location: node.loc.keyword.join(error.loc.expression),
99
- message: MSG_IMPLICIT)
98
+ offense_for_implicit_enforced_style(node, error)
100
99
  end
101
100
  when :explicit
102
101
  rescue_without_error_class?(node) do
103
- add_offense(node, location: :keyword, message: MSG_EXPLICIT)
102
+ offense_for_exlicit_enforced_style(node)
104
103
  end
105
104
  end
106
105
  end
107
106
 
108
- def autocorrect(node)
109
- lambda do |corrector|
110
- case style
111
- when :implicit
112
- error = rescue_standard_error?(node)
113
- range = range_between(node.loc.keyword.end_pos,
114
- error.loc.expression.end_pos)
115
- corrector.remove(range)
116
- when :explicit
117
- corrector.insert_after(node.loc.keyword, ' StandardError')
118
- end
107
+ private
108
+
109
+ def offense_for_implicit_enforced_style(node, error)
110
+ range = node.loc.keyword.join(error.loc.expression)
111
+
112
+ add_offense(range, message: MSG_IMPLICIT) do |corrector|
113
+ error = rescue_standard_error?(node)
114
+ range = range_between(node.loc.keyword.end_pos, error.loc.expression.end_pos)
115
+
116
+ corrector.remove(range)
117
+ end
118
+ end
119
+
120
+ def offense_for_exlicit_enforced_style(node)
121
+ add_offense(node.loc.keyword, message: MSG_EXPLICIT) do |corrector|
122
+ corrector.insert_after(node.loc.keyword, ' StandardError')
119
123
  end
120
124
  end
121
125
  end