rubocop 0.32.1 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/README.md +22 -4
  4. data/config/default.yml +29 -10
  5. data/config/disabled.yml +8 -4
  6. data/config/enabled.yml +40 -1
  7. data/lib/rubocop.rb +8 -0
  8. data/lib/rubocop/cli.rb +1 -0
  9. data/lib/rubocop/config_loader.rb +23 -2
  10. data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
  11. data/lib/rubocop/cop/lint/circular_argument_reference.rb +38 -0
  12. data/lib/rubocop/cop/lint/def_end_alignment.rb +8 -4
  13. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +38 -21
  14. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  15. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +95 -0
  16. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  17. data/lib/rubocop/cop/mixin/on_method_def.rb +4 -5
  18. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  19. data/lib/rubocop/cop/performance/count.rb +2 -0
  20. data/lib/rubocop/cop/performance/detect.rb +11 -2
  21. data/lib/rubocop/cop/performance/flat_map.rb +3 -3
  22. data/lib/rubocop/cop/performance/string_replacement.rb +161 -0
  23. data/lib/rubocop/cop/rails/date.rb +8 -8
  24. data/lib/rubocop/cop/rails/time_zone.rb +22 -13
  25. data/lib/rubocop/cop/style/block_delimiters.rb +6 -1
  26. data/lib/rubocop/cop/style/documentation.rb +1 -1
  27. data/lib/rubocop/cop/style/extra_spacing.rb +84 -5
  28. data/lib/rubocop/cop/style/first_parameter_indentation.rb +2 -0
  29. data/lib/rubocop/cop/style/indentation_width.rb +28 -4
  30. data/lib/rubocop/cop/style/initial_indentation.rb +32 -0
  31. data/lib/rubocop/cop/style/method_call_parentheses.rb +20 -1
  32. data/lib/rubocop/cop/style/one_line_conditional.rb +8 -4
  33. data/lib/rubocop/cop/style/option_hash.rb +56 -0
  34. data/lib/rubocop/cop/style/optional_arguments.rb +49 -0
  35. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -0
  36. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -66
  37. data/lib/rubocop/cop/style/redundant_return.rb +20 -3
  38. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +77 -0
  39. data/lib/rubocop/cop/style/rescue_modifier.rb +4 -28
  40. data/lib/rubocop/cop/style/send.rb +18 -0
  41. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +32 -13
  42. data/lib/rubocop/cop/style/symbol_literal.rb +1 -1
  43. data/lib/rubocop/cop/style/trivial_accessors.rb +10 -1
  44. data/lib/rubocop/cop/style/while_until_do.rb +1 -1
  45. data/lib/rubocop/cop/style/word_array.rb +13 -1
  46. data/lib/rubocop/formatter/disabled_config_formatter.rb +54 -5
  47. data/lib/rubocop/options.rb +81 -55
  48. data/lib/rubocop/version.rb +1 -1
  49. data/relnotes/v0.33.0.md +157 -0
  50. metadata +11 -2
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for options hashes and discourages them if the
7
+ # current Ruby version supports keyword arguments.
8
+ #
9
+ # @example
10
+ # Instead of:
11
+ #
12
+ # def fry(options = {})
13
+ # temperature = options.fetch(:temperature, 300)
14
+ # ...
15
+ # end
16
+ #
17
+ # Prefer:
18
+ #
19
+ # def fry(temperature: 300)
20
+ # ...
21
+ # end
22
+ class OptionHash < Cop
23
+ MSG = 'Prefer keyword arguments to options hashes.'
24
+
25
+ def on_args(node)
26
+ return unless supports_keyword_arguments?
27
+
28
+ *_but_last, last_arg = *node
29
+
30
+ # asserting that there was an argument at all
31
+ return unless last_arg
32
+
33
+ # asserting last argument is an optional argument
34
+ return unless last_arg.optarg_type?
35
+
36
+ _, default_value = *last_arg
37
+
38
+ # asserting default value is a hash
39
+ return unless default_value.hash_type?
40
+
41
+ # asserting default value is empty hash
42
+ *key_value_pairs = *default_value
43
+ return unless key_value_pairs.empty?
44
+
45
+ add_offense(last_arg, :expression, MSG)
46
+ end
47
+
48
+ private
49
+
50
+ def supports_keyword_arguments?
51
+ RUBY_VERSION >= '2.0.0'
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for optional arguments to methods
7
+ # that do not come at the end of the argument list
8
+ #
9
+ # @example
10
+ # # bad
11
+ # def foo(a = 1, b, c)
12
+ # end
13
+ #
14
+ # # good
15
+ # def baz(a, b, c = 1)
16
+ # end
17
+ #
18
+ # def foobar(a = 1, b = 2, c = 3)
19
+ # end
20
+ class OptionalArguments < Cop
21
+ MSG =
22
+ 'Optional arguments should appear at the end of the argument list.'
23
+
24
+ def on_def(node)
25
+ _method, arguments, = *node
26
+ arguments = *arguments
27
+ optarg_positions = []
28
+ arg_positions = []
29
+
30
+ arguments.each_with_index do |argument, index|
31
+ optarg_positions << index if argument.optarg_type?
32
+ arg_positions << index if argument.arg_type?
33
+ end
34
+
35
+ return if optarg_positions.empty? || arg_positions.empty?
36
+
37
+ optarg_positions.each do |optarg_position|
38
+ # there can only be one group of optional arguments
39
+ break if optarg_position > arg_positions.max
40
+ argument = arguments[optarg_position]
41
+ arg, = *argument
42
+
43
+ add_offense(argument, :expression, format(MSG, arg))
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -37,6 +37,9 @@ module RuboCop
37
37
  # account for edge cases using one variable with a comma
