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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +17 -0
- data/config/enabled.yml +29 -2
- data/lib/rubocop.rb +6 -1
- data/lib/rubocop/config.rb +0 -10
- data/lib/rubocop/config_loader.rb +21 -9
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +69 -0
- data/lib/rubocop/cop/bundler/ordered_gems.rb +54 -0
- data/lib/rubocop/cop/cop.rb +1 -0
- data/lib/rubocop/cop/lint/debugger.rb +9 -1
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +5 -6
- data/lib/rubocop/cop/lint/eval.rb +3 -7
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +6 -4
- data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +13 -4
- data/lib/rubocop/cop/lint/useless_comparison.rb +5 -9
- data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -0
- data/lib/rubocop/cop/metrics/line_length.rb +16 -3
- data/lib/rubocop/cop/mixin/access_modifier_node.rb +9 -9
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +14 -7
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +92 -20
- data/lib/rubocop/cop/performance/compare_with_block.rb +61 -0
- data/lib/rubocop/cop/performance/count.rb +21 -57
- data/lib/rubocop/cop/performance/detect.rb +15 -15
- data/lib/rubocop/cop/performance/flat_map.rb +23 -35
- data/lib/rubocop/cop/performance/sample.rb +84 -82
- data/lib/rubocop/cop/performance/string_replacement.rb +18 -43
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +71 -0
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +1 -1
- data/lib/rubocop/cop/rails/output.rb +8 -12
- data/lib/rubocop/cop/rails/read_write_attribute.rb +10 -6
- data/lib/rubocop/cop/rails/request_referer.rb +8 -9
- data/lib/rubocop/cop/rails/scope_args.rb +5 -11
- data/lib/rubocop/cop/style/access_modifier_indentation.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/array_join.rb +4 -8
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/case_equality.rb +3 -3
- data/lib/rubocop/cop/style/character_literal.rb +2 -4
- data/lib/rubocop/cop/style/class_check.rb +6 -6
- data/lib/rubocop/cop/style/colon_method_call.rb +6 -6
- data/lib/rubocop/cop/style/each_with_object.rb +13 -17
- data/lib/rubocop/cop/style/empty_literal.rb +46 -36
- data/lib/rubocop/cop/style/empty_method.rb +96 -0
- data/lib/rubocop/cop/style/even_odd.rb +19 -50
- data/lib/rubocop/cop/style/hash_syntax.rb +4 -1
- data/lib/rubocop/cop/style/lambda.rb +8 -18
- data/lib/rubocop/cop/style/module_function.rb +14 -11
- data/lib/rubocop/cop/style/nil_comparison.rb +4 -7
- data/lib/rubocop/cop/style/non_nil_check.rb +18 -36
- data/lib/rubocop/cop/style/numeric_predicate.rb +9 -10
- data/lib/rubocop/cop/style/op_method.rb +7 -9
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/proc.rb +5 -9
- data/lib/rubocop/cop/style/redundant_freeze.rb +6 -7
- data/lib/rubocop/cop/style/send.rb +6 -3
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
- data/lib/rubocop/cop/style/symbol_proc.rb +22 -43
- data/lib/rubocop/cop/style/ternary_parentheses.rb +67 -18
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +2 -0
- data/lib/rubocop/cop/variable_force/locatable.rb +8 -6
- data/lib/rubocop/cop/variable_force/reference.rb +2 -0
- data/lib/rubocop/formatter/base_formatter.rb +4 -8
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +6 -0
- data/lib/rubocop/node_pattern.rb +7 -5
- data/lib/rubocop/processed_source.rb +1 -0
- data/lib/rubocop/rspec/cop_helper.rb +4 -0
- data/lib/rubocop/rspec/host_environment_simulation_helper.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +7 -3
- 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
|
-
|
32
|
-
|
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,
|
40
|
-
|
41
|
+
detect_candidate?(node) do |receiver, second_method, args|
|
42
|
+
return unless args.empty?
|
43
|
+
return unless receiver
|
41
44
|
|
42
|
-
|
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,
|
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
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
43
|
-
flatten_level, = *
|
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(
|
49
|
+
corrector.replace(map_node.loc.selector, 'flat_map')
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
57
53
|
private
|
58
54
|
|
59
|
-
def
|
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,
|
57
|
+
offense(node, map_node, first_method, flatten, message)
|
70
58
|
end
|
71
59
|
|
72
|
-
def offense_for_method(node,
|
73
|
-
offense(node,
|
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,
|
77
|
-
range = range_between(
|
78
|
-
node.loc.
|
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,
|
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
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
52
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
44
|
+
def autocorrect(node)
|
45
|
+
shuffle_node, shuffle_arg, method, method_args =
|
46
|
+
sample_candidate?(node)
|
58
47
|
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
66
|
-
|
67
|
-
attr_reader :method_node, :shuffle_node
|
54
|
+
private
|
68
55
|
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
83
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
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
|
-
|
131
|
-
|
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
|
-
|
33
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
110
|
+
source_from_regex_literal(first_param)
|
129
111
|
when :send
|
130
|
-
source_from_regex_constructor(
|
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
|