rubocop 0.45.0 → 0.46.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +17 -0
  4. data/config/enabled.yml +29 -2
  5. data/lib/rubocop.rb +6 -1
  6. data/lib/rubocop/config.rb +0 -10
  7. data/lib/rubocop/config_loader.rb +21 -9
  8. data/lib/rubocop/cop/bundler/duplicated_gem.rb +69 -0
  9. data/lib/rubocop/cop/bundler/ordered_gems.rb +54 -0
  10. data/lib/rubocop/cop/cop.rb +1 -0
  11. data/lib/rubocop/cop/lint/debugger.rb +9 -1
  12. data/lib/rubocop/cop/lint/each_with_object_argument.rb +5 -6
  13. data/lib/rubocop/cop/lint/eval.rb +3 -7
  14. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +6 -4
  15. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +13 -4
  16. data/lib/rubocop/cop/lint/useless_comparison.rb +5 -9
  17. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -0
  18. data/lib/rubocop/cop/metrics/line_length.rb +16 -3
  19. data/lib/rubocop/cop/mixin/access_modifier_node.rb +9 -9
  20. data/lib/rubocop/cop/mixin/configurable_numbering.rb +14 -7
  21. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +92 -20
  22. data/lib/rubocop/cop/performance/compare_with_block.rb +61 -0
  23. data/lib/rubocop/cop/performance/count.rb +21 -57
  24. data/lib/rubocop/cop/performance/detect.rb +15 -15
  25. data/lib/rubocop/cop/performance/flat_map.rb +23 -35
  26. data/lib/rubocop/cop/performance/sample.rb +84 -82
  27. data/lib/rubocop/cop/performance/string_replacement.rb +18 -43
  28. data/lib/rubocop/cop/rails/enum_uniqueness.rb +71 -0
  29. data/lib/rubocop/cop/rails/http_positional_arguments.rb +1 -1
  30. data/lib/rubocop/cop/rails/output.rb +8 -12
  31. data/lib/rubocop/cop/rails/read_write_attribute.rb +10 -6
  32. data/lib/rubocop/cop/rails/request_referer.rb +8 -9
  33. data/lib/rubocop/cop/rails/scope_args.rb +5 -11
  34. data/lib/rubocop/cop/style/access_modifier_indentation.rb +1 -1
  35. data/lib/rubocop/cop/style/and_or.rb +1 -1
  36. data/lib/rubocop/cop/style/array_join.rb +4 -8
  37. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  38. data/lib/rubocop/cop/style/case_equality.rb +3 -3
  39. data/lib/rubocop/cop/style/character_literal.rb +2 -4
  40. data/lib/rubocop/cop/style/class_check.rb +6 -6
  41. data/lib/rubocop/cop/style/colon_method_call.rb +6 -6
  42. data/lib/rubocop/cop/style/each_with_object.rb +13 -17
  43. data/lib/rubocop/cop/style/empty_literal.rb +46 -36
  44. data/lib/rubocop/cop/style/empty_method.rb +96 -0
  45. data/lib/rubocop/cop/style/even_odd.rb +19 -50
  46. data/lib/rubocop/cop/style/hash_syntax.rb +4 -1
  47. data/lib/rubocop/cop/style/lambda.rb +8 -18
  48. data/lib/rubocop/cop/style/module_function.rb +14 -11
  49. data/lib/rubocop/cop/style/nil_comparison.rb +4 -7
  50. data/lib/rubocop/cop/style/non_nil_check.rb +18 -36
  51. data/lib/rubocop/cop/style/numeric_predicate.rb +9 -10
  52. data/lib/rubocop/cop/style/op_method.rb +7 -9
  53. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  54. data/lib/rubocop/cop/style/proc.rb +5 -9
  55. data/lib/rubocop/cop/style/redundant_freeze.rb +6 -7
  56. data/lib/rubocop/cop/style/send.rb +6 -3
  57. data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
  58. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  59. data/lib/rubocop/cop/style/symbol_proc.rb +22 -43
  60. data/lib/rubocop/cop/style/ternary_parentheses.rb +67 -18
  61. data/lib/rubocop/cop/util.rb +1 -1
  62. data/lib/rubocop/cop/variable_force/assignment.rb +2 -0
  63. data/lib/rubocop/cop/variable_force/locatable.rb +8 -6
  64. data/lib/rubocop/cop/variable_force/reference.rb +2 -0
  65. data/lib/rubocop/formatter/base_formatter.rb +4 -8
  66. data/lib/rubocop/formatter/fuubar_style_formatter.rb +6 -0
  67. data/lib/rubocop/node_pattern.rb +7 -5
  68. data/lib/rubocop/processed_source.rb +1 -0
  69. data/lib/rubocop/rspec/cop_helper.rb +4 -0
  70. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +1 -1
  71. data/lib/rubocop/version.rb +1 -1
  72. metadata +7 -3
  73. data/lib/rubocop/cop/performance/sort_with_block.rb +0 -53
