rubocop 0.41.2 → 0.42.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.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -3
  3. data/config/default.yml +13 -0
  4. data/config/disabled.yml +5 -0
  5. data/config/enabled.yml +20 -0
  6. data/lib/rubocop.rb +4 -0
  7. data/lib/rubocop/ast_node.rb +4 -3
  8. data/lib/rubocop/config.rb +1 -1
  9. data/lib/rubocop/config_loader.rb +2 -7
  10. data/lib/rubocop/cop/cop.rb +3 -3
  11. data/lib/rubocop/cop/lint/block_alignment.rb +18 -16
  12. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +34 -19
  13. data/lib/rubocop/cop/lint/next_without_accumulator.rb +9 -1
  14. data/lib/rubocop/cop/lint/shadowed_exception.rb +23 -3
  15. data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
  16. data/lib/rubocop/cop/lint/useless_access_modifier.rb +41 -4
  17. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -1
  18. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
  19. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +3 -5
  20. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +4 -4
  21. data/lib/rubocop/cop/mixin/space_inside.rb +23 -8
  22. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  23. data/lib/rubocop/cop/offense.rb +33 -10
  24. data/lib/rubocop/cop/performance/case_when_splat.rb +16 -14
  25. data/lib/rubocop/cop/performance/sample.rb +0 -1
  26. data/lib/rubocop/cop/rails/save_bang.rb +77 -0
  27. data/lib/rubocop/cop/rails/validation.rb +15 -15
  28. data/lib/rubocop/cop/style/access_modifier_indentation.rb +1 -1
  29. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  30. data/lib/rubocop/cop/style/block_comments.rb +1 -3
  31. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +19 -10
  32. data/lib/rubocop/cop/style/closing_parenthesis_indentation.rb +1 -1
  33. data/lib/rubocop/cop/style/comment_annotation.rb +14 -14
  34. data/lib/rubocop/cop/style/comment_indentation.rb +1 -1
  35. data/lib/rubocop/cop/style/conditional_assignment.rb +25 -26
  36. data/lib/rubocop/cop/style/dot_position.rb +24 -19
  37. data/lib/rubocop/cop/style/each_for_simple_loop.rb +22 -8
  38. data/lib/rubocop/cop/style/each_with_object.rb +11 -1
  39. data/lib/rubocop/cop/style/else_alignment.rb +1 -1
  40. data/lib/rubocop/cop/style/empty_lines.rb +22 -11
  41. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +9 -6
  42. data/lib/rubocop/cop/style/empty_lines_around_block_body.rb +14 -14
  43. data/lib/rubocop/cop/style/empty_lines_around_class_body.rb +8 -5
  44. data/lib/rubocop/cop/style/empty_lines_around_method_body.rb +12 -8
  45. data/lib/rubocop/cop/style/empty_lines_around_module_body.rb +17 -4
  46. data/lib/rubocop/cop/style/empty_literal.rb +12 -7
  47. data/lib/rubocop/cop/style/for.rb +1 -1
  48. data/lib/rubocop/cop/style/indent_array.rb +1 -1
  49. data/lib/rubocop/cop/style/indent_hash.rb +1 -1
  50. data/lib/rubocop/cop/style/indentation_width.rb +1 -1
  51. data/lib/rubocop/cop/style/initial_indentation.rb +1 -1
  52. data/lib/rubocop/cop/style/lambda.rb +2 -3
  53. data/lib/rubocop/cop/style/method_call_parentheses.rb +6 -4
  54. data/lib/rubocop/cop/style/method_missing.rb +74 -0
  55. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +1 -1
  56. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +1 -1
  57. data/lib/rubocop/cop/style/nested_modifier.rb +23 -13
  58. data/lib/rubocop/cop/style/next.rb +1 -1
  59. data/lib/rubocop/cop/style/numeric_predicate.rb +142 -0
  60. data/lib/rubocop/cop/style/op_method.rb +12 -4
  61. data/lib/rubocop/cop/style/parallel_assignment.rb +11 -3
  62. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +9 -6
  63. data/lib/rubocop/cop/style/single_line_block_params.rb +3 -2
  64. data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
  65. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +1 -1
  66. data/lib/rubocop/cop/style/symbol_array.rb +18 -10
  67. data/lib/rubocop/cop/style/ternary_parentheses.rb +94 -0
  68. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
  69. data/lib/rubocop/cop/style/unneeded_percent_q.rb +12 -6
  70. data/lib/rubocop/cop/util.rb +1 -1
  71. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  72. data/lib/rubocop/cop/variable_force/locatable.rb +1 -1
  73. data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -7
  74. data/lib/rubocop/formatter/html_formatter.rb +25 -11
  75. data/lib/rubocop/formatter/text_util.rb +1 -1
  76. data/lib/rubocop/node_pattern.rb +2 -0
  77. data/lib/rubocop/processed_source.rb +3 -0
  78. data/lib/rubocop/rake_task.rb +1 -1
  79. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  80. data/lib/rubocop/runner.rb +18 -7
  81. data/lib/rubocop/string_util.rb +2 -5
  82. data/lib/rubocop/version.rb +1 -1
  83. metadata +7 -3
