rubocop 0.91.0 → 0.91.1

Sign up to get free protection for your applications and to get access to all the features.
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