@@ -28,18 +28,25 @@ module RuboCop
28
28
  MSG = 'Use `%s` instead of `%s.%s`.'.freeze
29
29
  REVERSE_MSG = 'Use `reverse.%s` instead of `%s.%s`.'.freeze
30
30
 
31
- SELECT_METHODS = [:select, :find_all].freeze
32
- DANGEROUS_METHODS = [:first, :last].freeze
31
+ def_node_matcher :detect_candidate?, <<-PATTERN
32
+ {
33
+ (send $(block (send _ {:select :find_all}) ...) ${:first :last} $...)
34
+ (send $(send _ {:select :find_all} ...) ${:first :last} $...)
35
+ }
36
+ PATTERN
33
37
 
34
38
  def on_send(node)
35
39
  return if rails_safe_mode?
36
- receiver, second_method, *args = *node
37
- return if accept_second_call?(receiver, second_method, args)
38
40
 
39
- receiver, _args, body = *receiver if receiver.block_type?
40
- return if accept_first_call?(receiver, body)
41
+ detect_candidate?(node) do |receiver, second_method, args|
42
+ return unless args.empty?
43
+ return unless receiver
41
44
 
42
- offense(node, receiver, second_method)
45
+ receiver, _args, body = *receiver if receiver.block_type?
46
+ return if accept_first_call?(receiver, body)
47
+
48
+ offense(node, receiver, second_method)
49
+ end
43
50
  end
44
51
 
45
52
  def autocorrect(node)
@@ -63,18 +70,11 @@ module RuboCop
63
70
 
64
71
  private
65
72
 
66
- def accept_second_call?(receiver, method, args)
67
- !receiver ||
68
- !DANGEROUS_METHODS.include?(method) ||
69
- !args.empty?
70
- end
71
-
72
73
  def accept_first_call?(receiver, body)
73
- caller, first_method, args = *receiver
74
+ caller, _first_method, args = *receiver
74
75
 
75
76
  # check that we have usual block or block pass
76
77
  return true if body.nil? && (args.nil? || !args.block_pass_type?)
77
- return true unless SELECT_METHODS.include?(first_method)
78
78
 
79
79
  lazy?(caller)
80
80
  end
@@ -19,65 +19,53 @@ module RuboCop
19
19
  FLATTEN_MULTIPLE_LEVELS = ' Beware, `flat_map` only flattens 1 level ' \
20
20
  'and `flatten` can be used to flatten ' \
21
21
  'multiple levels.'.freeze
22
- FLATTEN_METHODS = [:flatten, :flatten!].freeze
23
- MAP_METHODS = [:map, :collect].freeze
24
22
 
25
- def on_send(node)
26
- left, second_method, flatten_param = *node
27
- return unless flatten_method?(second_method)
28
-
29
- flatten_level, = *flatten_param
30
- expression, = *left
31
- _array, first_method = *expression
32
- return unless map_method?(first_method)
23
+ def_node_matcher :flat_map_candidate?, <<-PATTERN
24
+ (send (block $(send _ ${:collect :map}) ...) ${:flatten :flatten!} $...)
25
+ PATTERN
33
26
 
34
- if cop_config['EnabledForFlattenWithoutParams'] && flatten_level.nil?
35
- offense_for_levels(node, expression, first_method, second_method)
36
- elsif flatten_level == 1
37
- offense_for_method(node, expression, first_method, second_method)
27
+ def on_send(node)
28
+ flat_map_candidate?(node) do |map_node, first_method, flatten, params|
29
+ flatten_level, = *params.first
30
+ if cop_config['EnabledForFlattenWithoutParams'] &&
31
+ flatten_level.nil?
32
+ offense_for_levels(node, map_node, first_method, flatten)
33
+ elsif flatten_level == 1
34
+ offense_for_method(node, map_node, first_method, flatten)
35
+ end
38
36
  end
39
37
  end
40
38
 
41
39
  def autocorrect(node)
