rubocop 0.55.0 → 0.56.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +45 -0
  4. data/config/disabled.yml +4 -4
  5. data/config/enabled.yml +32 -16
  6. data/lib/rubocop.rb +8 -2
  7. data/lib/rubocop/cli.rb +4 -0
  8. data/lib/rubocop/comment_config.rb +36 -9
  9. data/lib/rubocop/config.rb +8 -1
  10. data/lib/rubocop/cop/generator.rb +4 -3
  11. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +101 -29
  12. data/lib/rubocop/cop/{style → layout}/empty_line_after_guard_clause.rb +1 -1
  13. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +5 -5
  14. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +112 -2
  15. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +8 -4
  16. data/lib/rubocop/cop/lint/erb_new_arguments.rb +107 -0
  17. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -0
  18. data/lib/rubocop/cop/lint/nested_percent_literal.rb +0 -8
  19. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  20. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  21. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -0
  22. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +16 -3
  23. data/lib/rubocop/cop/lint/splat_keyword_arguments.rb +36 -0
  24. data/lib/rubocop/cop/lint/unneeded_cop_enable_directive.rb +20 -2
  25. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +95 -0
  26. data/lib/rubocop/cop/performance/unneeded_sort.rb +41 -6
  27. data/lib/rubocop/cop/rails/assert_not.rb +44 -0
  28. data/lib/rubocop/cop/rails/blank.rb +34 -28
  29. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +1 -1
  30. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +12 -2
  31. data/lib/rubocop/cop/rails/http_positional_arguments.rb +7 -7
  32. data/lib/rubocop/cop/rails/present.rb +31 -25
  33. data/lib/rubocop/cop/rails/refute_methods.rb +76 -0
  34. data/lib/rubocop/cop/rails/reversible_migration.rb +6 -4
  35. data/lib/rubocop/cop/rails/save_bang.rb +4 -1
  36. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -10
  37. data/lib/rubocop/cop/style/command_literal.rb +15 -3
  38. data/lib/rubocop/cop/style/comment_annotation.rb +6 -1
  39. data/lib/rubocop/cop/style/empty_method.rb +6 -3
  40. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +12 -2
  41. data/lib/rubocop/cop/style/method_missing_super.rb +34 -0
  42. data/lib/rubocop/cop/style/{method_missing.rb → missing_respond_to_missing.rb} +7 -29
  43. data/lib/rubocop/cop/style/parentheses_around_condition.rb +28 -2
  44. data/lib/rubocop/node_pattern.rb +1 -1
  45. data/lib/rubocop/processed_source.rb +12 -6
  46. data/lib/rubocop/result_cache.rb +9 -4
  47. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  48. data/lib/rubocop/runner.rb +8 -2
  49. data/lib/rubocop/target_finder.rb +40 -60
  50. data/lib/rubocop/version.rb +1 -1
  51. metadata +10 -4
@@ -10,6 +10,8 @@ module RuboCop
10
10
  # This cop detects instances of rubocop:enable comments that can be
11
11
  # removed.
12
12
  #
13
+ # When comment enables all cops at once `rubocop:enable all`
14
+ # that cop checks whether any cop was actually enabled.
13
15
  # @example
14
16
  # # bad
15
17
  # foo = 1
@@ -17,6 +19,19 @@ module RuboCop
17
19
  #
18
20
  # # good
19
21
  # foo = 1
22
+ # @example
23
+ # # bad
24
+ # # rubocop:disable Metrics/LineLength
25
+ # baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrrr
26
+ # # rubocop:enable Metrics/LineLength
27
+ # baz
28
+ # # rubocop:enable all
29
+ #
30
+ # # good
31
+ # # rubocop:disable Metrics/LineLength
32
+ # baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrrr
33
+ # # rubocop:enable all
34
+ # baz
20
35
  class UnneededCopEnableDirective < Cop
21
36
  include RangeHelp