38
38
  return if left_elements.size == 1
39
39
 
40
+ # account for edge case of Constant::CONSTANT
41
+ return unless right.array_type?
42
+
40
43
  # allow mass assignment as the return of a method call
41
44
  return if right.block_type? || right.send_type?
42
45
 
@@ -33,7 +33,7 @@ module RuboCop
33
33
  delimiters = preferred_delimiters(type)
34
34
 
35
35
  "`#{type}`-literals should be delimited by " \
36
- "`#{delimiters[0]}` and `#{delimiters[1]}`"
36
+ "`#{delimiters[0]}` and `#{delimiters[1]}`."
37
37
  end
38
38
 
39
39
  private
@@ -43,20 +43,9 @@ module RuboCop
43
43
 
44
44
  opening_delimiter, closing_delimiter = preferred_delimiters(type)
45
45
 
46
- first_child, *_middle, last_child = *node
47
- opening_newline = new_line(node.loc.begin, first_child)
48
- expression_indentation = leading_whitespace(first_child, :expression)
49
- closing_newline = new_line(node.loc.end, last_child)
50
- closing_indentation = leading_whitespace(node, :end)
51
- expression, reg_opt = *contents(node)
52
-
53
- corrected_source =
54
- type + opening_delimiter + opening_newline +
55
- expression_indentation + expression + closing_newline +
56
- closing_indentation + closing_delimiter + reg_opt
57
-
58
46
  lambda do |corrector|
59
- corrector.replace(node.loc.expression, corrected_source)
47
+ corrector.replace(node.loc.begin, "#{type}#{opening_delimiter}")
48
+ corrector.replace(node.loc.end, closing_delimiter)
60
49
  end
61
50
  end
62
51
 