42
- receiver, _flatten, flatten_param = *node
43
- flatten_level, = *flatten_param
40
+ map_node, _first_method, _flatten, params = flat_map_candidate?(node)
41
+ flatten_level, = *params.first
44
42
  return if flatten_level.nil?
45
43
 
46
- array, = *receiver
47
-
48
44
  lambda do |corrector|
49
45
  range = range_between(node.loc.dot.begin_pos,
50
46
  node.source_range.end_pos)
51
47
 
52
48
  corrector.remove(range)
53
- corrector.replace(array.loc.selector, 'flat_map')
49
+ corrector.replace(map_node.loc.selector, 'flat_map')
54
50
  end
55
51
  end
56
52
 
57
53
  private
58
54
 
59
- def flatten_method?(method_name)
60
- FLATTEN_METHODS.include?(method_name)
61
- end
62
-
63
- def map_method?(method_name)
64
- MAP_METHODS.include?(method_name)
65
- end
66
-
67
- def offense_for_levels(node, expression, first_method, second_method)
55
+ def offense_for_levels(node, map_node, first_method, flatten)
68
56
  message = MSG + FLATTEN_MULTIPLE_LEVELS
69
- offense(node, expression, first_method, second_method, message)
57
+ offense(node, map_node, first_method, flatten, message)
70
58
  end
71
59
 
72
- def offense_for_method(node, expression, first_method, second_method)
73
- offense(node, expression, first_method, second_method, MSG)
60
+ def offense_for_method(node, map_node, first_method, flatten)
61
+ offense(node, map_node, first_method, flatten, MSG)
74
62
  end
75
63
 
76
- def offense(node, expression, first_method, second_method, message)
77
- range = range_between(expression.loc.selector.begin_pos,
78
- node.loc.selector.end_pos)
64
+ def offense(node, map_node, first_method, flatten, message)
65
+ range = range_between(map_node.loc.selector.begin_pos,
66
+ node.loc.expression.end_pos)
79
67
 
80
- add_offense(node, range, format(message, first_method, second_method))
68
+ add_offense(node, range, format(message, first_method, flatten))
81
69
  end
82
70
  end
83
71
  end
@@ -27,110 +27,112 @@ module RuboCop
27
27
  class Sample < Cop
28
28
  MSG = 'Use `%<correct>s` instead of `%<incorrect>s`.'.freeze
29
29
 
30
- def on_send(node)
31
- analyzer = ShuffleAnalyzer.new(node)
32
- return unless analyzer.offensive?
33
- add_offense(node, analyzer.source_range, analyzer.message)
34
- end
35
-
36
- def autocorrect(node)
37
- ShuffleAnalyzer.new(node).autocorrect
38
- end
39
-
40
- # An internal class for representing a shuffle + method node analyzer.
41
- class ShuffleAnalyzer
42
- def initialize(shuffle_node)
43
- @shuffle_node = shuffle_node
44
- @method_node = shuffle_node.parent
45
- end
30
+ def_node_matcher :sample_candidate?, <<-PATTERN
31
+ (send $(send _ :shuffle $...) ${:first :last :[]} $...)
32
+ PATTERN
46
33
 
47
- def autocorrect
48
- ->(corrector) { corrector.replace(source_range, correct) }
49
- end
34
+ def on_send(node)
35
+ sample_candidate?(node) do |shuffle, shuffle_arg, method, method_args|
36
+ return unless offensive?(method, method_args)
50
37
 
51
- def message
52
- format(MSG, correct: correct, incorrect: source_range.source)
38
+ range = source_range(shuffle, node)
39
+ message = message(shuffle_arg, method, method_args, range)
40
+ add_offense(node, range, message)
53
41
  end
42
+ end
54
43
 
55
- def offensive?
56
- shuffle_node.to_a[1] == :shuffle && corrigible?
57
- end
44
+ def autocorrect(node)
45
+ shuffle_node, shuffle_arg, method, method_args =
46
+ sample_candidate?(node)
58
47
 
59
- def source_range
60
- Parser::Source::Range.new(shuffle_node.source_range.source_buffer,
61
- shuffle_node.loc.selector.begin_pos,
62
- method_node.source_range.end_pos)
48
+ lambda do |corrector|
49
+ corrector.replace(source_range(shuffle_node, node),
50
+ correction(shuffle_arg, method, method_args))
63
51
  end
52
+ end
64
53
 
