rubocop 0.91.0 → 0.91.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +9 -1
  4. data/lib/rubocop.rb +1 -1
  5. data/lib/rubocop/comment_config.rb +9 -5
  6. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  7. data/lib/rubocop/cop/layout/case_indentation.rb +4 -7
  8. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  9. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
  10. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +4 -13
  11. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +14 -8
  12. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  13. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -2
  14. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +10 -1
  15. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -2
  16. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -7
  17. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -18
  18. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -2
  19. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +2 -2
  20. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +23 -3
  21. data/lib/rubocop/cop/lint/duplicate_rescue_exception.rb +2 -4
  22. data/lib/rubocop/cop/lint/identity_comparison.rb +5 -3
  23. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +2 -5
  24. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +22 -12
  25. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +14 -4
  26. data/lib/rubocop/cop/lint/rescue_type.rb +0 -1
  27. data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -6
  28. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -5
  29. data/lib/rubocop/cop/lint/useless_access_modifier.rb +3 -9
  30. data/lib/rubocop/cop/lint/useless_times.rb +11 -2
  31. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +25 -16
  32. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
  33. data/lib/rubocop/cop/mixin/rescue_node.rb +1 -0
  34. data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -3
  35. data/lib/rubocop/cop/mixin/visibility_help.rb +4 -16
  36. data/lib/rubocop/cop/style/combinable_loops.rb +5 -10
  37. data/lib/rubocop/cop/style/commented_keyword.rb +7 -8
  38. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +15 -6
  39. data/lib/rubocop/cop/style/if_unless_modifier.rb +0 -4
  40. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -6
  41. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -2
  42. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -0
  43. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -1
  44. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +3 -0
  45. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  46. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -9
  47. data/lib/rubocop/cop/style/redundant_conditional.rb +4 -5
  48. data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -3
  49. data/lib/rubocop/cop/style/redundant_percent_q.rb +9 -11
  50. data/lib/rubocop/cop/style/redundant_return.rb +17 -17
  51. data/lib/rubocop/cop/style/redundant_self.rb +7 -9
  52. data/lib/rubocop/cop/style/redundant_sort.rb +13 -24
  53. data/lib/rubocop/cop/style/redundant_sort_by.rb +5 -9
  54. data/lib/rubocop/cop/style/rescue_standard_error.rb +20 -16
  55. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -2
  56. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +4 -3
  57. data/lib/rubocop/cop/util.rb +0 -1
  58. data/lib/rubocop/directive_comment.rb +32 -0
  59. data/lib/rubocop/version.rb +1 -1
  60. metadata +3 -3
  61. data/lib/rubocop/cop/tokens_util.rb +0 -84
@@ -33,10 +33,8 @@ module RuboCop
33
33
  def on_rescue(node)
34
34
  return if rescue_modifier?(node)
35
35
 
36
- _body, *resbodies, _else = *node
37
-
38
- resbodies.each_with_object(Set.new) do |resbody, previous|
39
- rescued_exceptions = rescued_exceptions(resbody)
36
+ node.resbody_branches.each_with_object(Set.new) do |resbody, previous|
37
+ rescued_exceptions = resbody.exceptions
40
38
 
41
39
  rescued_exceptions.each do |exception|
42
40
  add_offense(exception) unless previous.add?(exception)
@@ -26,9 +26,11 @@ module RuboCop
26
26
  return unless compare_between_object_id_by_double_equal?(node)
27
27
 
28
28
  add_offense(node) do |corrector|
29
- receiver = node.receiver.receiver.source
30
- argument = node.first_argument.receiver.source
31
- replacement = "#{receiver}.equal?(#{argument})"
29
+ receiver = node.receiver.receiver
30
+ argument = node.first_argument.receiver
31
+ return unless receiver && argument
32
+
33
+ replacement = "#{receiver.source}.equal?(#{argument.source})"
32
34
 
33
35
  corrector.replace(node, replacement)