22
37
  include SurroundingSpace
@@ -30,7 +45,7 @@ module RuboCop
30
45
  add_offense(
31
46
  [comment, name],
32
47
  location: range_of_offense(comment, name),
33
- message: format(MSG, cop: name)
48
+ message: format(MSG, cop: all_or_name(name))
34
49
  )
35
50
  end
36
51
  end
@@ -90,8 +105,11 @@ module RuboCop
90
105
  range_class.new(buffer, start, comment.loc.expression.end_pos)
91
106
  end
92
107
  end
108
+
109
+ def all_or_name(name)
110
+ name == 'all' ? 'all cops' : name
111
+ end
93
112
  end
94
113
  end
95
114
  end
96
115
  end
97
- # rubocop:enable Lint/UnneededCopEnableDirective
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # This cop checks for inefficient searching of keys and values within
7
+ # hashes.
8
+ #
9
+ # `Hash#keys.include?` is less efficient than `Hash#key?` because
10
+ # the former allocates a new array and then performs an O(n) search
11
+ # through that array, while `Hash#key?` does not allocate any array and
12
+ # performs a faster O(1) search for the key.
13
+ #
14
+ # `Hash#values.include?` is less efficient than `Hash#value?`. While they
15
+ # both perform an O(n) search through all of the values, calling `values`
16
+ # allocates a new array while using `value?` does not.
17
+ #
18
+ # @example
19
+ # # bad
20
+ # { a: 1, b: 2 }.keys.include?(:a)
21
+ # { a: 1, b: 2 }.keys.include?(:z)
22
+ # h = { a: 1, b: 2 }; h.keys.include?(100)
23
+ #
24
+ # # good
25
+ # { a: 1, b: 2 }.key?(:a)
26
+ # { a: 1, b: 2 }.has_key?(:z)
27
+ # h = { a: 1, b: 2 }; h.key?(100)
28
+ #
29
+ # # bad
30
+ # { a: 1, b: 2 }.values.include?(2)
31
+ # { a: 1, b: 2 }.values.include?('garbage')
32
+ # h = { a: 1, b: 2 }; h.values.include?(nil)
33
+ #
34
+ # # good
35
+ # { a: 1, b: 2 }.value?(2)
36
+ # { a: 1, b: 2 }.has_value?('garbage')
37
+ # h = { a: 1, b: 2 }; h.value?(nil)
38
+ #
39
+ class InefficientHashSearch < Cop
40
+ def_node_matcher :inefficient_include?, <<-PATTERN
41
+ (send $(send _ ${:keys :values}) :include? $_)
42
+ PATTERN
43
+
44
+ def on_send(node)
45
+ add_offense(node, message: msg(node)) if inefficient_include?(node)
46
+ end
47
+
48
+ def autocorrect(node)
49
+ lambda do |corrector|
50
+ # Replace `keys.include?` or `values.include?` with the appropriate
51
+ # `key?`/`value?` method.
52
+ corrector.replace(
53
+ node.loc.expression,
54
+ "#{autocorrect_hash_expression(node)}."\
55
+ "#{autocorrect_method(node)}(#{autocorrect_argument(node)})"
56
+ )
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def msg(node)
63
+ "Use `##{autocorrect_method(node)}` instead of "\
64
+ "`##{current_method(node)}.include?`."
65
+ end
66
+
67
+ def autocorrect_method(node)
68
+ case current_method(node)
69
+ when :keys then use_long_method ? 'has_key?' : 'key?'
70
+ when :values then use_long_method ? 'has_value?' : 'value?'
71
+ end
72
+ end
73
+
74
+ def current_method(node)
75
+ node.children[0].method_name
76
+ end
77
+
78
+ def use_long_method
79
+ preferred_config = config.for_all_cops['Style/PreferredHashMethods']
80
+ preferred_config &&
81
+ preferred_config['EnforcedStyle'] == 'long' &&
82
+ preferred_config['Enabled']
83
+ end
84
+
85
+ def autocorrect_argument(node)
86
+ node.arguments.first.source
87
+ end
88
+
89
+ def autocorrect_hash_expression(node)
90
+ node.children[0].children[0].loc.expression.source
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -3,17 +3,52 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop is used to identify instances of sorting and then taking
7
- # only the first or last element.
6
+ # This cop is used to identify instances of sorting and then
7
+ # taking only the first or last element. The same behavior can
8
+ # be accomplished without a relatively expensive sort by using
9
+ # `Enumerable#min` instead of sorting and taking the first
10
+ # element and `Enumerable#max` instead of sorting and taking the
11
+ # last element. Similarly, `Enumerable#min_by` and
12
+ # `Enumerable#max_by` can replace `Enumerable#sort_by` calls
13
+ # after which only the first or last element is used.
8
14
  #