65
- private
66
-
67
- attr_reader :method_node, :shuffle_node
54
+ private
68
55
 
69
- def correct
70
- args = [sample_arg, shuffle_arg].compact.join(', ')
71
- args.empty? ? 'sample' : "sample(#{args})"
56
+ def offensive?(method, method_args)
57
+ case method
58
+ when :first, :last
59
+ true
60
+ when :[]
61
+ sample_size(method_args) != :unknown
62
+ else
63
+ false
72
64
  end
65
+ end
73
66
 
74
- def corrigible?
75
- case method
76
- when :first, :last then true
77
- when :[] then sample_size != :unknown
78
- else false
79
- end
67
+ def sample_size(method_args)
68
+ case method_args.size
69
+ when 1
70
+ sample_size_for_one_arg(method_args.first)
71
+ when 2
72
+ sample_size_for_two_args(*method_args)
80
73
  end
74
+ end
81
75
 
82
- def method
83
- method_node.to_a[1]
76
+ def sample_size_for_one_arg(arg)
77
+ case arg.type
78
+ when :erange, :irange
79
+ range_size(arg)
80
+ when :int
81
+ arg.to_a.first.zero? ? nil : :unknown
82
+ else
83
+ :unknown
84
84
  end
85
+ end
85
86
 
86
- def method_arg
87
- _, _, arg = *method_node
88
- arg.source if arg
89
- end
87
+ def sample_size_for_two_args(first, second)
88
+ return :unknown unless first.int_type? && first.to_a.first.zero?
89
+ second.int_type? ? second.to_a.first : :unknown
90
+ end
90
91
 
91
- def range_size(range_node)
92
- vals = *range_node
93
- return :unknown unless vals.all?(&:int_type?)
94
- low, high = *vals.map { |val| val.to_a.first }
95
- return :unknown unless low.zero? && high >= 0
96
- case range_node.type
97
- when :erange then high - low
98
- when :irange then high - low + 1
99
- end
92
+ def range_size(range_node)
93
+ vals = range_node.to_a
94
+ return :unknown unless vals.all?(&:int_type?)
95
+ low, high = vals.map { |val| val.children[0] }
96
+ return :unknown unless low.zero? && high >= 0
97
+
98
+ case range_node.type
99
+ when :erange
100
+ (low...high).size
101
+ when :irange
102
+ (low..high).size
100
103
  end
104
+ end
101
105
 
102
- def sample_arg
103
- case method
104
- when :first, :last then method_arg
105
- when :[] then sample_size
106
- end
107
- end
106
+ def source_range(shuffle_node, node)
107
+ Parser::Source::Range.new(shuffle_node.source_range.source_buffer,
108
+ shuffle_node.loc.selector.begin_pos,
109
+ node.source_range.end_pos)
110
+ end
108
111
 
109
- def sample_size
110
- _, _, *args = *method_node
111
- case args.size
112
- when 1 then sample_size_for_one_arg(args.first)
113
- when 2 then sample_size_for_two_args(*args)
114
- end
115
- end
112
+ def message(shuffle_arg, method, method_args, range)
113
+ format(MSG,
114
+ correct: correction(shuffle_arg, method, method_args),
115
+ incorrect: range.source)
116
+ end
116
117
 
117
- def sample_size_for_one_arg(arg)
118
- case arg.type
119
- when :erange, :irange then range_size(arg)
120
- when :int then arg.to_a.first.zero? ? nil : :unknown
121
- else :unknown
122
- end
123
- end
118
+ def correction(shuffle_arg, method, method_args)
119
+ shuffle_arg = extract_source(shuffle_arg)
120
+ sample_arg = sample_arg(method, method_args)
121
+ args = [sample_arg, shuffle_arg].compact.join(', ')
122
+ args.empty? ? 'sample' : "sample(#{args})"
123
+ end
124
124
 
125
- def sample_size_for_two_args(first, second)
126
- return :unknown unless first.int_type? && first.to_a.first.zero?
127
- second.int_type? ? second.to_a.first : :unknown
125
+ def sample_arg(method, method_args)
126
+ case method
127
+ when :first, :last
128
+ extract_source(method_args)
129
+ when :[]
130
+ sample_size(method_args)
128
131
  end
132
+ end
129
133
 
130
- def shuffle_arg
131
- _, _, arg = *shuffle_node
132
- arg.source if arg
133
- end
134
+ def extract_source(args)
135
+ args.empty? ? nil : args.first.source
134
136
  end
135
137
  end