34
36
  end
@@ -58,12 +58,9 @@ module RuboCop
58
58
  PATTERN
59
59
 
60
60
  def on_class(node)
61
- check_node(node.children[2]) # class body
62
- end
63
-
64
- def on_module(node)
65
- check_node(node.children[1]) # module body
61
+ check_node(node.body)
66
62
  end
63
+ alias on_module on_class
67
64
 
68
65
  private
69
66
 
@@ -56,19 +56,29 @@ module RuboCop
56
56
 
57
57
  private
58
58
 
59
+ def previous_line_blank?(range)
60
+ processed_source.buffer.source_line(range.line - 1).blank?
61
+ end
62
+
59
63
  def comment_range_with_surrounding_space(range)
60
- # Eat the entire comment, the preceding space, and the preceding
61
- # newline if there is one.
62
- original_begin = range.begin_pos
63
- range = range_with_surrounding_space(range: range,
64
- side: :left,
65
- newlines: true)
66
- range_with_surrounding_space(range: range,
67
- side: :right,
68
- # Special for a comment that
69
- # begins the file: remove
70
- # the newline at the end.
71
- newlines: original_begin.zero?)
64
+ if previous_line_blank?(range)
65
+ # When the previous line is blank, it should be retained
66
+ range_with_surrounding_space(range: range, side: :right)
67
+ else
68
+ # Eat the entire comment, the preceding space, and the preceding
69
+ # newline if there is one.
70
+ original_begin = range.begin_pos
71
+ range = range_with_surrounding_space(range: range,
72
+ side: :left,
73
+ newlines: true)
74
+
75
+ range_with_surrounding_space(range: range,
76
+ side: :right,
77
+ # Special for a comment that
78
+ # begins the file: remove
79
+ # the newline at the end.
80
+ newlines: original_begin.zero?)
81
+ end
72
82
  end
73
83
 
74
84
  def directive_range_in_list(range, ranges)
@@ -45,18 +45,28 @@ module RuboCop
45
45
  return if processed_source.blank?
46
46
 
47
47
  offenses = processed_source.comment_config.extra_enabled_comments
48
- offenses.each do |comment, name|
48
+ offenses.each { |comment, cop_names| register_offense(comment, cop_names) }
49
+ end
50
+
51
+ private
52
+
53
+ def register_offense(comment, cop_names)
54
+ directive = DirectiveComment.new(comment)
55
+
56
+ cop_names.each do |name|
49
57
  add_offense(
50
58
  range_of_offense(comment, name),
51
59
  message: format(MSG, cop: all_or_name(name))
52
60
  ) do |corrector|
53
- corrector.remove(range_with_comma(comment, name))
61
+ if directive.match?(cop_names)
62
+ corrector.remove(range_with_surrounding_space(range: directive.range, side: :right))
63
+ else
64
+ corrector.remove(range_with_comma(comment, name))
65
+ end
54
66
  end
55
67
  end
56
68
  end
57
69
 
58
- private
59
-
60
70
  def range_of_offense(comment, name)
61
71
  start_pos = comment_start(comment) + cop_name_indention(comment, name)
62
72
  range_between(start_pos, start_pos + name.size)
@@ -35,7 +35,6 @@ module RuboCop
35
35
  # baz
36
36
  # end
37
37
  class RescueType < Base
38
- include RescueNode
39
38
  extend AutoCorrector
40
39
 
41
40
  MSG = 'Rescuing from `%<invalid_exceptions>s` will raise a ' \
@@ -75,8 +75,7 @@ module RuboCop
75
75
 
76
76
  def rescued_groups_for(rescues)
77
77
  rescues.map do |group|
78
- rescue_group, = *group
79
- evaluate_exceptions(rescue_group)
78
+ evaluate_exceptions(group)
80
79
  end
81
80
  end
82
81
 
@@ -117,14 +116,15 @@ module RuboCop
117
116
  $VERBOSE = old_verbose