@@ -4,15 +4,23 @@
4
4
  module RuboCop
5
5
  module Cop
6
6
  module Style
7
- # This cop makes sure that certain operator methods have their sole
8
- # parameter named `other`.
7
+ # This cop makes sure that certain binary operator methods have their
8
+ # sole parameter named `other`.
9
+ #
10
+ # @example
11
+ #
12
+ # # bad
13
+ # def +(amount); end
14
+ #
15
+ # # good
16
+ # def +(other); end
9
17
  class OpMethod < Cop
10
18
  MSG = 'When defining the `%s` operator, ' \
11
19
  'name its argument `other`.'.freeze
12
20
 
13
21
  OP_LIKE_METHODS = [:eql?, :equal?].freeze
14
22
 
15
- BLACKLISTED = [:+@, :-@, :[], :[]=, :<<].freeze
23
+ BLACKLISTED = [:+@, :-@, :[], :[]=, :<<, :`].freeze
16
24
 
17
25
  TARGET_ARGS = [s(:args, s(:arg, :other)),
18
26
  s(:args, s(:arg, :_other))].freeze
@@ -20,7 +28,7 @@ module RuboCop
20
28
  def on_def(node)
21
29
  name, args, _body = *node
22
30
  return unless op_method?(name) &&
23
- args.children.size == 1 &&
31
+ args.children.one? &&
24
32
  !TARGET_ARGS.include?(args)
25
33
 
26
34
  add_offense(args.children[0], :expression, format(MSG, name))
@@ -179,13 +179,21 @@ module RuboCop
179
179
  protected
180
180
 
181
181
  def assignment
182
- @new_elements.map do |lhs, rhs|
183
- "#{lhs.source} = #{rhs.source}"
184
- end
182
+ @new_elements.map { |lhs, rhs| "#{lhs.source} = #{source(rhs)}" }
185
183
  end
186
184
 
187
185
  private
188
186
 
187
+ def source(node)
188
+ if node.str_type? && node.loc.begin.nil?
189
+ "'#{node.source}'"
190
+ elsif node.sym_type? && node.loc.begin.nil?
191
+ ":#{node.source}"
192
+ else
193
+ node.source
194
+ end
195
+ end
196
+
189
197
  def extract_sources(node)
190
198
  node.children.map(&:source)
191
199
  end
@@ -58,14 +58,17 @@ module RuboCop
58
58
 
59
59
  def check(node)
60
60
  end_loc = ancestor_node(node).loc.end
61
- return if end_loc.column == node.loc.keyword.column
62
- return if end_loc.line == node.loc.keyword.line
63
-
64
61
  kw_loc = node.loc.keyword
65
62
 
66
- add_offense(node, kw_loc,
67
- format(MSG, kw_loc.source, kw_loc.line, kw_loc.column,
68
- end_loc.line, end_loc.column))
63
+ return if end_loc.column == kw_loc.column
64
+ return if end_loc.line == kw_loc.line
65
+
66
+ add_offense(node, kw_loc, format_message(kw_loc, end_loc))
67
+ end
68
+
69
+ def format_message(kw_loc, end_loc)
70
+ format(MSG, kw_loc.source, kw_loc.line, kw_loc.column, end_loc.line,
71
+ end_loc.column)
69
72
  end
70
73
 
71
74
  def modifier?(node)
@@ -12,7 +12,7 @@ module RuboCop
12
12
  class SingleLineBlockParams < Cop
13
13
  def on_block(node)
14
14
  # we care only for single line blocks
15
- return unless block_length(node) == 0
15
+ return unless block_length(node).zero?
16
16
 
17
17
  method_node, args_node, _body_node = *node
18
18
  receiver, method_name, _method_args = *method_node
@@ -21,9 +21,10 @@ module RuboCop
21
21
  return unless receiver
22
22
  return unless method_names.include?(method_name)
23
23
 
24
- # discard cases with argument destructuring
25
24
  args = *args_node
26
25
 
26
+ return if args.empty?
27
+ # discard cases with argument destructuring
27
28
  return true unless args.all? { |n| n.type == :arg }
28
29
  return if args_match?(method_name, args)
29
30
 
@@ -70,7 +70,7 @@ module RuboCop
70
70
  space_inside_left_brace(left_brace, args_delimiter, sb)
71
71
  end
72
72
 
73
- if inner =~ /\S$/ && block_length(node) == 0
73
+ if inner =~ /\S$/ && block_length(node).zero?
74
74
  no_space(sb, right_brace.begin_pos, right_brace.end_pos,
75
75
  'Space missing inside }.')
76
76
  else
@@ -40,7 +40,7 @@ module RuboCop
40
40
  private
41
41
 
42
42
  def autocorrect(node)
43
- new_source = (style == :no_space) ? node.source : " #{node.source} "
43
+ new_source = style == :no_space ? node.source : " #{node.source} "
44
44
  lambda do |corrector|
45
45
  corrector.replace(range_with_surrounding_space(node.source_range),
46
46
  new_source)
@@ -76,23 +76,31 @@ module RuboCop
76
76
  def autocorrect(node)
77
77
  syms = node.children.map { |c| c.children[0].to_s }
78
78
  corrected = if style == :percent
79
- escape = syms.any? { |s| needs_escaping?(s) }
80
- syms = syms.map { |s| escape_string(s) } if escape
81
- syms = syms.map { |s| s.gsub(/\)/, '\\)') }
82
- if escape
83
- "%I(#{syms.join(' ')})"
84
- else
85
- "%i(#{syms.join(' ')})"
86
- end
79
+ percent_replacement(syms)
87
80
  else
88
- syms = syms.map { |s| to_symbol_literal(s) }
89
- "[#{syms.join(', ')}]"
81
+ bracket_replacement(syms)
90
82
  end
91
83
 
92
84
  lambda do |corrector|
93
85
  corrector.replace(node.source_range, corrected)
94
86
  end
95
87
  end
88
+
89
+ def percent_replacement(syms)
90
+ escape = syms.any? { |s| needs_escaping?(s) }
91
+ syms = syms.map { |s| escape_string(s) } if escape
92
+ syms = syms.map { |s| s.gsub(/\)/, '\\)') }
93
+ if escape
94
+ "%I(#{syms.join(' ')})"
95
+ else
96
+ "%i(#{syms.join(' ')})"
97
+ end
98
+ end
99
+
100
+ def bracket_replacement(syms)
101
+ syms = syms.map { |s| to_symbol_literal(s) }
102
+ "[#{syms.join(', ')}]"
103
+ end
96
104
  end
97
105
  end
98
106
  end
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Style
7
+ # This cop checks for the presence of arentheses around ternary
8
+ # conditions. It is configurable to enforce inclusion or omission of
9
+ # parentheses using `EnforcedStyle`.
10
+ #
11
+ # @example
12
+ #
13
+ # EnforcedStyle: require_no_parentheses (deafault)
14
+ #
15
+ # @bad
16
+ # foo = (bar?) ? a : b
17
+ # foo = (bar.baz) ? a : b
18
+ # foo = (bar && baz) ? a : b
19
+ #
20
+ # @good
21
+ # foo = bar? ? a : b
22
+ # foo = bar.baz? ? a : b
23
+ # foo = bar && baz ? a : b
24
+ #
25
+ # @example
26
+ #
27
+ # EnforcedStyle: require_parentheses
28
+ #
29
+ # @bad
30
+ # foo = bar? ? a : b
31
+ # foo = bar.baz? ? a : b
32
+ # foo = bar && baz ? a : b
33
+ #
34
+ # @good
35
+ # foo = (bar?) ? a : b
36
+ # foo = (bar.baz) ? a : b
37
+ # foo = (bar && baz) ? a : b
38
+ class TernaryParentheses < Cop
39
+ include IfNode
40
+ include SafeAssignment
41
+ include ConfigurableEnforcedStyle
42
+
43
+ MSG = '%s parentheses for ternary conditions.'.freeze
44
+
45
+ def on_if(node)
46
+ return unless ternary?(node)
47
+
48
+ add_offense(node, node.source_range, message) if offense?(node)
49
+ end
50
+
51
+ private
52
+
53
+ def offense?(node)
54
+ condition, = *node
55
+
56
+ (require_parentheses? && !parenthesized?(condition) ||
57
+ !require_parentheses? && parenthesized?(condition)) &&
58
+ !(safe_assignment?(condition) && safe_assignment_allowed?)
59
+ end
60
+
61
+ def autocorrect(node)
62
+ condition, = *node
63
+
64
+ lambda do |corrector|
65
+ if require_parentheses?
66
+ corrector.insert_before(condition.source_range, '(')
67
+ corrector.insert_after(condition.source_range, ')')
68
+ else
69
+ # Don't correct if it's a safe assignment
70
+ unless safe_assignment?(condition)
71
+ corrector.remove(condition.loc.begin)
72
+ corrector.remove(condition.loc.end)
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def message
79
+ verb = require_parentheses? ? 'Use' : 'Omit'
80
+
81
+ format(MSG, verb)
82
+ end
83
+
84
+ def require_parentheses?
85
+ style == :require_parentheses
86
+ end
87
+
88
+ def parenthesized?(node)
89
+ node.source =~ /^\(.*\)$/
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -60,7 +60,7 @@ module RuboCop
60
60
  when 0
61
61
  'Trailing blank line missing.'
62
62
  else
63
- instead_of = if wanted_blank_lines == 0
63
+ instead_of = if wanted_blank_lines.zero?
64
64
  ''
65
65
  else
66
66
  "instead of #{wanted_blank_lines} "
@@ -16,6 +16,7 @@ module RuboCop
16
16
  PERCENT_Q = '%q'.freeze
17
17
  PERCENT_CAPITAL_Q = '%Q'.freeze
18
18
  STRING_INTERPOLATION_REGEXP = /#\{.+}/
19
+ ESCAPED_NON_BACKSLASH = /\\[^\\]/
19
20
 
20
21
  def on_dstr(node)
21
22
  check(node)
@@ -35,12 +36,9 @@ module RuboCop
35
36
  src = node.source
36
37
  return unless start_with_percent_q_variant?(src)
37
38
  return if src.include?(SINGLE_QUOTE) && src.include?(QUOTE)
38
- if src.start_with?(PERCENT_Q) && src =~ STRING_INTERPOLATION_REGEXP
39
- return
40
- end
41
- if src.start_with?(PERCENT_CAPITAL_Q) && acceptable_capital_q?(node)
42
- return
43
- end
39
+ return if src.start_with?(PERCENT_Q) && acceptable_q?(node)
40
+ return if src.start_with?(PERCENT_CAPITAL_Q) &&
41
+ acceptable_capital_q?(node)
44
42
 
45
43
  add_offense(node, :expression)
46
44
  end
@@ -73,6 +71,14 @@ module RuboCop
73
71
  string.start_with?(PERCENT_Q, PERCENT_CAPITAL_Q)
74
72
  end
75
73
 
74
+ def acceptable_q?(node)
75
+ src = node.source
76
+
77
+ return true if src =~ STRING_INTERPOLATION_REGEXP
78
+
79
+ src.scan(/\\./).any? { |s| s =~ ESCAPED_NON_BACKSLASH }
80
+ end
81
+
76
82
  def acceptable_capital_q?(node)
77
83
  src = node.source
78
84
  src.include?(QUOTE) &&
@@ -95,7 +95,7 @@ module RuboCop
95
95
  column_index = column
96
96
  end
97
97
 
98
- line_begin_pos = if line_number == 0
98
+ line_begin_pos = if line_number.zero?
99
99
  0
100
100
  else
101
101
  source_buffer.line_range(line_number).begin_pos
@@ -79,7 +79,7 @@ module RuboCop
79
79
  def operator_assignment_node
80
80
  return nil unless node.parent
81
81
  return nil unless OPERATOR_ASSIGNMENT_TYPES.include?(node.parent.type)
82
- return nil unless node.parent.children.index(node) == 0
82
+ return nil unless node.sibling_index.zero?
83
83
  node.parent
84
84
  end
85
85
 
@@ -124,7 +124,7 @@ module RuboCop
124
124
  end
125
125
 
126
126
  def rescue_body_name
127
- if body_index == 0
127
+ if body_index.zero?
128
128
  'main'
129
129
  elsif branch_body_node.type == :resbody
130
130
  "rescue#{body_index - 1}"
@@ -60,6 +60,8 @@ module RuboCop
60
60
  "#{output.path}` in a .rubocop.yml file."
61
61
  end
62
62
 
63
+ private
64
+
63
65
  def command
64
66
  command = 'rubocop --auto-gen-config'
65
67
  if @exclude_limit_option
@@ -89,14 +91,22 @@ module RuboCop
89
91
  output.puts '# Cop supports --auto-correct.'
90
92
  end
91
93
 
92
- default_cfg = RuboCop::ConfigLoader.default_configuration[cop_name]
94
+ default_cfg = default_config(cop_name)
93
95
  return unless default_cfg
94
96
 
95
- params = default_cfg.keys -
96
- %w(Description StyleGuide Reference Enabled Exclude) -
97
- cfg.keys
97
+ params = cop_config_params(default_cfg, cfg)
98
98
  return if params.empty?
99
99
 
100
+ output_cop_param_comments(params, default_cfg)
101
+ end
102
+
103
+ def cop_config_params(default_cfg, cfg)
104
+ default_cfg.keys -
105
+ %w(Description StyleGuide Reference Enabled Exclude) -
106
+ cfg.keys
107
+ end
108
+
109
+ def output_cop_param_comments(params, default_cfg)
100
110
  output.puts "# Configuration parameters: #{params.join(', ')}."
101
111
 
102
112
  params.each do |param|
@@ -108,6 +118,10 @@ module RuboCop
108
118
  end
109
119
  end
110
120
 
121
+ def default_config(cop_name)
122
+ RuboCop::ConfigLoader.default_configuration[cop_name]
123
+ end
124
+
111
125
  def output_cop_config(output, cfg, cop_name)
112
126
  # 'Enabled' option will be put into file only if exclude
113
127
  # limit is exceeded.
@@ -156,9 +170,6 @@ module RuboCop
156
170
  output.puts " - '#{file}'"
157
171
  end
158
172
  end
159
- rescue LoadError
160
- # Fallback to Enabled: false for Ruby < 1.9.3
161
- output.puts ' Enabled: false'
162
173
  end
163
174
  end
164
175
  end
@@ -94,20 +94,34 @@ module RuboCop
94
94
  end
95
95
 
96
96
  def highlighted_source_line(offense)
97
- location = offense.location
98
- source_line = location.source_line
99
-
100
- escape(source_line[0...offense.highlighted_area.begin_pos]) +
101
- "<span class=\"highlight #{offense.severity}\">" +
102
- escape(offense.highlighted_area.source) +
103
- '</span>' +
104
- escape(source_line[offense.highlighted_area.end_pos..-1]) +
105
- (location.first_line == location.last_line ? '' : " #{ELLIPSES}")
97
+ source_before_highlight(offense) +
98
+ hightlight_source_tag(offense) +
99
+ source_after_highlight(offense) +
100
+ possible_ellipses(offense.location)
101
+ end
102
+
103
+ def hightlight_source_tag(offense)
104
+ "<span class=\"highlight #{offense.severity}\">" \
105
+ "#{escape(offense.highlighted_area.source)}" \
106
+ '</span>'
107
+ end
108
+
109
+ def source_before_highlight(offense)
110
+ source_line = offense.location.source_line
111
+ escape(source_line[0...offense.highlighted_area.begin_pos])
112
+ end
113
+
114
+ def source_after_highlight(offense)
115
+ source_line = offense.location.source_line
116
+ escape(source_line[offense.highlighted_area.end_pos..-1])
117
+ end
118
+
119
+ def possible_ellipses(location)
120
+ location.first_line == location.last_line ? '' : " #{ELLIPSES}"
106
121
  end
107
122
 
108
123
  def escape(s)
109
- # Single quotes not escaped in Ruby 1.9, so add extra substitution.
110
- CGI.escapeHTML(s).gsub(/'/, '&#39;')
124
+ CGI.escapeHTML(s)
111
125
  end
112
126
 
113
127
  def base64_encoded_logo_image
@@ -8,7 +8,7 @@ module RuboCop
8
8
  module_function
9
9
 
10
10
  def pluralize(number, thing, options = {})
11
- if number == 0 && options[:no_for_zero]
11
+ if number.zero? && options[:no_for_zero]
12
12
  "no #{thing}s"
13
13
  elsif number == 1
14
14
  "1 #{thing}"