@@ -72,49 +61,6 @@ module RuboCop
72
61
  cop_config['PreferredDelimiters'][type].split(//)
73
62
  end
74
63
 
75
- def leading_whitespace(object, part)
76
- case object
77
- when String
78
- ''
79
- when NilClass
80
- ''
81
- when Parser::AST::Node
82
- part_range = object.loc.send(part)
83
- left_of_part = part_range.source_line[0...part_range.column]
84
- /^(\s*)$/.match(left_of_part) ? left_of_part : ''
85
- else
86
- fail "Unsupported object #{object}"
87
- end
88
- end
89
-
90
- def contents(node)
91
- first_child, *middle, last_child = *node
92
- last_child ||= first_child
93
- if node.type == :regexp
94
- *_, next_to_last_child = *middle
95
- next_to_last_child ||= first_child
96
- expression = source(node, first_child, next_to_last_child)
97
- reg_opt = last_child.loc.expression.source
98
- else
99
- expression = if first_child.is_a?(Parser::AST::Node)
100
- source(node, first_child, last_child)
101
- else
102
- first_child.to_s
103
- end
104
- reg_opt = ''
105
- end
106
-
107
- [expression, reg_opt]
108
- end
109
-
110
- def source(node, begin_node, end_node)
111
- Parser::Source::Range.new(
112
- node.loc.expression.source_buffer,
113
- begin_node.loc.expression.begin_pos,
114
- end_node.loc.expression.end_pos
115
- ).source
116
- end
117
-
118
64
  def uses_preferred_delimiter?(node, type)
119
65
  preferred_delimiters(type)[0] == begin_source(node)[-1]
120
66
  end
@@ -133,15 +79,6 @@ module RuboCop
133
79
  node.loc.expression.source
134
80
  end
135
81
  end
136
-
137
- def new_line(range, child_node)
138
- same_line?(range, child_node) ? '' : "\n"
139
- end
140
-
141
- def same_line?(range, child_node)
142
- !child_node.is_a?(Parser::AST::Node) ||
143
- range.begin.line == child_node.loc.line
144
- end
145
82
  end
146
83
  end
147
84
  end
@@ -34,16 +34,33 @@ module RuboCop
34
34
  next
35
35
  end
36
36
 
37
+ return_value, = *node
37
38
  if node.children.size > 1
38
- kids = node.children.map { |child| child.loc.expression }
39
- corrector.insert_before(kids.first, '[')
40
- corrector.insert_after(kids.last, ']')
39
+ add_brackets(corrector, node)
40
+ elsif return_value.hash_type?
41
+ add_braces(corrector, return_value) unless braces?(return_value)
41
42
  end
42
43
  return_kw = range_with_surrounding_space(node.loc.keyword, :right)
43
44
  corrector.remove(return_kw)
44
45
  end
45
46
  end
46
47
 
48
+ def braces?(arg)
49
+ arg.loc.begin
50
+ end
51
+
52
+ def add_brackets(corrector, node)
53
+ kids = node.children.map { |child| child.loc.expression }
54
+ corrector.insert_before(kids.first, '[')
55
+ corrector.insert_after(kids.last, ']')
56
+ end
57
+
58
+ def add_braces(corrector, node)
59
+ kids = node.children.map { |child| child.loc.expression }
60
+ corrector.insert_before(kids.first, '{')
61
+ corrector.insert_after(kids.last, '}')
62
+ end
63
+
47
64
  def arguments?(args)
48
65
  return false if args.empty?
49
66
  return true if args.size > 1
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks whether the rescue and ensure keywords are aligned
7
+ # properly.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # begin
13
+ # something
14
+ # rescue
15
+ # puts 'error'
16
+ # end
17
+ #
18
+ # # good
19
+ # begin
20
+ # something
21
+ # rescue
22
+ # puts 'error'
23
+ # end
24
+ class RescueEnsureAlignment < Cop
25
+ MSG = '`%s` at %d, %d is not aligned with `end` at %d, %d.'
26
+
27
+ def on_resbody(node)
28
+ check(node) unless modifier?(node)
29
+ end
30
+
31
+ def on_ensure(node)
32
+ check(node)
33
+ end
34
+
35
+ def investigate(processed_source)
36
+ @modifier_locations = processed_source.tokens
37
+ .select { |t| t.type == :kRESCUE_MOD }
38
+ .map(&:pos)
39
+ end
40
+
41
+ def autocorrect(node)
42
+ source_buffer = node.loc.keyword.source_buffer
43
+ begin_pos = node.loc.keyword.begin_pos
44
+ current_column = node.loc.keyword.column
45
+ whitespace = Parser::Source::Range.new(source_buffer,
46
+ begin_pos - current_column,
47
+ begin_pos)
48
+ return false unless whitespace.source.strip.empty?
49
+
50
+ new_column = ancestor_node(node).loc.end.column
51
+ ->(corrector) { corrector.replace(whitespace, ' ' * new_column) }
52
+ end
53
+
54
+ private
55
+
56
+ def check(node)
57
+ end_loc = ancestor_node(node).loc.end
58
+ return if end_loc.column == node.loc.keyword.column
59
+
60
+ kw_loc = node.loc.keyword
61
+
62
+ add_offense(node, kw_loc,
63
+ format(MSG, kw_loc.source, kw_loc.line, kw_loc.column,
64
+ end_loc.line, end_loc.column))
65
+ end
66
+
67
+ def modifier?(node)
68
+ @modifier_locations.include? node.loc.keyword
69
+ end
70
+
71
+ def ancestor_node(node)
72
+ node.each_ancestor(:kwbegin, :def, :defs).first
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -5,36 +5,12 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for uses of rescue in its modifier form.
7
7
  class RescueModifier < Cop
8
- include OnMethodDef
9
-
10
8
  MSG = 'Avoid using `rescue` in its modifier form.'
11
9
 
12
- def on_rescue(node)
13
- return if ignored_node?(node)
14
-
15
- add_offense(node, :expression)
16
- end
17
-
18
- def on_kwbegin(node)
19
- body, *_ = *node
20
- check(body)
21
- end
22
-
23
- def on_method_def(_node, _method_name, _args, body)
24
- check(body)
25
- end
26
-
27
- def check(body)
28
- return unless body
29
-
30
- case body.type
31
- when :rescue
32
- ignore_node(body)
33
- when :ensure
34
- first_child = body.children.first
35
- if first_child && first_child.type == :rescue
36
- ignore_node(first_child)
37
- end
10
+ def investigate(processed_source)
11
+ processed_source.tokens.each do |t|
12
+ next unless t.type == :kRESCUE_MOD
13
+ add_offense(nil, t.pos)
38
14
  end
39
15
  end
40
16
  end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for the use of the send method.
7
+ class Send < Cop
8
+ MSG = 'Prefer `Object#__send__` or `Object#public_send` to `send`.'
9
+
10
+ def on_send(node)
11
+ _receiver, method_name, *args = *node
12
+ return unless method_name == :send && args.length > 0
13
+ add_offense(node, :selector)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -5,22 +5,32 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for whitespace within string interpolations.
7
7
  #
8
- # Good:
9
- # var = "This is the #{good} example"
10
- #
11
- # Bad:
12
- # var = "This is the #{ bad } example"
8
+ # @example
9
+ # # Good if EnforcedStyle is no_space, bad if space.
10
+ # var = "This is the #{no_space} example"
13
11
  #
12
+ # # Good if EnforceStyle is space, bad if no_space.
13
+ # var = "This is the #{ space } example"
14
14
  class SpaceInsideStringInterpolation < Cop
15
- MSG = 'Space inside string interpolation detected.'
15
+ include ConfigurableEnforcedStyle
16
+
17
+ NO_SPACE_MSG = 'Space inside string interpolation detected.'
18
+ SPACE_MSG = 'Missing space around string interpolation detected.'
16
19
 
17
20
  def on_dstr(node)
18
21
  node.children.select { |n| n.type == :begin }.each do |begin_node|
19
22
  final_node = begin_node.children.last
20
23
 
21
24
  interp = final_node.loc.expression
22
- if range_with_surrounding_space(interp) != interp
23
- add_offense(final_node, :expression)
25
+ interp_with_surrounding_space = range_with_surrounding_space(interp)
26
+ if style == :no_space
27
+ if interp_with_surrounding_space != interp
28
+ add_offense(final_node, :expression, NO_SPACE_MSG)
29
+ end
30
+ elsif style == :space
31
+ if interp_with_surrounding_space.source != " #{interp.source} "
32
+ add_offense(final_node, :expression, SPACE_MSG)
33
+ end
24
34
  end
25
35
  end
26
36
  end
@@ -28,11 +38,20 @@ module RuboCop
28
38
  private
29
39
 
30
40
  def autocorrect(node)
31
- lambda do |corrector|
32
- corrector.replace(
33
- range_with_surrounding_space(node.loc.expression),
34
- node.loc.expression.source
35
- )
41
+ if style == :no_space
42
+ lambda do |corrector|
43
+ corrector.replace(
44
+ range_with_surrounding_space(node.loc.expression),
45
+ node.loc.expression.source
46
+ )
47
+ end
48
+ elsif style == :space
49
+ lambda do |corrector|
50
+ corrector.replace(
51
+ range_with_surrounding_space(node.loc.expression),
52
+ " #{node.loc.expression.source} "
53
+ )
54
+ end
36
55
  end
37
56
  end
38
57
  end