136
138
  end
@@ -21,22 +21,24 @@ module RuboCop
21
21
  class StringReplacement < Cop
22
22
  MSG = 'Use `%s` instead of `%s`.'.freeze
23
23
  DETERMINISTIC_REGEX = /\A(?:#{LITERAL_REGEX})+\Z/
24
- REGEXP_CONSTRUCTOR_METHODS = [:new, :compile].freeze
25
- GSUB_METHODS = [:gsub, :gsub!].freeze
26
- DETERMINISTIC_TYPES = [:regexp, :str, :send].freeze
27
24
  DELETE = 'delete'.freeze
28
25
  TR = 'tr'.freeze
29
26
  BANG = '!'.freeze
30
27
  SINGLE_QUOTE = "'".freeze
31
28
 
32
- def on_send(node)
33
- _string, method, first_param, second_param = *node
29
+ def_node_matcher :string_replacement?, <<-PATTERN
30
+ (send _ ${:gsub :gsub!}
31
+ ${regexp str (send (const nil :Regexp) {:new :compile} _)}
32
+ $str)
33
+ PATTERN
34
34
 
35
- return unless GSUB_METHODS.include?(method)
36
- return if accept_second_param?(second_param)
37
- return if accept_first_param?(first_param)
35
+ def on_send(node)
36
+ string_replacement?(node) do |method, first_param, second_param|
37
+ return if accept_second_param?(second_param)
38
+ return if accept_first_param?(first_param)
38
39
 
39
- offense(node, method, first_param, second_param)
40
+ offense(node, method, first_param, second_param)
41
+ end
40
42
  end
41
43
 
42
44
  def autocorrect(node)
@@ -44,7 +46,7 @@ module RuboCop
44
46
  first_source, = first_source(first_param)
45
47
  second_source, = *second_param
46
48
 
47
- if regex?(first_param)
49
+ unless first_param.str_type?
48
50
  first_source = interpret_string_escapes(first_source)
49
51
  end
50
52
 
@@ -72,19 +74,15 @@ module RuboCop
72
74
  private
73
75
 
74
76
  def accept_second_param?(second_param)
75
- return true unless string?(second_param)
76
77
  second_source, = *second_param
77
-
78
78
  second_source.length > 1
79
79
  end
80
80
 
81
81
  def accept_first_param?(first_param)
82
- return true unless DETERMINISTIC_TYPES.include?(first_param.type)
83
-
84
82
  first_source, options = first_source(first_param)
85
83
  return true if first_source.nil?
86
84
 
87
- if regex?(first_param)
85
+ unless first_param.str_type?
88
86
  return true if options
89
87
  return true unless first_source =~ DETERMINISTIC_REGEX
90
88
  # This must be done after checking DETERMINISTIC_REGEX
@@ -97,7 +95,7 @@ module RuboCop
97
95
 
98
96
  def offense(node, method, first_param, second_param)
99
97
  first_source, = first_source(first_param)
100
- if regex?(first_param)
98
+ unless first_param.str_type?
101
99
  first_source = interpret_string_escapes(first_source)
102
100
  end
103
101
  second_source, = *second_param
@@ -106,28 +104,14 @@ module RuboCop
106
104
  add_offense(node, range(node), message)
107
105
  end
108
106
 
109
- def string?(node)
110
- node && node.str_type?
111
- end
112
-
113
107
  def first_source(first_param)
114
108
  case first_param.type
115
- when :regexp, :send
116
- return nil unless regex?(first_param)
117
- source, options = extract_source(first_param)
118
- when :str
119
- source, = *first_param
120
- end
121
-
122
- [source, options]
123
- end
124
-
125
- def extract_source(node)
126
- case node.type
127
109
  when :regexp
128
- source_from_regex_literal(node)
110
+ source_from_regex_literal(first_param)
129
111
  when :send
130
- source_from_regex_constructor(node)
112
+ source_from_regex_constructor(first_param)
113
+ when :str
114
+ first_param.children.first
131
115
  end
132
116
  end
133
117
 
@@ -149,15 +133,6 @@ module RuboCop
149
133
  end
150
134
  end
151
135
 
152
- def regex?(node)
153
- return true if node.regexp_type?
154
-
155
- const, init, = *node
156
- _, klass = *const
157
-
158
- klass == :Regexp && REGEXP_CONSTRUCTOR_METHODS.include?(init)
159
- end
160
-
161
136
  def range(node)
162
137
  range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
163
138
  end