118
117
  end
119
118
 
120
- def evaluate_exceptions(rescue_group)
121
- if rescue_group
122
- rescued_exceptions = rescued_exceptions(rescue_group)
119
+ def evaluate_exceptions(group)
120
+ rescued_exceptions = group.exceptions
121
+
122
+ if rescued_exceptions.any?
123
123
  rescued_exceptions.each_with_object([]) do |exception, converted|
124
124
  begin
125
125
  silence_warnings do
126
126
  # Avoid printing deprecation warnings about constants
127
- converted << Kernel.const_get(exception)
127
+ converted << Kernel.const_get(exception.source)
128
128
  end
129
129
  rescue NameError
130
130
  converted << nil
@@ -159,16 +159,12 @@ module RuboCop
159
159
  end
160
160
 
161
161
  def preceded_by_continue_statement?(break_statement)
162
- left_siblings_of(break_statement).any? do |sibling|
162
+ break_statement.left_siblings.any? do |sibling|
163
163
  next if sibling.loop_keyword? || loop_method?(sibling)
164
164
 
165
165
  sibling.each_descendant(:next, :redo).any?
166
166
  end
167
167
  end
168
-
169
- def left_siblings_of(node)
170
- node.parent.children[0, node.sibling_index]
171
- end
172
168
  end
173
169
  end
174
170
  end
@@ -131,12 +131,10 @@ module RuboCop
131
131
  MSG = 'Useless `%<current>s` access modifier.'
132
132
 
133
133
  def on_class(node)
134
- check_node(node.children[2]) # class body
135
- end
136
-
137
- def on_module(node)
138
- check_node(node.children[1]) # module body
134
+ check_node(node.body)
139
135
  end
136
+ alias on_module on_class
137
+ alias on_sclass on_class
140
138
 
141
139
  def on_block(node)
142
140
  return unless eval_call?(node)
@@ -144,10 +142,6 @@ module RuboCop
144
142
  check_node(node.body)
145
143
  end
146
144
 
147
- def on_sclass(node)
148
- check_node(node.children[1]) # singleton class body
149
- end
150
-
151
145
  private
152
146
 
153
147
  def autocorrect(corrector, node)
@@ -49,7 +49,7 @@ module RuboCop
49
49
  add_offense(node, message: format(MSG, count: count)) do |corrector|
50
50
  next unless own_line?(node)
51
51
 
52
- if count < 1
52
+ if never_process?(count, node)
53
53
  remove_node(corrector, node)
54
54
  elsif !proc_name.empty?
55
55
  autocorrect_block_pass(corrector, node, proc_name)
@@ -61,6 +61,10 @@ module RuboCop
61
61
 
62
62
  private
63
63
 
64
+ def never_process?(count, node)
65
+ count < 1 || node.block_type? && node.body.nil?
66
+ end
67
+
64
68
  def remove_node(corrector, node)
65
69
  corrector.remove(range_by_whole_lines(node.loc.expression, include_final_newline: true))
66
70
  end
@@ -82,7 +86,12 @@ module RuboCop
82
86
  def fix_indentation(source, range)
83
87
  # Cleanup indentation in a multiline block
84
88
  source_lines = source.split("\n")
85
- source_lines[1..-1].each { |line| line[range] = '' }
89
+
90
+ source_lines[1..-1].each do |line|
91
+ next if line.empty?
92
+
93
+ line[range] = ''
94
+ end
86
95
  source_lines.join("\n")
87
96
  end
88
97
 
@@ -81,40 +81,49 @@ module RuboCop
81
81
  private
82
82
 
83
83
  def assignment?(node)
84
+ return compound_assignment(node) if node.masgn_type? || node.shorthand_asgn?
85
+
84
86
  node.for_type? ||
85
- node.op_asgn_type? ||
86
87
  (node.respond_to?(:setter_method?) && node.setter_method?) ||
