rubocop 0.57.2 → 0.58.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -9
  3. data/bin/setup +7 -0
  4. data/config/default.yml +18 -2
  5. data/config/disabled.yml +4 -0
  6. data/lib/rubocop.rb +1 -0
  7. data/lib/rubocop/ast/node.rb +5 -0
  8. data/lib/rubocop/ast/node/str_node.rb +2 -0
  9. data/lib/rubocop/cli.rb +4 -7
  10. data/lib/rubocop/config.rb +4 -4
  11. data/lib/rubocop/config_loader.rb +4 -8
  12. data/lib/rubocop/cop/corrector.rb +25 -0
  13. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +3 -7
  14. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  15. data/lib/rubocop/cop/layout/indentation_width.rb +9 -1
  16. data/lib/rubocop/cop/layout/leading_blank_lines.rb +1 -1
  17. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +28 -51
  18. data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
  19. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -3
  20. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +1 -1
  21. data/lib/rubocop/cop/lint/useless_access_modifier.rb +17 -4
  22. data/lib/rubocop/cop/metrics/line_length.rb +28 -6
  23. data/lib/rubocop/cop/mixin/check_assignment.rb +0 -2
  24. data/lib/rubocop/cop/mixin/statement_modifier.rb +6 -1
  25. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +79 -4
  26. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +9 -5
  27. data/lib/rubocop/cop/performance/range_include.rb +9 -3
  28. data/lib/rubocop/cop/performance/sample.rb +6 -4
  29. data/lib/rubocop/cop/rails/bulk_change_table.rb +11 -7
  30. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +3 -1
  31. data/lib/rubocop/cop/registry.rb +11 -2
  32. data/lib/rubocop/cop/style/encoding.rb +5 -0
  33. data/lib/rubocop/cop/style/end_block.rb +8 -0
  34. data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -1
  35. data/lib/rubocop/cop/style/ip_addresses.rb +76 -0
  36. data/lib/rubocop/cop/style/multiple_comparison.rb +16 -2
  37. data/lib/rubocop/cop/style/symbol_proc.rb +4 -2
  38. data/lib/rubocop/cop/style/unneeded_condition.rb +19 -2
  39. data/lib/rubocop/formatter/disabled_config_formatter.rb +3 -3
  40. data/lib/rubocop/options.rb +20 -12
  41. data/lib/rubocop/processed_source.rb +2 -5
  42. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  43. data/lib/rubocop/rspec/shared_contexts.rb +0 -4
  44. data/lib/rubocop/rspec/shared_examples.rb +0 -23
  45. data/lib/rubocop/version.rb +1 -1
  46. metadata +7 -11
@@ -36,7 +36,7 @@ module RuboCop
36
36
  def_node_matcher :redundant_with_object?, <<-PATTERN
37
37
  (block
38
38
  $(send _ {:each_with_object :with_object}
39
- (_))
39
+ _)
40
40
  (args
41
41
  (arg _))
42
42
  ...)
@@ -77,9 +77,7 @@ module RuboCop
77
77
  next if references.any? do |reference|
78
78
  next true if !reference.explicit? && ignore_implicit_references?
79
79
 
80
- reference_pos = reference.node.source_range.begin_pos
81
-
82
- reference_pos <= assignment_without_usage_pos
80
+ reference_pos(reference.node) <= assignment_without_usage_pos
83
81
  end
84
82
 
85
83
  yield location_known ? node : argument.declaration_node
@@ -115,6 +113,12 @@ module RuboCop
115
113
  end
116
114
  end
117
115
 
116
+ def reference_pos(node)
117
+ node = node.parent.masgn_type? ? node.parent : node
118
+
119
+ node.source_range.begin_pos
120
+ end
121
+
118
122
  # Check whether the given node is nested into block or conditional.
119
123
  #
120
124
  def node_within_block_or_conditional?(node, stop_search_node)
@@ -44,7 +44,7 @@ module RuboCop
44
44
  # end
45
45
  #
46
46
  # case foo
47
- # when *[1, 2, 3]
47
+ # when 1, 2, 3
48
48
  # bar
49
49
  # else
50
50
  # baz
@@ -134,11 +134,16 @@ module RuboCop
134
134
 
135
135
  if node.begin_type?
136
136
  check_scope(node)