9
15
  # @example
10
16
  # # bad
11
- # [].sort.first
12
- # [].sort_by(&:length).last
17
+ # [2, 1, 3].sort.first
18
+ # [2, 1, 3].sort[0]
19
+ # [2, 1, 3].sort.at(0)
20
+ # [2, 1, 3].sort.slice(0)
13
21
  #
14
22
  # # good
15
- # [].min
16
- # [].max_by(&:length)
23
+ # [2, 1, 3].min
24
+ #
25
+ # # bad
26
+ # [2, 1, 3].sort.last
27
+ # [2, 1, 3].sort[-1]
28
+ # [2, 1, 3].sort.at(-1)
29
+ # [2, 1, 3].sort.slice(-1)
30
+ #
31
+ # # good
32
+ # [2, 1, 3].max
33
+ #
34
+ # # bad
35
+ # arr.sort_by(&:foo).first
36
+ # arr.sort_by(&:foo)[0]
37
+ # arr.sort_by(&:foo).at(0)
38
+ # arr.sort_by(&:foo).slice(0)
39
+ #
40
+ # # good
41
+ # arr.min_by(&:foo)
42
+ #
43
+ # # bad
44
+ # arr.sort_by(&:foo).last
45
+ # arr.sort_by(&:foo)[-1]
46
+ # arr.sort_by(&:foo).at(-1)
47
+ # arr.sort_by(&:foo).slice(-1)
48
+ #
49
+ # # good
50
+ # arr.max_by(&:foo)
51
+ #
17
52
  class UnneededSort < Cop
18
53
  include RangeHelp