87
- (simple_assignment?(node) && capturing_variable?(node.children.first))
88
+ simple_assignment?(node) ||
89
+ argument?(node)
88
90
  end
89
91
 
90
- def simple_assignment?(node)
91
- return false if node.masgn_type?
92
+ def compound_assignment(node)
93
+ # Methods setter can not be detected for multiple assignments
94
+ # and shorthand assigns, so we'll count them here instead
95
+ children = node.masgn_type? ? node.children[0].children : node.children
92
96
 
93
- if node.equals_asgn?
94
- reset_on_lvasgn(node) if node.lvasgn_type?
95
- return true
97
+ will_be_miscounted = children.count do |child|
98
+ child.respond_to?(:setter_method?) &&
99
+ !child.setter_method?
96
100
  end
101
+ @assignment += will_be_miscounted
97
102
 
98
- argument?(node)
103
+ false
99
104
  end
100
105
 
101
- def capturing_variable?(name)
102
- name && !/^_/.match?(name)
106
+ def simple_assignment?(node)
107
+ if !node.equals_asgn?
108
+ false
109
+ elsif node.lvasgn_type?
110
+ reset_on_lvasgn(node)
111
+ capturing_variable?(node.children.first)
112
+ else
113
+ true
114
+ end
103
115
  end
104
116
 
105
- # Returns true for nodes which otherwise would be counted
106
- # as one too many assignment
107
- def assignment_doubled_in_ast?(node)
108
- node.masgn_type? || node.or_asgn_type? || node.and_asgn_type?
117
+ def capturing_variable?(name)
118
+ name && !/^_/.match?(name)
109
119
  end
110
120
 
111
121
  def branch?(node)
112
122
  BRANCH_NODES.include?(node.type)
113
123
  end
114
124
 
115
- # TODO: move to rubocop-ast
116
125
  def argument?(node)
117
- ARGUMENT_TYPES.include?(node.type)
126
+ ARGUMENT_TYPES.include?(node.type) && capturing_variable?(node.children.first)
118
127
  end
119
128
 
120
129
  def condition?(node)
@@ -8,9 +8,9 @@ module RuboCop
8
8
  include ConfigurableFormatting
9
9
 
10
10
  FORMATS = {
11
- snake_case: /(?:[a-z_]|_\d+)$/,
12
- normalcase: /(?:_\D*|[A-Za-z]\d*)$/,
13
- non_integer: /[A-Za-z_]$/
11
+ snake_case: /(?:[[[:lower:]]_]|_\d+)$/,
12
+ normalcase: /(?:_\D*|[[[:upper:]][[:lower:]]]\d*)$/,
13
+ non_integer: /[[[:upper:]][[:lower:]]_]$/
14
14
  }.freeze
15
15
  end
16
16
  end
@@ -18,6 +18,7 @@ module RuboCop
18
18
  @modifier_locations.include?(node.loc.keyword)
19
19
  end
20
20
 
21
+ # @deprecated Use ResbodyNode#exceptions instead
21
22
  def rescued_exceptions(resbody)
22
23
  rescue_group, = *resbody
23
24
  if rescue_group
@@ -57,10 +57,11 @@ module RuboCop
57
57
  end
58
58
 
59
59
  def first_line_comment(node)
60
- comment =
61
- processed_source.find_comment { |c| c.loc.line == node.loc.line }
60
+ comment = processed_source.find_comment { |c| c.loc.line == node.loc.line }
61
+ return unless comment
62
62
 
63
- comment ? comment.loc.expression.source : nil
63
+ comment_source = comment.loc.expression.source
64
+ comment_source unless comment_disables_cop?(comment_source)
64
65
  end
65
66
 
66
67
  def parenthesize?(node)
@@ -80,6 +81,11 @@ module RuboCop
80
81
 
81
82
  config.for_cop('Layout/LineLength')['Max']
82
83
  end