137
- elsif node.send_type? && node.bare_access_modifier?
137
+ elsif node.send_type? && access_modifier?(node)
138
138
  add_offense(node, message: format(MSG, current: node.method_name))
139
139
  end
140
140
  end
141
141
 
142
+ def access_modifier?(node)
143
+ node.bare_access_modifier? ||
144
+ node.method_name == :private_class_method
145
+ end
146
+
142
147
  def check_scope(node)
143
148
  cur_vis, unused = check_child_nodes(node, nil, :public)
144
149
 
@@ -147,9 +152,8 @@ module RuboCop
147
152
 
148
153
  def check_child_nodes(node, unused, cur_vis)
149
154
  node.child_nodes.each do |child|
150
- if child.send_type? && child.bare_access_modifier?
151
- cur_vis, unused =
152
- check_new_visibility(child, unused, child.method_name, cur_vis)
155
+ if child.send_type? && access_modifier?(child)
156
+ cur_vis, unused = check_send_node(child, cur_vis, unused)
153
157
  elsif method_definition?(child)
154
158
  unused = nil
155
159
  elsif start_of_new_scope?(child)
@@ -162,6 +166,15 @@ module RuboCop
162
166
  [cur_vis, unused]
163
167
  end
164
168
 
169
+ def check_send_node(node, cur_vis, unused)
170
+ if node.bare_access_modifier?
171
+ check_new_visibility(node, unused, node.method_name, cur_vis)
172
+ elsif node.method_name == :private_class_method && !node.arguments?
173
+ add_offense(node, message: format(MSG, current: node.method_name))
174
+ [cur_vis, unused]
175
+ end
176
+ end
177
+
165
178
  def check_new_visibility(node, unused, new_vis, cur_vis)
166
179
  # does this modifier just repeat the existing visibility?
167
180
  if new_vis == cur_vis
@@ -7,6 +7,8 @@ module RuboCop
7
7
  module Metrics
8
8
  # This cop checks the length of lines in the source code.
9
9
  # The maximum length is configurable.
10
+ # The tab size is configured in the `IndentationWidth`
11
+ # of the `Layout/Tab` cop.
10
12
  class LineLength < Cop
11
13
  include ConfigurableMax
12
14
  include IgnoredPattern
@@ -23,8 +25,24 @@ module RuboCop
23
25
 
24
26
  private
25
27
 
28
+ def tab_indentation_width
29
+ config.for_cop('Layout/Tab')['IndentationWidth']
30
+ end
31
+
32
+ def line_length(line)
33
+ if tab_indentation_width
34
+ line = line.gsub("\t", ' ' * tab_indentation_width)
35
+ end
36
+ line.length
37
+ end
38
+
39
+ def highligh_start(line)
40
+ return max unless tab_indentation_width
41
+ max - (tab_indentation_width - 1) * line.count("\t")
42
+ end
43
+
26
44
  def check_line(line, index, heredocs)
27
- return if line.length <= max
45
+ return if line_length(line) <= max
28
46
  return if ignored_line?(line, index, heredocs)
29
47
 
30
48
  if ignore_cop_directives? && directive_on_source_line?(index)
@@ -33,7 +51,10 @@ module RuboCop
33
51
  return check_uri_line(line, index) if allow_uri?
34
52
 
35
53
  register_offense(
36
- source_range(processed_source.buffer, index + 1, 0...line.length),
54
+ source_range(
55
+ processed_source.buffer, index,
56
+ highligh_start(line)...line_length(line)
57
+ ),
37
58
  line
38
59
  )
39
60
  end
@@ -44,10 +65,10 @@ module RuboCop
44
65
  end
45
66
 
46
67
  def register_offense(loc, line)
47
- message = format(MSG, length: line.length, max: max)
68
+ message = format(MSG, length: line_length(line), max: max)
48
69
 
49
70
  add_offense(nil, location: loc, message: message) do
50
- self.max = line.length
71
+ self.max = line_length(line)
51
72
  end
52
73
  end
53
74
 
@@ -59,7 +80,7 @@ module RuboCop
59
80
  end
60
81
 
61
82
  source_range(processed_source.buffer, index + 1,
62
- excessive_position...(line.length))
83
+ excessive_position...(line_length(line)))
63
84
  end
64
85
 
65
86
  def max
@@ -100,7 +121,8 @@ module RuboCop
100
121
 
101
122
  def allowed_uri_position?(line, uri_range)
102
123
  uri_range.begin < max &&