19
54
 
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ #
7
+ # Use `assert_not` instead of `assert !`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert !x
12
+ #
13
+ # # good
14
+ # assert_not x
15
+ #
16
+ class AssertNot < RuboCop::Cop::Cop
17
+ MSG = 'Prefer `assert_not` over `assert !`.'.freeze
18
+
19
+ def_node_matcher :offensive?, '(send nil? :assert (send ... :!))'
20
+
21
+ def on_send(node)
22
+ add_offense(node) if offensive?(node)
23
+ end
24
+
25
+ def autocorrect(node)
26
+ expression = node.loc.expression
27
+
28
+ lambda do |corrector|
29
+ corrector.replace(
30
+ expression,
31
+ corrected_source(expression.source)
32
+ )
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def corrected_source(source)
39
+ source.gsub(/^assert(\(| ) *! */, 'assert_not\\1')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -3,40 +3,46 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cops checks for code that can be changed to `blank?`.
7
- # Settings:
8
- # NilOrEmpty: Convert checks for `nil` or `empty?` to `blank?`
9
- # NotPresent: Convert usages of not `present?` to `blank?`
10
- # UnlessPresent: Convert usages of `unless` `present?` to `blank?`
6
+ # This cop checks for code that can be written with simpler conditionals
7
+ # using `Object#blank?` defined by Active Support.
11
8
  #
12
- # @example
13
- # # NilOrEmpty: true
14
- # # bad
15
- # foo.nil? || foo.empty?
16
- # foo == nil || foo.empty?
9
+ # @example NilOrEmpty: true (default)
10
+ # # Converts usages of `nil? || empty?` to `blank?`
17
11
  #
18
- # # good
19
- # foo.blank?
12
+ # # bad
13
+ # foo.nil? || foo.empty?
14
+ # foo == nil || foo.empty?
20
15
  #
21
- # # NotPresent: true
22
- # # bad
23
- # !foo.present?
16
+ # # good
17
+ # foo.blank?
24
18
  #
25
- # # good
26
- # foo.blank?
19
+ # @example NotPresent: true (default)
20
+ # # Converts usages of `!present?` to `blank?`
27
21
  #
28
- # # UnlessPresent: true
29
- # # bad
30
- # something unless foo.present?
31
- # unless foo.present?
32
- # something
33
- # end
22
+ # # bad
23
+ # !foo.present?
34
24
  #
35
- # # good
36
- # something if foo.blank?
37
- # if foo.blank?
38
- # something
39
- # end
25
+ # # good
26
+ # foo.blank?
27
+ #
28
+ # @example UnlessPresent: true (default)
29
+ # # Converts usages of `unless present?` to `if blank?`
30
+ #
31
+ # # bad
32
+ # something unless foo.present?
33
+ #
34
+ # # good
35
+ # something if foo.blank?
36
+ #
37
+ # # bad
38
+ # unless foo.present?
39
+ # something
40
+ # end
41
+ #
42
+ # # good
43
+ # if foo.blank?
44
+ # something
45
+ # end
40
46
  class Blank < Cop
41
47
  MSG_NIL_OR_EMPTY = 'Use `%<prefer>s` instead of `%<current>s`.'.freeze
42
48
  MSG_NOT_PRESENT = 'Use `%<prefer>s` instead of `%<current>s`.'.freeze
@@ -51,7 +51,7 @@ module RuboCop
51
51
  PATTERN
52
52
 
53
53
  def_node_matcher :create_table_with_timestamps_proc?, <<-PATTERN
54
- (send nil? :create_table (sym _) (block-pass (sym :timestamps)))
54
+ (send nil? :create_table (sym _) ... (block-pass (sym :timestamps)))
55
55
  PATTERN
56
56
 
57
57
  def_node_search :timestamps_included?, <<-PATTERN
@@ -63,8 +63,18 @@ module RuboCop
63
63
 
64
64
  n = node.parent.begin_type? ? node.parent.parent : node.parent
65
65
 
66
- if with_options_block(n)
67
- return true if valid_options?(with_options_block(n))
66
+ contain_valid_options_in_with_options_block?(n)
67
+ end
68
+
69
+ def contain_valid_options_in_with_options_block?(node)
70
+ if with_options_block(node)
71
+ return true if valid_options?(with_options_block(node))
72
+
73
+ return false unless node.parent
74
+
75
+ return true if contain_valid_options_in_with_options_block?(
76
+ node.parent.parent
77
+ )
68
78
  end
69
79
 
70
80
  false
@@ -22,7 +22,7 @@ module RuboCop
22
22
  MSG = 'Use keyword arguments instead of ' \
23
23
  'positional arguments for http call: `%<verb>s`.'.freeze
24
24
  KEYWORD_ARGS = %i[
25
- headers env params body flash as xhr session method
25
+ method params session body flash xhr as
26
26
  ].freeze
27
27
  HTTP_METHODS = %i[get post put patch delete head].freeze
28
28
 
@@ -41,11 +41,11 @@ module RuboCop
41
41
  end
42
42
  end
43
43
 
44
- # given a pre Rails 5 method: get :new, user_id: @user.id, {}
44
+ # given a pre Rails 5 method: get :new, {user_id: @user.id}, {}
45
45
  #
46
46
  # @return lambda of auto correct procedure
47
47
  # the result should look like:
48
- # get :new, params: { user_id: @user.id }, headers: {}
48
+ # get :new, params: { user_id: @user.id }, session: {}
49
49
  # the http_method is the method used to call the controller
50
50
  # the controller node can be a symbol, method, object or string
51
51
  # that represents the path/action on the Rails controller
@@ -56,14 +56,14 @@ module RuboCop
56
56
 
57
57
  controller_action = http_path.source
58
58
  params = convert_hash_data(data.first, 'params')
59
- headers = convert_hash_data(data.last, 'headers') if data.size > 1
59
+ session = convert_hash_data(data.last, 'session') if data.size > 1
60
60
  # the range of the text to replace, which is the whole line
61
61
  code_to_replace = node.loc.expression
62
62
  # what to replace with
63
63
  format = parentheses_format(node)
64
64
  new_code = format(format, name: node.method_name,
65
65
  action: controller_action,
66
- params: params, headers: headers)
66
+ params: params, session: session)
67
67
  ->(corrector) { corrector.replace(code_to_replace, new_code) }
