rubocop 1.19.1 → 1.22.1
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/README.md +1 -1
- data/config/default.yml +86 -14
- data/lib/rubocop/config.rb +5 -0
- data/lib/rubocop/config_loader.rb +4 -2
- data/lib/rubocop/config_validator.rb +9 -1
- data/lib/rubocop/cop/base.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
- data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
- data/lib/rubocop/cop/generator.rb +14 -8
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -1
- data/lib/rubocop/cop/layout/dot_position.rb +31 -4
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +8 -6
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -24
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +8 -8
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
- data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
- data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
- data/lib/rubocop/cop/lint/else_layout.rb +9 -5
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
- data/lib/rubocop/cop/lint/loop.rb +4 -3
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +12 -1
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
- data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
- data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
- data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
- data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/lint/useless_times.rb +4 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
- data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
- data/lib/rubocop/cop/mixin/percent_array.rb +6 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +5 -1
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
- data/lib/rubocop/cop/security/io_methods.rb +49 -0
- data/lib/rubocop/cop/security/json_load.rb +8 -7
- data/lib/rubocop/cop/security/open.rb +4 -0
- data/lib/rubocop/cop/security/yaml_load.rb +4 -0
- data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
- data/lib/rubocop/cop/style/and_or.rb +5 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
- data/lib/rubocop/cop/style/array_coercion.rb +21 -3
- data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +23 -6
- data/lib/rubocop/cop/style/case_equality.rb +6 -9
- data/lib/rubocop/cop/style/case_like_if.rb +5 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
- data/lib/rubocop/cop/style/collection_compact.rb +7 -5
- data/lib/rubocop/cop/style/collection_methods.rb +8 -6
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
- data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
- data/lib/rubocop/cop/style/commented_keyword.rb +4 -1
- data/lib/rubocop/cop/style/date_time.rb +5 -0
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +23 -8
- data/lib/rubocop/cop/style/double_negation.rb +15 -5
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
- data/lib/rubocop/cop/style/float_division.rb +10 -2
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -2
- data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
- data/lib/rubocop/cop/style/hash_except.rb +4 -3
- data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
- data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
- data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
- data/lib/rubocop/cop/style/lambda_call.rb +1 -1
- data/lib/rubocop/cop/style/line_end_concatenation.rb +13 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
- data/lib/rubocop/cop/style/module_function.rb +8 -9
- data/lib/rubocop/cop/style/mutable_constant.rb +73 -6
- data/lib/rubocop/cop/style/negated_if.rb +1 -1
- data/lib/rubocop/cop/style/negated_unless.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
- data/lib/rubocop/cop/style/not.rb +2 -2
- data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
- data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
- data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
- data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
- data/lib/rubocop/cop/style/quoted_symbols.rb +10 -6
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
- data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
- data/lib/rubocop/cop/style/redundant_self.rb +10 -0
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
- data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
- data/lib/rubocop/cop/style/return_nil.rb +2 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
- data/lib/rubocop/cop/style/select_by_regexp.rb +133 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
- data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
- data/lib/rubocop/cop/style/static_class.rb +5 -5
- data/lib/rubocop/cop/style/string_chars.rb +4 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
- data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
- data/lib/rubocop/cop/style/swap_values.rb +4 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
- data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
- data/lib/rubocop/cop/util.rb +4 -3
- data/lib/rubocop/cops_documentation_generator.rb +17 -5
- data/lib/rubocop/options.rb +126 -112
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/result_cache.rb +3 -3
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/runner.rb +2 -3
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +10 -2
- metadata +17 -9
@@ -50,15 +50,15 @@ module RuboCop
|
|
50
50
|
# spec.add_dependency 'rubocop'
|
51
51
|
# # For tests
|
52
52
|
# spec.add_dependency 'rspec'
|
53
|
-
class OrderedDependencies <
|
54
|
-
|
53
|
+
class OrderedDependencies < Base
|
54
|
+
extend AutoCorrector
|
55
55
|
include OrderedGemNode
|
56
56
|
|
57
57
|
MSG = 'Dependencies should be sorted in an alphabetical order within ' \
|
58
58
|
'their section of the gemspec. '\
|
59
59
|
'Dependency `%<previous>s` should appear before `%<current>s`.'
|
60
60
|
|
61
|
-
def
|
61
|
+
def on_new_investigation
|
62
62
|
return if processed_source.blank?
|
63
63
|
|
64
64
|
dependency_declarations(processed_source.ast)
|
@@ -71,15 +71,6 @@ module RuboCop
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
def autocorrect(node)
|
75
|
-
OrderedGemCorrector.correct(
|
76
|
-
processed_source,
|
77
|
-
node,
|
78
|
-
previous_declaration(node),
|
79
|
-
treat_comments_as_separators
|
80
|
-
)
|
81
|
-
end
|
82
|
-
|
83
74
|
private
|
84
75
|
|
85
76
|
def previous_declaration(node)
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
# end
|
43
43
|
#
|
44
44
|
# # accepted but not recommended, since
|
45
|
-
# # Ruby does not really follow semantic
|
45
|
+
# # Ruby does not really follow semantic versioning
|
46
46
|
# Gem::Specification.new do |spec|
|
47
47
|
# spec.required_ruby_version = '~> 2.5'
|
48
48
|
# end
|
@@ -24,6 +24,11 @@ module RuboCop
|
|
24
24
|
# `SupportedStyle` and unique configuration, there needs to be examples.
|
25
25
|
# Examples must have valid Ruby syntax. Do not use upticks.
|
26
26
|
#
|
27
|
+
# @safety
|
28
|
+
# Delete this section if the cop is not unsafe (`Safe: false` or
|
29
|
+
# `SafeAutoCorrect: false`), or use it to explain how the cop is
|
30
|
+
# unsafe.
|
31
|
+
#
|
27
32
|
# @example EnforcedStyle: bar (default)
|
28
33
|
# # Description of the `bar` style.
|
29
34
|
#
|
@@ -106,9 +111,8 @@ module RuboCop
|
|
106
111
|
'[modify] A configuration for the cop is added into ' \
|
107
112
|
'%<configuration_file_path>s.'
|
108
113
|
|
109
|
-
def initialize(name,
|
114
|
+
def initialize(name, output: $stdout)
|
110
115
|
@badge = Badge.parse(name)
|
111
|
-
@github_user = github_user
|
112
116
|
@output = output
|
113
117
|
return if badge.qualified?
|
114
118
|
|
@@ -142,17 +146,19 @@ module RuboCop
|
|
142
146
|
|
143
147
|
def todo
|
144
148
|
<<~TODO
|
145
|
-
Do
|
146
|
-
1.
|
147
|
-
|
148
|
-
|
149
|
-
|
149
|
+
Do 4 steps:
|
150
|
+
1. Modify the description of #{badge} in config/default.yml
|
151
|
+
2. Implement your new cop in the generated file!
|
152
|
+
3. Commit your new cop with a message such as
|
153
|
+
e.g. "Add new `#{badge}` cop."
|
154
|
+
4. Run `bundle exec rake changelog:new` to generate a changelog entry
|
155
|
+
for your new cop.
|
150
156
|
TODO
|
151
157
|
end
|
152
158
|
|
153
159
|
private
|
154
160
|
|
155
|
-
attr_reader :badge, :
|
161
|
+
attr_reader :badge, :output
|
156
162
|
|
157
163
|
def write_unless_file_exists(path, contents)
|
158
164
|
if File.exist?(path)
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
extend AutoCorrector
|
24
24
|
include RangeHelp
|
25
25
|
|
26
|
-
MSG = '
|
26
|
+
MSG = 'Precede `%<method>s` with a `@!method` YARD directive.'
|
27
27
|
MSG_WRONG_NAME = '`@!method` YARD directive has invalid method name, ' \
|
28
28
|
'use `%<expected>s` instead of `%<actual>s`.'
|
29
29
|
MSG_TOO_MANY = 'Multiple `@!method` YARD directives found for this matcher.'
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
|
55
55
|
def on_send(node)
|
56
56
|
first_arg = node.first_argument
|
57
|
-
return if !multiple_arguments?(node, first_arg) || node.send_type? && node.method?(:[]=)
|
57
|
+
return if !multiple_arguments?(node, first_arg) || (node.send_type? && node.method?(:[]=))
|
58
58
|
|
59
59
|
if first_arg.hash_type? && !first_arg.braces?
|
60
60
|
pairs = first_arg.pairs
|
@@ -264,7 +264,8 @@ module RuboCop
|
|
264
264
|
|
265
265
|
def source_range_with_comment(node)
|
266
266
|
begin_pos, end_pos =
|
267
|
-
if node.def_type? && !node.method?(:initialize) ||
|
267
|
+
if (node.def_type? && !node.method?(:initialize)) ||
|
268
|
+
(node.send_type? && node.def_modifier?)
|
268
269
|
start_node = find_visibility_start(node) || node
|
269
270
|
end_node = find_visibility_end(node) || node
|
270
271
|
[begin_pos_with_comment(start_node),
|
@@ -68,19 +68,26 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def proper_dot_position?(node)
|
71
|
-
receiver_line = node.receiver.source_range.end.line
|
72
71
|
selector_line = selector_range(node).line
|
73
72
|
|
74
|
-
# receiver and selector
|
75
|
-
|
73
|
+
# If the receiver is a HEREDOC and the selector is on the same line
|
74
|
+
# then there is nothing to do
|
75
|
+
return true if heredoc?(node.receiver) && node.receiver.loc.first_line == selector_line
|
76
76
|
|
77
|
+
receiver_line = receiver_end_line(node.receiver)
|
77
78
|
dot_line = node.loc.dot.line
|
78
79
|
|
80
|
+
# receiver and selector are on the same line
|
81
|
+
return true if selector_line == receiver_line
|
82
|
+
|
79
83
|
# don't register an offense if there is a line comment between the
|
80
84
|
# dot and the selector otherwise, we might break the code while
|
81
85
|
# "correcting" it (even if there is just an extra blank line, treat
|
82
86
|
# it the same)
|
83
|
-
|
87
|
+
# Also, in the case of a heredoc, the receiver will end after the dot,
|
88
|
+
# because the heredoc body is on subsequent lines, so use the highest
|
89
|
+
# line to compare to.
|
90
|
+
return true if line_between?(selector_line, [receiver_line, dot_line].max)
|
84
91
|
|
85
92
|
correct_dot_position_style?(dot_line, selector_line)
|
86
93
|
end
|
@@ -96,6 +103,26 @@ module RuboCop
|
|
96
103
|
end
|
97
104
|
end
|
98
105
|
|
106
|
+
def receiver_end_line(node)
|
107
|
+
if (line = last_heredoc_line(node))
|
108
|
+
line
|
109
|
+
else
|
110
|
+
node.source_range.end.line
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def last_heredoc_line(node)
|
115
|
+
if node.send_type?
|
116
|
+
node.arguments.select { |arg| heredoc?(arg) }.map { |arg| arg.loc.heredoc_end.line }.max
|
117
|
+
elsif heredoc?(node)
|
118
|
+
node.loc.heredoc_end.line
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def heredoc?(node)
|
123
|
+
(node.str_type? || node.dstr_type?) && node.heredoc?
|
124
|
+
end
|
125
|
+
|
99
126
|
def selector_range(node)
|
100
127
|
# l.(1) has no selector, so we use the opening parenthesis instead
|
101
128
|
node.loc.selector || node.loc.begin
|
@@ -182,7 +182,7 @@ module RuboCop
|
|
182
182
|
|
183
183
|
def assignment_or_operator_method(node)
|
184
184
|
node.ancestors.find do |ancestor|
|
185
|
-
ancestor.assignment_or_similar? || ancestor.send_type? && ancestor.operator_method?
|
185
|
+
ancestor.assignment_or_similar? || (ancestor.send_type? && ancestor.operator_method?)
|
186
186
|
end
|
187
187
|
end
|
188
188
|
end
|
@@ -176,15 +176,15 @@ module RuboCop
|
|
176
176
|
def ignored_line?(line, line_index)
|
177
177
|
matches_ignored_pattern?(line) ||
|
178
178
|
shebang?(line, line_index) ||
|
179
|
-
heredocs && line_in_permitted_heredoc?(line_index.succ)
|
179
|
+
(heredocs && line_in_permitted_heredoc?(line_index.succ))
|
180
180
|
end
|
181
181
|
|
182
182
|
def shebang?(line, line_index)
|
183
183
|
line_index.zero? && line.start_with?('#!')
|
184
184
|
end
|
185
185
|
|
186
|
-
def register_offense(loc, line, line_index)
|
187
|
-
message = format(MSG, length:
|
186
|
+
def register_offense(loc, line, line_index, length: line_length(line))
|
187
|
+
message = format(MSG, length: length, max: max)
|
188
188
|
|
189
189
|
self.breakable_range = breakable_range_by_line_index[line_index]
|
190
190
|
|
@@ -241,9 +241,10 @@ module RuboCop
|
|
241
241
|
end
|
242
242
|
|
243
243
|
def check_directive_line(line, line_index)
|
244
|
-
|
244
|
+
length_without_directive = line_length_without_directive(line)
|
245
|
+
return if length_without_directive <= max
|
245
246
|
|
246
|
-
range = max..(
|
247
|
+
range = max..(length_without_directive - 1)
|
247
248
|
register_offense(
|
248
249
|
source_range(
|
249
250
|
processed_source.buffer,
|
@@ -251,7 +252,8 @@ module RuboCop
|
|
251
252
|
range
|
252
253
|
),
|
253
254
|
line,
|
254
|
-
line_index
|
255
|
+
line_index,
|
256
|
+
length: length_without_directive
|
255
257
|
)
|
256
258
|
end
|
257
259
|
|
@@ -6,6 +6,9 @@ module RuboCop
|
|
6
6
|
# This cop ensures that each argument in a multi-line method call
|
7
7
|
# starts on a separate line.
|
8
8
|
#
|
9
|
+
# NOTE: this cop does not move the first argument, if you want that to
|
10
|
+
# be on a separate line, see `Layout/FirstMethodArgumentLineBreak`.
|
11
|
+
#
|
9
12
|
# @example
|
10
13
|
#
|
11
14
|
# # bad
|
@@ -127,6 +127,7 @@ module RuboCop
|
|
127
127
|
.gsub(/" *\\\n\s*'/, %q(" + ')) # Double quote, backslash, and then single quote
|
128
128
|
.gsub(/' *\\\n\s*"/, %q(' + ")) # Single quote, backslash, and then double quote
|
129
129
|
.gsub(/(["']) *\\\n\s*\1/, '') # Double or single quote, backslash, then same quote
|
130
|
+
.gsub(/\n\s*(?=\.\w)/, '') # Extra space within method chaining
|
130
131
|
.gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
|
131
132
|
end
|
132
133
|
|
@@ -37,15 +37,26 @@ module RuboCop
|
|
37
37
|
return unless receiver&.block_type?
|
38
38
|
|
39
39
|
receiver_location = receiver.loc
|
40
|
-
|
41
|
-
return if receiver_location.begin.line <
|
40
|
+
closing_block_delimiter_line_num = receiver_location.end.line
|
41
|
+
return if receiver_location.begin.line < closing_block_delimiter_line_num
|
42
42
|
|
43
43
|
node_location = node.loc
|
44
44
|
dot_range = node_location.dot
|
45
45
|
return unless dot_range
|
46
|
-
return
|
46
|
+
return unless call_method_after_block?(node, dot_range, closing_block_delimiter_line_num)
|
47
47
|
|
48
|
-
range_between(dot_range.begin_pos,
|
48
|
+
range_between(dot_range.begin_pos, selector_range(node).end_pos)
|
49
|
+
end
|
50
|
+
|
51
|
+
def call_method_after_block?(node, dot_range, closing_block_delimiter_line_num)
|
52
|
+
return false if dot_range.line > closing_block_delimiter_line_num
|
53
|
+
|
54
|
+
dot_range.column < selector_range(node).column
|
55
|
+
end
|
56
|
+
|
57
|
+
def selector_range(node)
|
58
|
+
# l.(1) has no selector, so we use the opening parenthesis instead
|
59
|
+
node.loc.selector || node.loc.begin
|
49
60
|
end
|
50
61
|
end
|
51
62
|
end
|
@@ -47,7 +47,8 @@ module RuboCop
|
|
47
47
|
space_on_both_sides = space_on_both_sides?(arg, equals)
|
48
48
|
no_surrounding_space = no_surrounding_space?(arg, equals)
|
49
49
|
|
50
|
-
if style == :space && space_on_both_sides ||
|
50
|
+
if (style == :space && space_on_both_sides) ||
|
51
|
+
(style == :no_space && no_surrounding_space)
|
51
52
|
correct_style_detected
|
52
53
|
else
|
53
54
|
incorrect_style_detected(arg, value)
|
@@ -228,8 +228,8 @@ module RuboCop
|
|
228
228
|
def accepted_opening_delimiter?(range, char)
|
229
229
|
return true unless char
|
230
230
|
|
231
|
-
accept_left_square_bracket?(range) && char == '[' ||
|
232
|
-
accept_left_parenthesis?(range) && char == '('
|
231
|
+
(accept_left_square_bracket?(range) && char == '[') ||
|
232
|
+
(accept_left_parenthesis?(range) && char == '(')
|
233
233
|
end
|
234
234
|
|
235
235
|
def accept_left_parenthesis?(range)
|
@@ -33,6 +33,27 @@ module RuboCop
|
|
33
33
|
# g = ( a + 3 )
|
34
34
|
# y()
|
35
35
|
#
|
36
|
+
# @example EnforcedStyle: compact
|
37
|
+
# # The `compact` style enforces that parentheses have a space at the
|
38
|
+
# # beginning with the exception that successive parentheses are allowed.
|
39
|
+
# # Note: Empty parentheses should not have spaces.
|
40
|
+
#
|
41
|
+
# # bad
|
42
|
+
# f(3)
|
43
|
+
# g = (a + 3)
|
44
|
+
# y( )
|
45
|
+
# g( f( x ) )
|
46
|
+
# g( f( x( 3 ) ), 5 )
|
47
|
+
# g( ( ( 3 + 5 ) * f) ** x, 5 )
|
48
|
+
#
|
49
|
+
# # good
|
50
|
+
# f( 3 )
|
51
|
+
# g = ( a + 3 )
|
52
|
+
# y()
|
53
|
+
# g( f( x ))
|
54
|
+
# g( f( x( 3 )), 5 )
|
55
|
+
# g((( 3 + 5 ) * f ) ** x, 5 )
|
56
|
+
#
|
36
57
|
class SpaceInsideParens < Base
|
37
58
|
include SurroundingSpace
|
38
59
|
include RangeHelp
|
@@ -45,14 +66,13 @@ module RuboCop
|
|
45
66
|
def on_new_investigation
|
46
67
|
tokens = processed_source.sorted_tokens
|
47
68
|
|
48
|
-
|
69
|
+
case style
|
70
|
+
when :space
|
49
71
|
process_with_space_style(tokens)
|
72
|
+
when :compact
|
73
|
+
process_with_compact_style(tokens)
|
50
74
|
else
|
51
|
-
|
52
|
-
add_offense(range) do |corrector|
|
53
|
-
corrector.remove(range)
|
54
|
-
end
|
55
|
-
end
|
75
|
+
correct_extraneous_space(tokens)
|
56
76
|
end
|
57
77
|
end
|
58
78
|
|
@@ -60,20 +80,23 @@ module RuboCop
|
|
60
80
|
|
61
81
|
def process_with_space_style(tokens)
|
62
82
|
tokens.each_cons(2) do |token1, token2|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
83
|
+
correct_extraneous_space_in_empty_parens(token1, token2)
|
84
|
+
correct_missing_space(token1, token2)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_with_compact_style(tokens)
|
89
|
+
tokens.each_cons(2) do |token1, token2|
|
90
|
+
correct_extraneous_space_in_empty_parens(token1, token2)
|
91
|
+
if !left_parens?(token1, token2) && !right_parens?(token1, token2)
|
92
|
+
correct_missing_space(token1, token2)
|
93
|
+
else
|
94
|
+
correct_extaneus_space_between_consecutive_parens(token1, token2)
|
72
95
|
end
|
73
96
|
end
|
74
97
|
end
|
75
98
|
|
76
|
-
def
|
99
|
+
def correct_extraneous_space(tokens)
|
77
100
|
tokens.each_cons(2) do |token1, token2|
|
78
101
|
next unless parens?(token1, token2)
|
79
102
|
|
@@ -82,25 +105,44 @@ module RuboCop
|
|
82
105
|
next if token2.comment?
|
83
106
|
next unless same_line?(token1, token2) && token1.space_after?
|
84
107
|
|
85
|
-
|
108
|
+
range = range_between(token1.end_pos, token2.begin_pos)
|
109
|
+
add_offense(range) do |corrector|
|
110
|
+
corrector.remove(range)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def correct_extaneus_space_between_consecutive_parens(token1, token2)
|
116
|
+
return if range_between(token1.end_pos, token2.begin_pos).source != ' '
|
117
|
+
|
118
|
+
range = range_between(token1.end_pos, token2.begin_pos)
|
119
|
+
add_offense(range) do |corrector|
|
120
|
+
corrector.remove(range)
|
86
121
|
end
|
87
122
|
end
|
88
123
|
|
89
|
-
def
|
124
|
+
def correct_extraneous_space_in_empty_parens(token1, token2)
|
90
125
|
return unless token1.left_parens? && token2.right_parens?
|
91
126
|
|
92
127
|
return if range_between(token1.begin_pos, token2.end_pos).source == '()'
|
93
128
|
|
94
|
-
|
129
|
+
range = range_between(token1.end_pos, token2.begin_pos)
|
130
|
+
add_offense(range) do |corrector|
|
131
|
+
corrector.remove(range)
|
132
|
+
end
|
95
133
|
end
|
96
134
|
|
97
|
-
def
|
135
|
+
def correct_missing_space(token1, token2)
|
98
136
|
return if can_be_ignored?(token1, token2)
|
99
137
|
|
100
|
-
if token1.left_parens?
|
101
|
-
|
102
|
-
|
103
|
-
|
138
|
+
range = if token1.left_parens?
|
139
|
+
range_between(token2.begin_pos, token2.begin_pos + 1)
|
140
|
+
elsif token2.right_parens?
|
141
|
+
range_between(token2.begin_pos, token2.end_pos)
|
142
|
+
end
|
143
|
+
|
144
|
+
add_offense(range, message: MSG_SPACE) do |corrector|
|
145
|
+
corrector.insert_before(range, ' ')
|
104
146
|
end
|
105
147
|
end
|
106
148
|
|
@@ -112,6 +154,14 @@ module RuboCop
|
|
112
154
|
token1.left_parens? || token2.right_parens?
|
113
155
|
end
|
114
156
|
|
157
|
+
def left_parens?(token1, token2)
|
158
|
+
token1.left_parens? && token2.left_parens?
|
159
|
+
end
|
160
|
+
|
161
|
+
def right_parens?(token1, token2)
|
162
|
+
token1.right_parens? && token2.right_parens?
|
163
|
+
end
|
164
|
+
|
115
165
|
def can_be_ignored?(token1, token2)
|
116
166
|
return true unless parens?(token1, token2)
|
117
167
|
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
107
107
|
current_token = tokens.reverse.find(&:left_ref_bracket?)
|
108
108
|
previous_token = previous_token(current_token)
|
109
109
|
|
110
|
-
if node.method?(:[]=) || previous_token && !previous_token.right_bracket?
|
110
|
+
if node.method?(:[]=) || (previous_token && !previous_token.right_bracket?)
|
111
111
|
tokens.find(&:left_ref_bracket?)
|
112
112
|
else
|
113
113
|
current_token
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop looks for expressions containing multiple binary operators
|
7
|
+
# where precedence is ambiguous due to lack of parentheses. For example,
|
8
|
+
# in `1 + 2 * 3`, the multiplication will happen before the addition, but
|
9
|
+
# lexically it appears that the addition will happen first.
|
10
|
+
#
|
11
|
+
# The cop does not consider unary operators (ie. `!a` or `-b`) or comparison
|
12
|
+
# operators (ie. `a =~ b`) because those are not ambiguous.
|
13
|
+
#
|
14
|
+
# NOTE: Ranges are handled by `Lint/AmbiguousRange`.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# # bad
|
18
|
+
# a + b * c
|
19
|
+
# a || b && c
|
20
|
+
# a ** b + c
|
21
|
+
#
|
22
|
+
# # good (different precedence)
|
23
|
+
# a + (b * c)
|
24
|
+
# a || (b && c)
|
25
|
+
# (a ** b) + c
|
26
|
+
#
|
27
|
+
# # good (same precedence)
|
28
|
+
# a + b + c
|
29
|
+
# a * b / c % d
|
30
|
+
class AmbiguousOperatorPrecedence < Base
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
# See https://ruby-doc.org/core-3.0.2/doc/syntax/precedence_rdoc.html
|
34
|
+
PRECEDENCE = [
|
35
|
+
%i[**],
|
36
|
+
%i[* / %],
|
37
|
+
%i[+ -],
|
38
|
+
%i[<< >>],
|
39
|
+
%i[&],
|
40
|
+
%i[| ^],
|
41
|
+
%i[&&],
|
42
|
+
%i[||]
|
43
|
+
].freeze
|
44
|
+
RESTRICT_ON_SEND = PRECEDENCE.flatten.freeze
|
45
|
+
MSG = 'Wrap expressions with varying precedence with parentheses to avoid ambiguity.'
|
46
|
+
|
47
|
+
def on_new_investigation
|
48
|
+
# Cache the precedence of each node being investigated
|
49
|
+
# so that we only need to calculate it once
|
50
|
+
@node_precedences = {}
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_and(node)
|
55
|
+
return unless (parent = node.parent)
|
56
|
+
|
57
|
+
return if parent.begin_type? # if the `and` is in a `begin`, it's parenthesized already
|
58
|
+
return unless parent.or_type?
|
59
|
+
|
60
|
+
add_offense(node) do |corrector|
|
61
|
+
autocorrect(corrector, node)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_send(node)
|
66
|
+
return if node.parenthesized?
|
67
|
+
|
68
|
+
return unless (parent = node.parent)
|
69
|
+
return unless operator?(parent)
|
70
|
+
return unless greater_precedence?(node, parent)
|
71
|
+
|
72
|
+
add_offense(node) do |corrector|
|
73
|
+
autocorrect(corrector, node)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def precedence(node)
|
80
|
+
@node_precedences.fetch(node) do
|
81
|
+
PRECEDENCE.index { |operators| operators.include?(operator_name(node)) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def operator?(node)
|
86
|
+
(node.send_type? && RESTRICT_ON_SEND.include?(node.method_name)) || node.operator_keyword?
|
87
|
+
end
|
88
|
+
|
89
|
+
def greater_precedence?(node1, node2)
|
90
|
+
node1_precedence = precedence(node1)
|
91
|
+
node2_precedence = precedence(node2)
|
92
|
+
return false unless node1_precedence && node2_precedence
|
93
|
+
|
94
|
+
node2_precedence > node1_precedence
|
95
|
+
end
|
96
|
+
|
97
|
+
def operator_name(node)
|
98
|
+
if node.send_type?
|
99
|
+
node.method_name
|
100
|
+
else
|
101
|
+
node.operator.to_sym
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def autocorrect(corrector, node)
|
106
|
+
corrector.wrap(node, '(', ')')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -10,12 +10,6 @@ module RuboCop
|
|
10
10
|
# explicit by requiring parenthesis around complex range boundaries (anything
|
11
11
|
# that is not a basic literal: numerics, strings, symbols, etc.).
|
12
12
|
#
|
13
|
-
# NOTE: The cop auto-corrects by wrapping the entire boundary in parentheses, which
|
14
|
-
# makes the outcome more explicit but is possible to not be the intention of the
|
15
|
-
# programmer. For this reason, this cop's auto-correct is marked as unsafe (it
|
16
|
-
# will not change the behaviour of the code, but will not necessarily match the
|
17
|
-
# intent of the program).
|
18
|
-
#
|
19
13
|
# This cop can be configured with `RequireParenthesesForMethodChains` in order to
|
20
14
|
# specify whether method chains (including `self.foo`) should be wrapped in parens
|
21
15
|
# by this cop.
|
@@ -23,6 +17,13 @@ module RuboCop
|
|
23
17
|
# NOTE: Regardless of this configuration, if a method receiver is a basic literal
|
24
18
|
# value, it will be wrapped in order to prevent the ambiguity of `1..2.to_a`.
|
25
19
|
#
|
20
|
+
# @safety
|
21
|
+
# The cop auto-corrects by wrapping the entire boundary in parentheses, which
|
22
|
+
# makes the outcome more explicit but is possible to not be the intention of the
|
23
|
+
# programmer. For this reason, this cop's auto-correct is unsafe (it will not
|
24
|
+
# change the behaviour of the code, but will not necessarily match the
|
25
|
+
# intent of the program).
|
26
|
+
#
|
26
27
|
# @example
|
27
28
|
# # bad
|
28
29
|
# x || 1..2
|
@@ -55,7 +56,6 @@ module RuboCop
|
|
55
56
|
#
|
56
57
|
# # good
|
57
58
|
# (a.foo)..(b.bar)
|
58
|
-
#
|
59
59
|
class AmbiguousRange < Base
|
60
60
|
extend AutoCorrector
|
61
61
|
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
83
83
|
node.begin_type? ||
|
84
84
|
node.basic_literal? ||
|
85
85
|
node.variable? || node.const_type? ||
|
86
|
-
node.call_type? && acceptable_call?(node)
|
86
|
+
(node.call_type? && acceptable_call?(node))
|
87
87
|
end
|
88
88
|
|
89
89
|
def acceptable_call?(node)
|