103
- (uri_range.end == line.length || uri_range.end == line.length - 1)
124
+ (uri_range.end == line_length(line) ||
125
+ uri_range.end == line_length(line) - 1)
104
126
  end
105
127
 
106
128
  def find_excessive_uri_range(line)
@@ -11,8 +11,6 @@ module RuboCop
11
11
  end
12
12
 
13
13
  def on_send(node)
14
- return unless node.setter_method?
15
-
16
14
  rhs = extract_rhs(node)
17
15
 
18
16
  return unless rhs
@@ -39,7 +39,7 @@ module RuboCop
39
39
  end
40
40
 
41
41
  def length_in_modifier_form(node, cond, body_length)
42
- indentation = node.loc.keyword.column
42
+ indentation = node.loc.keyword.column * indentation_multiplier
43
43
  kw_length = node.loc.keyword.size
44
44
  cond_length = cond.source_range.size
45
45
  space = 1
@@ -49,6 +49,11 @@ module RuboCop
49
49
  def max_line_length
50
50
  config.for_cop('Metrics/LineLength')['Max']
51
51
  end
52
+
53
+ def indentation_multiplier
54
+ return 1 if config.for_cop('Layout/Tab')['Enabled']
55
+ config.for_cop('Layout/Tab')['IndentationWidth']
56
+ end
52
57
  end
53
58
  end
54
59
  end
@@ -6,7 +6,13 @@ module RuboCop
6
6
  # This cop checks for memoized methods whose instance variable name
7
7
  # does not match the method name.
8
8
  #
9
- # @example
9
+ # This cop can be configured with the EnforcedStyleForLeadingUnderscores
10
+ # directive. It can be configured to allow for memoized instance variables
11
+ # prefixed with an underscore. Prefixing ivars with an undersscore is a
12
+ # convention that is used to implicitly indicate that an ivar should not
13
+ # be set or referencd outside of the memoization method.
14
+ #
15
+ # @example EnforcedStyleForLeadingUnderscores: disallowed (default)
10
16
  # # bad
11
17
  # # Method foo is memoized using an instance variable that is
12
18
  # # not `@foo`. This can cause confusion and bugs.
@@ -32,9 +38,44 @@ module RuboCop
32
38
  # @foo ||= calculate_expensive_thing(helper_variable)
33
39
  # end
34
40
  #
41
+ # @example EnforcedStyleForLeadingUnderscores :required
42
+ # # bad
43
+ # def foo
44
+ # @something ||= calculate_expensive_thing
45
+ # end
46
+ #
47
+ # # bad
48
+ # def foo
49
+ # @foo ||= calculate_expensive_thing
50
+ # end
51
+ #
52
+ # # good
53
+ # def foo
54
+ # @_foo ||= calculate_expensive_thing
55
+ # end
56
+ #
57
+ # @example EnforcedStyleForLeadingUnderscores :optional
58
+ # # bad
59
+ # def foo
60
+ # @something ||= calculate_expensive_thing
61
+ # end
62
+ #
63
+ # # good
64
+ # def foo
65
+ # @foo ||= calculate_expensive_thing
66
+ # end
67
+ #
68
+ # # good
69
+ # def foo
70
+ # @_foo ||= calculate_expensive_thing
71
+ # end
35
72
  class MemoizedInstanceVariableName < Cop
73
+ include ConfigurableEnforcedStyle
74
+
36
75
  MSG = 'Memoized variable `%<var>s` does not match ' \
37
76
  'method name `%<method>s`. Use `@%<suggested_var>s` instead.'.freeze
77
+ UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
78
+ 'with `_`. Use `@%<suggested_var>s` instead.'.freeze
38
79
 
39
80
  def self.node_pattern
40
81
  memo_assign = '(or_asgn $(ivasgn _) _)'
@@ -52,10 +93,11 @@ module RuboCop
52
93
  def on_def(node)
53
94
  (method_name, ivar_assign) = memoized?(node)
54
95
  return if matches?(method_name, ivar_assign)
96
+
55
97
  msg = format(
56
- MSG,
98
+ message(ivar_assign.children.first.to_s),
57
99
  var: ivar_assign.children.first.to_s,
58
- suggested_var: method_name.to_s.delete('!?'),
100
+ suggested_var: suggested_var(method_name),
59
101
  method: method_name
60
102
  )