68
68
  end
69
69
 
@@ -103,9 +103,9 @@ module RuboCop
103
103
 
104
104
  def parentheses_format(node)
105
105
  if parentheses?(node)
106
- '%<name>s(%<action>s%<params>s%<headers>s)'
106
+ '%<name>s(%<action>s%<params>s%<session>s)'
107
107
  else
108
- '%<name>s %<action>s%<params>s%<headers>s'
108
+ '%<name>s %<action>s%<params>s%<session>s'
109
109
  end
110
110
  end
111
111
  end
@@ -3,37 +3,43 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cops checks for code that can be changed to `blank?`.
7
- # Settings:
8
- # NotNilAndNotEmpty: Convert checks for not `nil` and `not empty?`
9
- # to `present?`
10
- # NotBlank: Convert usages of not `blank?` to `present?`
11
- # UnlessBlank: Convert usages of `unless` `blank?` to `if` `present?`
6
+ # This cop checks for code that can be written with simpler conditionals
7
+ # using `Object#present?` defined by Active Support.
12
8
  #
13
- # @example
14
- # # NotNilAndNotEmpty: true
15
- # # bad
16
- # !foo.nil? && !foo.empty?
17
- # foo != nil && !foo.empty?
18
- # !foo.blank?
9
+ # simpler conditionals.
19
10
  #
20
- # # good
21
- # foo.present?
11
+ # @example NotNilAndNotEmpty: true (default)
12
+ # # Converts usages of `!nil? && !empty?` to `present?`
22
13
  #
23
- # # NotBlank: true
24
- # # bad
25
- # !foo.blank?
26
- # not foo.blank?
14
+ # # bad
15
+ # !foo.nil? && !foo.empty?
27
16
  #
28
- # # good
29
- # foo.present?
17
+ # # bad
18
+ # foo != nil && !foo.empty?
30
19
  #
31
- # # UnlessBlank: true
32
- # # bad
33
- # something unless foo.blank?
20
+ # # good
21
+ # foo.present?
34
22
  #
35
- # # good
36
- # something if foo.present?
23
+ # @example NotBlank: true (default)
24
+ # # Converts usages of `!blank?` to `present?`
25
+ #
26
+ # # bad
27
+ # !foo.blank?
28
+ #
29
+ # # bad
30
+ # not foo.blank?
31
+ #
32
+ # # good
33
+ # foo.present?
34
+ #
35
+ # @example UnlessBlank: true (default)
36
+ # # Converts usages of `unless blank?` to `if present?`
37
+ #
38
+ # # bad
39
+ # something unless foo.blank?
40
+ #
41
+ # # good
42
+ # something if foo.present?
37
43
  class Present < Cop
38
44
  MSG_NOT_BLANK = 'Use `%<prefer>s` instead of `%<current>s`.'.freeze
39
45
  MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of ' \