84
+
85
+ def comment_disables_cop?(comment)
86
+ regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
87
+ Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
88
+ end
83
89
  end
84
90
  end
85
91
  end
@@ -16,32 +16,20 @@ module RuboCop
16
16
  end
17
17
 
18
18
  def find_visibility_start(node)
19
- left_siblings_of(node)
20
- .reverse
21
- .find(&method(:visibility_block?))
19
+ node.left_siblings
20
+ .reverse
21
+ .find(&method(:visibility_block?))
22
22
  end
23
23
 
24
24
  # Navigate to find the last protected method
25
25
  def find_visibility_end(node)
26
26
  possible_visibilities = VISIBILITY_SCOPES - [node_visibility(node)]
27
- right = right_siblings_of(node)
27
+ right = node.right_siblings
28
28
  right.find do |child_node|
29
29
  possible_visibilities.include?(node_visibility(child_node))
30
30
  end || right.last
31
31
  end
32
32
 
33
- def left_siblings_of(node)
34
- siblings_of(node)[0, node.sibling_index]
35
- end
36
-
37
- def right_siblings_of(node)
38
- siblings_of(node)[node.sibling_index..-1]
39
- end
40
-
41
- def siblings_of(node)
42
- node.parent.children
43
- end
44
-
45
33
  def_node_matcher :visibility_block?, <<~PATTERN
46
34
  (send nil? { :private :protected :public })
47
35
  PATTERN
@@ -53,14 +53,16 @@ module RuboCop
53
53
  MSG = 'Combine this loop with the previous loop.'
54
54
 
55
55
  def on_block(node)
56
+ return unless node.parent&.begin_type?
56
57
  return unless collection_looping_method?(node)
57
58
 
58
- sibling = left_sibling_of(node)
59
- add_offense(node) if same_collection_looping?(node, sibling)
59
+ add_offense(node) if same_collection_looping?(node, node.left_sibling)
60
60
  end
61
61
 
62
62
  def on_for(node)
63
- sibling = left_sibling_of(node)
63
+ return unless node.parent&.begin_type?
64
+
65
+ sibling = node.left_sibling
64
66
  add_offense(node) if sibling&.for_type? && node.collection == sibling.collection
65
67
  end
66
68
 
@@ -71,13 +73,6 @@ module RuboCop
71
73
  method_name.match?(/^each/) || method_name.match?(/_each$/)
72
74
  end
73
75
 
74
- def left_sibling_of(node)
75
- return unless node.parent&.begin_type?
76
-
77
- index = node.sibling_index - 1
78
- node.parent.children[index] if index >= 0
79
- end
80
-
81
76
  def same_collection_looping?(node, sibling)
82
77
  sibling&.block_type? &&
83
78
  sibling.send_node.method?(node.method_name) &&
@@ -33,13 +33,17 @@ module RuboCop
33
33
  # class X # :nodoc:
34
34
  # y
35
35
  # end
36
- class CommentedKeyword < Cop
36
+ class CommentedKeyword < Base
37
37
  MSG = 'Do not place comments on the same line as the ' \
38
38
  '`%<keyword>s` keyword.'
39
39
 
40
- def investigate(processed_source)
40
+ def on_new_investigation
41
41
  processed_source.comments.each do |comment|
42
- add_offense(comment) if offensive?(comment)
42
+ next unless (match = line(comment).match(/(?<keyword>\S+).*#/))
43
+
44
+ if offensive?(comment)
45
+ add_offense(comment, message: format(MSG, keyword: match[:keyword]))
46
+ end
43
47
  end
44
48
  end
45
49
 
@@ -62,11 +66,6 @@ module RuboCop
62
66
  ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
63
67
  end
64
68
 
65
- def message(comment)
66
- keyword = line(comment).match(/(\S+).*#/)[1]
67
- format(MSG, keyword: keyword)
68
- end
69
-
70
69
  def line(comment)
71
70
  comment.location.expression.source_line
72
71
  end