61
103
  add_offense(node, location: ivar_assign.source_range, message: msg)
@@ -64,12 +106,45 @@ module RuboCop
64
106
 
65
107
  private
66
108
 
109
+ def style_parameter_name
110
+ 'EnforcedStyleForLeadingUnderscores'
111
+ end
112
+
67
113
  def matches?(method_name, ivar_assign)
68
114
  return true if ivar_assign.nil? || method_name == :initialize
69
115
  method_name = method_name.to_s.delete('!?')
70
116
  variable = ivar_assign.children.first
71
117
  variable_name = variable.to_s.sub('@', '')
72
- variable_name == method_name
118
+
119
+ return false unless valid_leading_underscore?(variable_name)
120
+
121
+ variable_name.sub(/\A_/, '') == method_name
122
+ end
123
+
124
+ def message(variable)
125
+ variable_name = variable.to_s.sub('@', '')
126
+
127
+ return UNDERSCORE_REQUIRED if style == :required &&
128
+ !variable_name.start_with?('_')
129
+
130
+ MSG
131
+ end
132
+
133
+ def suggested_var(method_name)
134
+ suggestion = method_name.to_s.delete('!?')
135
+
136
+ style == :required ? "_#{suggestion}" : suggestion
137
+ end
138
+
139
+ def valid_leading_underscore?(variable_name)
140
+ case style
141
+ when :required
142
+ variable_name.start_with?('_')
143
+ when :disallowed
144
+ !variable_name.start_with?('_')
145
+ else
146
+ true
147
+ end
73
148
  end
74
149
  end
75
150
  end
@@ -38,11 +38,15 @@ module RuboCop
38
38
  #
39
39
  class InefficientHashSearch < Cop
40
40
  def_node_matcher :inefficient_include?, <<-PATTERN
41
- (send $(send _ ${:keys :values}) :include? $_)
41
+ (send (send $_ {:keys :values}) :include? _)
42
42
  PATTERN
43
43
 
44
44
  def on_send(node)
45
- add_offense(node, message: msg(node)) if inefficient_include?(node)
45
+ inefficient_include?(node) do |receiver|
46
+ return if receiver.nil?
47
+
48
+ add_offense(node)
49
+ end
46
50
  end
47
51
 
48
52
  def autocorrect(node)
@@ -59,7 +63,7 @@ module RuboCop
59
63
 
60
64
  private
61
65
 
62
- def msg(node)
66
+ def message(node)
63
67
  "Use `##{autocorrect_method(node)}` instead of "\
64
68
  "`##{current_method(node)}.include?`."
65
69
  end
@@ -72,7 +76,7 @@ module RuboCop
72
76
  end
73
77
 
74
78
  def current_method(node)
75
- node.children[0].method_name
79
+ node.receiver.method_name
76
80
  end
77
81
 
78
82
  def use_long_method
@@ -87,7 +91,7 @@ module RuboCop
87
91
  end
88
92
 
89
93
  def autocorrect_hash_expression(node)
90
- node.children[0].children[0].loc.expression.source
94
+ node.receiver.receiver.source
91
95
  end
92
96
  end
93
97
  end
@@ -9,11 +9,17 @@ module RuboCop
9
9
  # end points of the `Range`. In a great majority of cases, this is what
10
10
  # is wanted.
11
11
  #
12
- # Here is an example of a case where `Range#cover?` may not provide the
13
- # desired result:
12
+ # @example
13
+ # # bad
14
+ # ('a'..'z').include?('b') # => true
14
15
  #
15
- # ('a'..'z').cover?('yellow') # => true
16
+ # # good
17
+ # ('a'..'z').cover?('b') # => true
16
18
  #
19
+ # # Example of a case where `Range#cover?` may not provide
20
+ # # the desired result:
21
+ #
22
+ # ('a'..'z').cover?('yellow') # => true
17
23
  class RangeInclude < Cop
18
24
  MSG = 'Use `Range#cover?` instead of `Range#include?`.'.freeze
19
25
 
@@ -11,6 +11,8 @@ module RuboCop
11
11
  # [1, 2, 3].shuffle.first
12
12
  # [1, 2, 3].shuffle.first(2)
13
13
  # [1, 2, 3].shuffle.last
14
+ # [2, 1, 3].shuffle.at(0)
15
+ # [2, 1, 3].shuffle.slice(0)
14
16
  # [1, 2, 3].shuffle[2]
