rubocop 1.41.0 → 1.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +26 -1
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +7 -7
- data/lib/rubocop/config_loader_resolver.rb +5 -1
- data/lib/rubocop/cop/base.rb +62 -61
- data/lib/rubocop/cop/cop.rb +28 -28
- data/lib/rubocop/cop/corrector.rb +23 -11
- data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
- data/lib/rubocop/cop/layout/class_structure.rb +32 -11
- data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +6 -6
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -2
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
- data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -3
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -4
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/registry.rb +22 -22
- data/lib/rubocop/cop/security/compound_hash.rb +2 -1
- data/lib/rubocop/cop/style/alias.rb +9 -1
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +22 -2
- data/lib/rubocop/cop/style/documentation.rb +10 -4
- data/lib/rubocop/cop/style/guard_clause.rb +12 -8
- data/lib/rubocop/cop/style/hash_syntax.rb +10 -7
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
- data/lib/rubocop/cop/style/map_to_set.rb +61 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
- data/lib/rubocop/cop/style/min_max_comparison.rb +73 -0
- data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
- data/lib/rubocop/cop/style/require_order.rb +4 -2
- data/lib/rubocop/cop/style/select_by_regexp.rb +6 -2
- data/lib/rubocop/cop/style/signal_exception.rb +8 -6
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
- data/lib/rubocop/cop/style/word_array.rb +41 -0
- data/lib/rubocop/cop/style/yoda_expression.rb +74 -0
- data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
- data/lib/rubocop/cop/team.rb +29 -29
- data/lib/rubocop/cop/variable_force.rb +0 -3
- data/lib/rubocop/cops_documentation_generator.rb +11 -8
- data/lib/rubocop/formatter.rb +2 -0
- data/lib/rubocop/path_util.rb +6 -1
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +10 -3
- data/lib/rubocop/target_ruby.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +12 -9
@@ -256,7 +256,7 @@ module RuboCop
|
|
256
256
|
# regular dotted method calls bind more tightly than operators
|
257
257
|
# so we need to climb up the AST past them
|
258
258
|
node.each_ancestor do |ancestor|
|
259
|
-
return true if ancestor.and_type? || ancestor.or_type?
|
259
|
+
return true if ancestor.and_type? || ancestor.or_type? || ancestor.range_type?
|
260
260
|
return false unless ancestor.send_type?
|
261
261
|
return true if ancestor.operator_method?
|
262
262
|
end
|
@@ -47,7 +47,6 @@ module RuboCop
|
|
47
47
|
MSG = 'Trailing whitespace detected.'
|
48
48
|
|
49
49
|
def on_new_investigation
|
50
|
-
@heredocs = extract_heredocs(processed_source.ast)
|
51
50
|
processed_source.lines.each_with_index do |line, index|
|
52
51
|
next unless line.end_with?(' ', "\t")
|
53
52
|
|
@@ -102,10 +101,14 @@ module RuboCop
|
|
102
101
|
end
|
103
102
|
|
104
103
|
def find_heredoc(line_number)
|
105
|
-
|
104
|
+
heredocs.each { |node, r| return node if r.include?(line_number) }
|
106
105
|
nil
|
107
106
|
end
|
108
107
|
|
108
|
+
def heredocs
|
109
|
+
@heredocs ||= extract_heredocs(processed_source.ast)
|
110
|
+
end
|
111
|
+
|
109
112
|
def extract_heredocs(ast)
|
110
113
|
return [] unless ast
|
111
114
|
|
@@ -68,6 +68,12 @@ module RuboCop
|
|
68
68
|
@valid_ref = regexp_conditions.map { |condition| check_regexp(condition) }.compact.max
|
69
69
|
end
|
70
70
|
|
71
|
+
def on_in_pattern(node)
|
72
|
+
regexp_patterns = patterns(node).select(&:regexp_type?)
|
73
|
+
|
74
|
+
@valid_ref = regexp_patterns.map { |pattern| check_regexp(pattern) }.compact.max
|
75
|
+
end
|
76
|
+
|
71
77
|
def on_nth_ref(node)
|
72
78
|
backref, = *node
|
73
79
|
return if @valid_ref.nil? || backref <= @valid_ref
|
@@ -84,6 +90,19 @@ module RuboCop
|
|
84
90
|
|
85
91
|
private
|
86
92
|
|
93
|
+
def patterns(pattern_node)
|
94
|
+
pattern = pattern_node.node_parts[0]
|
95
|
+
|
96
|
+
case pattern.type
|
97
|
+
when :array_pattern, :match_alt
|
98
|
+
pattern.children
|
99
|
+
when :match_as
|
100
|
+
patterns(pattern)
|
101
|
+
else
|
102
|
+
[pattern]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
87
106
|
def check_regexp(node)
|
88
107
|
return if node.interpolation?
|
89
108
|
|
@@ -128,6 +128,7 @@ module RuboCop
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
131
132
|
def each_already_disabled(cop, line_ranges)
|
132
133
|
line_ranges.each_cons(2) do |previous_range, range|
|
133
134
|
next if ignore_offense?(range)
|
@@ -152,9 +153,10 @@ module RuboCop
|
|
152
153
|
cop
|
153
154
|
end
|
154
155
|
|
155
|
-
yield comment, redundant
|
156
|
+
yield comment, redundant if redundant
|
156
157
|
end
|
157
158
|
end
|
159
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
158
160
|
|
159
161
|
def find_redundant_cop(cop, range)
|
160
162
|
cop_offenses = offenses_to_check.select { |offense| offense.cop_name == cop }
|
@@ -17,13 +17,19 @@ module RuboCop
|
|
17
17
|
# do_something
|
18
18
|
# end
|
19
19
|
class RegexpAsCondition < Base
|
20
|
+
include IgnoredNode
|
20
21
|
extend AutoCorrector
|
21
22
|
|
22
23
|
MSG = 'Do not use regexp literal as a condition. ' \
|
23
24
|
'The regexp literal matches `$_` implicitly.'
|
24
25
|
|
25
26
|
def on_match_current_line(node)
|
27
|
+
return if node.ancestors.none?(&:conditional?)
|
28
|
+
return if part_of_ignored_node?(node)
|
29
|
+
|
26
30
|
add_offense(node) { |corrector| corrector.replace(node, "#{node.source} =~ $_") }
|
31
|
+
|
32
|
+
ignore_node(node)
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
@@ -46,7 +46,9 @@ module RuboCop
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def check_ternary(ternary, node)
|
49
|
-
|
49
|
+
if node.method?(:[]) || node.assignment_method? || !ternary.condition.operator_keyword?
|
50
|
+
return
|
51
|
+
end
|
50
52
|
|
51
53
|
range = range_between(node.source_range.begin_pos, ternary.condition.source_range.end_pos)
|
52
54
|
|
@@ -100,7 +100,8 @@ module RuboCop
|
|
100
100
|
|
101
101
|
unless variable.keyword_argument?
|
102
102
|
message << " If it's necessary, use `_` or `_#{variable.name}` " \
|
103
|
-
"as an argument name to indicate that it won't be used."
|
103
|
+
"as an argument name to indicate that it won't be used. " \
|
104
|
+
"If it's unnecessary, remove it."
|
104
105
|
end
|
105
106
|
|
106
107
|
scope = variable.scope
|
@@ -77,10 +77,12 @@ module RuboCop
|
|
77
77
|
PATTERN
|
78
78
|
|
79
79
|
def on_send(node)
|
80
|
-
|
81
|
-
|
80
|
+
return unless (first_argument = node.first_argument)
|
81
|
+
|
82
|
+
if first_argument.def_type?
|
83
|
+
inspect_def(node, first_argument)
|
82
84
|
elsif node.first_argument.sym_type?
|
83
|
-
inspect_sym(node,
|
85
|
+
inspect_sym(node, first_argument)
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
@@ -25,15 +25,15 @@ module RuboCop
|
|
25
25
|
# > http://c2.com/cgi/wiki?AbcMetric
|
26
26
|
CONDITION_NODES = CyclomaticComplexity::COUNTED_NODES.freeze
|
27
27
|
|
28
|
-
def self.calculate(node, discount_repeated_attributes: false)
|
29
|
-
new(node, discount_repeated_attributes: discount_repeated_attributes).calculate
|
30
|
-
end
|
31
|
-
|
32
28
|
# TODO: move to rubocop-ast
|
33
29
|
ARGUMENT_TYPES = %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg].freeze
|
34
30
|
|
35
31
|
private_constant :BRANCH_NODES, :CONDITION_NODES, :ARGUMENT_TYPES
|
36
32
|
|
33
|
+
def self.calculate(node, discount_repeated_attributes: false)
|
34
|
+
new(node, discount_repeated_attributes: discount_repeated_attributes).calculate
|
35
|
+
end
|
36
|
+
|
37
37
|
def initialize(node)
|
38
38
|
@assignment = 0
|
39
39
|
@branch = 0
|
@@ -47,7 +47,7 @@ module RuboCop
|
|
47
47
|
match.captures
|
48
48
|
end
|
49
49
|
|
50
|
-
KEYWORDS_REGEX_CACHE = {} # rubocop:disable
|
50
|
+
KEYWORDS_REGEX_CACHE = {} # rubocop:disable Style/MutableConstant
|
51
51
|
private_constant :KEYWORDS_REGEX_CACHE
|
52
52
|
|
53
53
|
def regex
|
@@ -175,7 +175,7 @@ module RuboCop
|
|
175
175
|
|
176
176
|
def remove_optarg_equals(asgn_tokens, processed_source)
|
177
177
|
optargs = processed_source.ast.each_node(:optarg)
|
178
|
-
optarg_eql = optargs.
|
178
|
+
optarg_eql = optargs.to_set { |o| o.loc.operator.begin_pos }
|
179
179
|
asgn_tokens.reject { |t| optarg_eql.include?(t.begin_pos) }
|
180
180
|
end
|
181
181
|
end
|
@@ -108,7 +108,7 @@ module RuboCop
|
|
108
108
|
return if node.body.nil?
|
109
109
|
|
110
110
|
node.body.each_descendant(:lvar, :lvasgn).any? do |lvar|
|
111
|
-
!lvar.parent.block_pass_type? && lvar.
|
111
|
+
!lvar.parent.block_pass_type? && lvar.node_parts[0].to_s == last_argument
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -19,6 +19,28 @@ module RuboCop
|
|
19
19
|
class Registry
|
20
20
|
include Enumerable
|
21
21
|
|
22
|
+
def self.all
|
23
|
+
global.without_department(:Test).cops
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.qualified_cop_name(name, origin)
|
27
|
+
global.qualified_cop_name(name, origin)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Changes momentarily the global registry
|
31
|
+
# Intended for testing purposes
|
32
|
+
def self.with_temporary_global(temp_global = global.dup)
|
33
|
+
previous = @global
|
34
|
+
@global = temp_global
|
35
|
+
yield
|
36
|
+
ensure
|
37
|
+
@global = previous
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.reset!
|
41
|
+
@global = new
|
42
|
+
end
|
43
|
+
|
22
44
|
attr_reader :options
|
23
45
|
|
24
46
|
def initialize(cops = [], options = {})
|
@@ -238,28 +260,6 @@ module RuboCop
|
|
238
260
|
attr_reader :global
|
239
261
|
end
|
240
262
|
|
241
|
-
def self.all
|
242
|
-
global.without_department(:Test).cops
|
243
|
-
end
|
244
|
-
|
245
|
-
def self.qualified_cop_name(name, origin)
|
246
|
-
global.qualified_cop_name(name, origin)
|
247
|
-
end
|
248
|
-
|
249
|
-
# Changes momentarily the global registry
|
250
|
-
# Intended for testing purposes
|
251
|
-
def self.with_temporary_global(temp_global = global.dup)
|
252
|
-
previous = @global
|
253
|
-
@global = temp_global
|
254
|
-
yield
|
255
|
-
ensure
|
256
|
-
@global = previous
|
257
|
-
end
|
258
|
-
|
259
|
-
def self.reset!
|
260
|
-
@global = new
|
261
|
-
end
|
262
|
-
|
263
263
|
private
|
264
264
|
|
265
265
|
def initialize_copy(reg)
|
@@ -9,7 +9,8 @@ module RuboCop
|
|
9
9
|
# Manually combining hashes is error prone and hard to follow, especially
|
10
10
|
# when there are many values. Poor implementations may also introduce
|
11
11
|
# performance or security concerns if they are prone to collisions.
|
12
|
-
# Delegating to `Array#hash` is clearer
|
12
|
+
# Delegating to `Array#hash` is clearer and safer, although it might be slower
|
13
|
+
# depending on the use case.
|
13
14
|
#
|
14
15
|
# @safety
|
15
16
|
# This cop may be unsafe if the application logic depends on the hash
|
@@ -7,6 +7,11 @@ module RuboCop
|
|
7
7
|
# depending on configuration.
|
8
8
|
# It also flags uses of `alias :symbol` rather than `alias bareword`.
|
9
9
|
#
|
10
|
+
# However, it will always enforce `method_alias` when used `alias`
|
11
|
+
# in an instance method definition and in a singleton method definition.
|
12
|
+
# If used in a block, always enforce `alias_method`
|
13
|
+
# unless it is an `instance_eval` block.
|
14
|
+
#
|
10
15
|
# @example EnforcedStyle: prefer_alias (default)
|
11
16
|
# # bad
|
12
17
|
# alias_method :bar, :foo
|
@@ -22,6 +27,7 @@ module RuboCop
|
|
22
27
|
#
|
23
28
|
# # good
|
24
29
|
# alias_method :bar, :foo
|
30
|
+
#
|
25
31
|
class Alias < Base
|
26
32
|
include ConfigurableEnforcedStyle
|
27
33
|
extend AutoCorrector
|
@@ -71,7 +77,9 @@ module RuboCop
|
|
71
77
|
end
|
72
78
|
|
73
79
|
def alias_method_possible?(node)
|
74
|
-
scope_type(node) != :instance_eval &&
|
80
|
+
scope_type(node) != :instance_eval &&
|
81
|
+
node.children.none?(&:gvar_type?) &&
|
82
|
+
node&.parent&.type != :def
|
75
83
|
end
|
76
84
|
|
77
85
|
def add_offense_for_args(node, &block)
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
eq_begin, eq_end, contents = parts(comment)
|
33
33
|
|
34
34
|
corrector.remove(eq_begin)
|
35
|
-
unless contents.
|
35
|
+
unless contents.empty?
|
36
36
|
corrector.replace(
|
37
37
|
contents,
|
38
38
|
contents.source.gsub(/\A/, '# ').gsub(/\n\n/, "\n#\n").gsub(/\n(?=[^#])/, "\n# ")
|
@@ -30,6 +30,7 @@ module RuboCop
|
|
30
30
|
'Use `push` with elements as arguments without array brackets instead of `%<current>s`.'
|
31
31
|
RESTRICT_ON_SEND = %i[concat].freeze
|
32
32
|
|
33
|
+
# rubocop:disable Metrics
|
33
34
|
def on_send(node)
|
34
35
|
return if node.arguments.empty?
|
35
36
|
return unless node.arguments.all?(&:array_type?)
|
@@ -38,7 +39,12 @@ module RuboCop
|
|
38
39
|
current = offense.source
|
39
40
|
|
40
41
|
if node.arguments.any?(&:percent_literal?)
|
41
|
-
|
42
|
+
if percent_literals_includes_only_basic_literals?(node)
|
43
|
+
prefer = preferred_method(node)
|
44
|
+
message = format(MSG, prefer: prefer, current: current)
|
45
|
+
else
|
46
|
+
message = format(MSG_FOR_PERCENT_LITERALS, current: current)
|
47
|
+
end
|
42
48
|
else
|
43
49
|
prefer = preferred_method(node)
|
44
50
|
message = format(MSG, prefer: prefer, current: current)
|
@@ -48,6 +54,7 @@ module RuboCop
|
|
48
54
|
corrector.replace(offense, prefer)
|
49
55
|
end
|
50
56
|
end
|
57
|
+
# rubocop:enable Metrics
|
51
58
|
|
52
59
|
private
|
53
60
|
|
@@ -56,10 +63,23 @@ module RuboCop
|
|
56
63
|
end
|
57
64
|
|
58
65
|
def preferred_method(node)
|
59
|
-
new_arguments =
|
66
|
+
new_arguments =
|
67
|
+
node.arguments.map do |arg|
|
68
|
+
if arg.percent_literal?
|
69
|
+
arg.children.map(&:value).map(&:inspect)
|
70
|
+
else
|
71
|
+
arg.children.map(&:source)
|
72
|
+
end
|
73
|
+
end.join(', ')
|
60
74
|
|
61
75
|
"push(#{new_arguments})"
|
62
76
|
end
|
77
|
+
|
78
|
+
def percent_literals_includes_only_basic_literals?(node)
|
79
|
+
node.arguments.select(&:percent_literal?).all? do |arg|
|
80
|
+
arg.children.all? { |child| child.str_type? || child.sym_type? }
|
81
|
+
end
|
82
|
+
end
|
63
83
|
end
|
64
84
|
end
|
65
85
|
end
|
@@ -86,6 +86,11 @@ module RuboCop
|
|
86
86
|
(send nil? {:public_constant :private_constant} ({sym str} _))
|
87
87
|
PATTERN
|
88
88
|
|
89
|
+
# @!method include_statement?(node)
|
90
|
+
def_node_matcher :include_statement?, <<~PATTERN
|
91
|
+
(send nil? {:include :extend :prepend} const)
|
92
|
+
PATTERN
|
93
|
+
|
89
94
|
def on_class(node)
|
90
95
|
return unless node.body
|
91
96
|
|
@@ -103,7 +108,7 @@ module RuboCop
|
|
103
108
|
return if documentation_comment?(node)
|
104
109
|
return if constant_allowed?(node)
|
105
110
|
return if nodoc_self_or_outer_module?(node)
|
106
|
-
return if
|
111
|
+
return if include_statement_only?(body)
|
107
112
|
|
108
113
|
range = range_between(node.loc.expression.begin_pos, node.loc.name.end_pos)
|
109
114
|
message = format(MSG, type: node.type, identifier: identifier(node))
|
@@ -115,9 +120,10 @@ module RuboCop
|
|
115
120
|
(compact_namespace?(node) && nodoc_comment?(outer_module(node).first))
|
116
121
|
end
|
117
122
|
|
118
|
-
def
|
119
|
-
|
120
|
-
|
123
|
+
def include_statement_only?(body)
|
124
|
+
return true if include_statement?(body)
|
125
|
+
|
126
|
+
body.respond_to?(:children) && body.children.all? { |node| include_statement_only?(node) }
|
121
127
|
end
|
122
128
|
|
123
129
|
def namespace?(node)
|
@@ -189,14 +189,14 @@ module RuboCop
|
|
189
189
|
|
190
190
|
if if_branch&.send_type? && heredoc?(if_branch.last_argument)
|
191
191
|
autocorrect_heredoc_argument(corrector, node, if_branch, else_branch, guard)
|
192
|
-
elsif else_branch&.send_type? && else_branch.last_argument
|
192
|
+
elsif else_branch&.send_type? && heredoc?(else_branch.last_argument)
|
193
193
|
autocorrect_heredoc_argument(corrector, node, else_branch, if_branch, guard)
|
194
194
|
else
|
195
195
|
corrector.remove(node.loc.end)
|
196
196
|
return unless node.else?
|
197
197
|
|
198
198
|
corrector.remove(node.loc.else)
|
199
|
-
corrector.remove(
|
199
|
+
corrector.remove(range_of_branch_to_remove(node, guard))
|
200
200
|
end
|
201
201
|
end
|
202
202
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
@@ -206,20 +206,24 @@ module RuboCop
|
|
206
206
|
end
|
207
207
|
|
208
208
|
def autocorrect_heredoc_argument(corrector, node, heredoc_branch, leave_branch, guard)
|
209
|
+
return unless node.else?
|
210
|
+
|
209
211
|
remove_whole_lines(corrector, leave_branch.source_range)
|
210
212
|
remove_whole_lines(corrector, node.loc.else)
|
211
213
|
remove_whole_lines(corrector, node.loc.end)
|
212
|
-
remove_whole_lines(corrector,
|
214
|
+
remove_whole_lines(corrector, range_of_branch_to_remove(node, guard))
|
213
215
|
corrector.insert_after(
|
214
216
|
heredoc_branch.last_argument.loc.heredoc_end, "\n#{leave_branch.source}"
|
215
217
|
)
|
216
218
|
end
|
217
219
|
|
218
|
-
def
|
219
|
-
case guard
|
220
|
-
|
221
|
-
|
222
|
-
|
220
|
+
def range_of_branch_to_remove(node, guard)
|
221
|
+
branch = case guard
|
222
|
+
when :if then node.if_branch
|
223
|
+
when :else then node.else_branch
|
224
|
+
end
|
225
|
+
|
226
|
+
branch.source_range
|
223
227
|
end
|
224
228
|
|
225
229
|
def guard_clause_source(guard_clause)
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
# * always - forces use of the 3.1 syntax (e.g. {foo:})
|
29
29
|
# * never - forces use of explicit hash literal value
|
30
30
|
# * either - accepts both shorthand and explicit use of hash literal value
|
31
|
-
# * consistent -
|
31
|
+
# * consistent - forces use of the 3.1 syntax only if all values can be omitted in the hash
|
32
32
|
#
|
33
33
|
# @example EnforcedStyle: ruby19 (default)
|
34
34
|
# # bad
|
@@ -92,16 +92,19 @@ module RuboCop
|
|
92
92
|
#
|
93
93
|
# @example EnforcedShorthandSyntax: consistent
|
94
94
|
#
|
95
|
-
# # bad
|
96
|
-
# {foo: , bar: bar}
|
95
|
+
# # bad - `foo` and `bar` values can be omitted
|
96
|
+
# {foo: foo, bar: bar}
|
97
97
|
#
|
98
|
-
# #
|
99
|
-
# {foo:, bar:}
|
98
|
+
# # bad - `bar` value can be omitted
|
99
|
+
# {foo:, bar: bar}
|
100
100
|
#
|
101
|
-
# # bad
|
102
|
-
# {foo
|
101
|
+
# # bad - mixed syntaxes
|
102
|
+
# {foo:, bar: baz}
|
103
103
|
#
|
104
104
|
# # good
|
105
|
+
# {foo:, bar:}
|
106
|
+
#
|
107
|
+
# # good - can't omit `baz`
|
105
108
|
# {foo: foo, bar: baz}
|
106
109
|
#
|
107
110
|
class HashSyntax < Base
|
@@ -136,6 +136,7 @@ module RuboCop
|
|
136
136
|
|
137
137
|
private
|
138
138
|
|
139
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
139
140
|
def check_branches(node, branches)
|
140
141
|
# return if any branch is empty. An empty branch can be an `if`
|
141
142
|
# without an `else` or a branch that contains only comments.
|
@@ -144,9 +145,13 @@ module RuboCop
|
|
144
145
|
tails = branches.map { |branch| tail(branch) }
|
145
146
|
check_expressions(node, tails, :after_condition) if duplicated_expressions?(node, tails)
|
146
147
|
|
148
|
+
return if last_child_of_parent?(node) &&
|
149
|
+
branches.any? { |branch| single_child_branch?(branch) }
|
150
|
+
|
147
151
|
heads = branches.map { |branch| head(branch) }
|
148
152
|
check_expressions(node, heads, :before_condition) if duplicated_expressions?(node, heads)
|
149
153
|
end
|
154
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
150
155
|
|
151
156
|
def duplicated_expressions?(node, expressions)
|
152
157
|
unique_expressions = expressions.uniq
|
@@ -180,6 +185,16 @@ module RuboCop
|
|
180
185
|
end
|
181
186
|
end
|
182
187
|
|
188
|
+
def last_child_of_parent?(node)
|
189
|
+
return true unless (parent = node.parent)
|
190
|
+
|
191
|
+
parent.child_nodes.last == node
|
192
|
+
end
|
193
|
+
|
194
|
+
def single_child_branch?(branch_node)
|
195
|
+
!branch_node.begin_type? || branch_node.children.size == 1
|
196
|
+
end
|
197
|
+
|
183
198
|
def message(node)
|
184
199
|
format(MSG, source: node.source)
|
185
200
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Looks for uses of `map.to_set` or `collect.to_set` that could be
|
7
|
+
# written with just `to_set`.
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe, as it can produce false positives if the receiver
|
11
|
+
# is not an `Enumerable`.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # bad
|
15
|
+
# something.map { |i| i * 2 }.to_set
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# something.to_set { |i| i * 2 }
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# [1, 2, 3].collect { |i| i.to_s }.to_set
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# [1, 2, 3].to_set { |i| i.to_s }
|
25
|
+
#
|
26
|
+
class MapToSet < Base
|
27
|
+
extend AutoCorrector
|
28
|
+
include RangeHelp
|
29
|
+
|
30
|
+
MSG = 'Pass a block to `to_set` instead of calling `%<method>s.to_set`.'
|
31
|
+
RESTRICT_ON_SEND = %i[to_set].freeze
|
32
|
+
|
33
|
+
# @!method map_to_set?(node)
|
34
|
+
def_node_matcher :map_to_set?, <<~PATTERN
|
35
|
+
$(send (block $(send _ {:map :collect}) ...) :to_set)
|
36
|
+
PATTERN
|
37
|
+
|
38
|
+
def on_send(node)
|
39
|
+
return unless (to_set_node, map_node = map_to_set?(node))
|
40
|
+
|
41
|
+
message = format(MSG, method: map_node.loc.selector.source)
|
42
|
+
add_offense(map_node.loc.selector, message: message) do |corrector|
|
43
|
+
# If the `to_set` call already has a block, do not autocorrect.
|
44
|
+
next if to_set_node.block_node
|
45
|
+
|
46
|
+
autocorrect(corrector, to_set_node, map_node)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def autocorrect(corrector, to_set, map)
|
53
|
+
removal_range = range_between(to_set.loc.dot.begin_pos, to_set.loc.selector.end_pos)
|
54
|
+
|
55
|
+
corrector.remove(range_with_surrounding_space(removal_range, side: :left))
|
56
|
+
corrector.replace(map.loc.selector, 'to_set')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -10,7 +10,9 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# 1. Endless methods
|
12
12
|
# 2. Argument lists containing a `forward-arg` (`...`)
|
13
|
-
# 3. Argument lists containing an anonymous
|
13
|
+
# 3. Argument lists containing an anonymous rest arguments forwarding (`*`)
|
14
|
+
# 4. Argument lists containing an anonymous keyword rest arguments forwarding (`**`)
|
15
|
+
# 5. Argument lists containing an anonymous block forwarding (`&`)
|
14
16
|
#
|
15
17
|
# Removing the parens would be a syntax error here.
|
16
18
|
#
|
@@ -130,9 +132,11 @@ module RuboCop
|
|
130
132
|
# Regardless of style, parentheses are necessary for:
|
131
133
|
# 1. Endless methods
|
132
134
|
# 2. Argument lists containing a `forward-arg` (`...`)
|
133
|
-
# 3. Argument lists containing an anonymous
|
135
|
+
# 3. Argument lists containing an anonymous rest arguments forwarding (`*`)
|
136
|
+
# 4. Argument lists containing an anonymous keyword rest arguments forwarding (`**`)
|
137
|
+
# 5. Argument lists containing an anonymous block forwarding (`&`)
|
134
138
|
# Removing the parens would be a syntax error here.
|
135
|
-
node.endless? ||
|
139
|
+
node.endless? || anonymous_arguments?(node)
|
136
140
|
end
|
137
141
|
|
138
142
|
def require_parentheses?(args)
|
@@ -162,7 +166,10 @@ module RuboCop
|
|
162
166
|
end
|
163
167
|
end
|
164
168
|
|
165
|
-
def
|
169
|
+
def anonymous_arguments?(node)
|
170
|
+
return true if node.arguments.any? do |arg|
|
171
|
+
arg.forward_arg_type? || arg.restarg_type? || arg.kwrestarg_type?
|
172
|
+
end
|
166
173
|
return false unless (last_argument = node.arguments.last)
|
167
174
|
|
168
175
|
last_argument.blockarg_type? && last_argument.name.nil?
|