15
17
  # [1, 2, 3].shuffle[0, 2] # sample(2) will do the same
16
18
  # [1, 2, 3].shuffle[0..2] # sample(3) will do the same
@@ -28,7 +30,7 @@ module RuboCop
28
30
  MSG = 'Use `%<correct>s` instead of `%<incorrect>s`.'.freeze
29
31
 
30
32
  def_node_matcher :sample_candidate?, <<-PATTERN
31
- (send $(send _ :shuffle $...) ${:first :last :[]} $...)
33
+ (send $(send _ :shuffle $...) ${:first :last :[] :at :slice} $...)
32
34
  PATTERN
33
35
 
34
36
  def on_send(node)
@@ -57,7 +59,7 @@ module RuboCop
57
59
  case method
58
60
  when :first, :last
59
61
  true
60
- when :[]
62
+ when :[], :at, :slice
61
63
  sample_size(method_args) != :unknown
62
64
  else
63
65
  false
@@ -78,7 +80,7 @@ module RuboCop
78
80
  when :erange, :irange
79
81
  range_size(arg)
80
82
  when :int
81
- arg.to_a.first.zero? ? nil : :unknown
83
+ [0, -1].include?(arg.to_a.first) ? nil : :unknown
82
84
  else
83
85
  :unknown
84
86
  end
@@ -126,7 +128,7 @@ module RuboCop
126
128
  case method
127
129
  when :first, :last
128
130
  extract_source(method_args)
129
- when :[]
131
+ when :[], :slice
130
132
  sample_size(method_args)
131
133
  end
132
134
  end
@@ -76,7 +76,7 @@ module RuboCop
76
76
  MYSQL = 'mysql'.freeze
77
77
  POSTGRESQL = 'postgresql'.freeze
78
78
 
79
- MIGRATIION_METHODS = %i[change up down].freeze
79
+ MIGRATION_METHODS = %i[change up down].freeze
80
80
 
81
81
  COMBINABLE_TRANSFORMATIONS = %i[
82
82
  primary_key
@@ -134,7 +134,7 @@ module RuboCop
134
134
 
135
135
  def on_def(node)
136
136
  return unless support_bulk_alter?
137
- return unless MIGRATIION_METHODS.include?(node.method_name)
137
+ return unless MIGRATION_METHODS.include?(node.method_name)
138
138
  return unless node.body
139
139
 
140
140
  recorder = AlterMethodsRecorder.new
@@ -168,7 +168,7 @@ module RuboCop
168
168
 
169
169
  # @param node [RuboCop::AST::SendNode] (send nil? :change_table ...)
170
170
  def include_bulk_options?(node)
171
- # arguments: [(sym :table) (hash (pair (sym :bulk) _))]
171
+ # arguments: [{(sym :table)(str "table")} (hash (pair (sym :bulk) _))]
172
172
  options = node.arguments[1]
173
173
  return false unless options
174
174
  options.hash_type? &&
@@ -196,6 +196,8 @@ module RuboCop
196
196
  config = yaml['development']
197
197
  return nil unless config.is_a?(Hash)
198
198
  config
199
+ rescue Psych::SyntaxError
200
+ nil
199
201
  end
200
202
 
201
203
  def support_bulk_alter?
@@ -231,7 +233,7 @@ module RuboCop
231
233
 
232
234
  # @param node [RuboCop::AST::SendNode]
233
235
  def add_offense_for_alter_methods(node)
234
- # arguments: [(sym :table) ...]
236
+ # arguments: [{(sym :table)(str "table")} ...]
235
237
  table_name = node.arguments[0].value
236
238
  message = format(MSG_FOR_ALTER_METHODS, table: table_name)
237
239
  add_offense(node, message: message)
@@ -251,9 +253,11 @@ module RuboCop
251
253
 
252
254
  # @param new_node [RuboCop::AST::SendNode]
253
255
  def process(new_node)
254
- # arguments: [(sym :table) ...]
255
- table_name = new_node.arguments[0]
256
- flush unless @nodes.all? { |node| node.arguments[0] == table_name }
256
+ # arguments: [{(sym :table)(str "table")} ...]
257
+ table_name = new_node.arguments[0].value.to_s
258
+ flush unless @nodes.all? do |node|
259
+ node.arguments[0].value.to_s == table_name
260
+ end
257
261
  @nodes << new_node
258
262
  end
259
263