rubocop 1.48.1 → 1.52.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 +3 -3
- data/config/default.yml +59 -12
- data/lib/rubocop/cli/command/execute_runner.rb +7 -2
- data/lib/rubocop/cli.rb +6 -6
- data/lib/rubocop/config.rb +5 -1
- data/lib/rubocop/config_loader.rb +8 -8
- data/lib/rubocop/config_obsoletion.rb +2 -2
- data/lib/rubocop/cop/autocorrect_logic.rb +28 -12
- data/lib/rubocop/cop/base.rb +5 -1
- data/lib/rubocop/cop/cop.rb +2 -2
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -1
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +33 -9
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +29 -2
- data/lib/rubocop/cop/layout/class_structure.rb +1 -0
- data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +0 -1
- data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +6 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +25 -34
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +7 -19
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +42 -52
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +38 -55
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
- data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +8 -27
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +7 -26
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +4 -21
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +6 -30
- data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -7
- data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_inside_parens.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +3 -3
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +122 -0
- data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
- data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +3 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +35 -15
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -1
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
- data/lib/rubocop/cop/lint/unreachable_loop.rb +3 -3
- data/lib/rubocop/cop/lint/useless_assignment.rb +59 -1
- data/lib/rubocop/cop/lint/useless_method_definition.rb +10 -2
- data/lib/rubocop/cop/lint/void.rb +69 -9
- data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +1 -0
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
- data/lib/rubocop/cop/mixin/comments_help.rb +7 -3
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +23 -4
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +22 -7
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
- data/lib/rubocop/cop/naming/variable_name.rb +6 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
- data/lib/rubocop/cop/style/attr.rb +11 -1
- data/lib/rubocop/cop/style/begin_block.rb +1 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +2 -2
- data/lib/rubocop/cop/style/class_equality_comparison.rb +51 -40
- data/lib/rubocop/cop/style/collection_compact.rb +19 -6
- data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
- data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
- data/lib/rubocop/cop/style/copyright.rb +6 -3
- data/lib/rubocop/cop/style/data_inheritance.rb +75 -0
- data/lib/rubocop/cop/style/dir.rb +1 -1
- data/lib/rubocop/cop/style/dir_empty.rb +8 -14
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +2 -2
- data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
- data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
- data/lib/rubocop/cop/style/file_empty.rb +3 -3
- data/lib/rubocop/cop/style/file_read.rb +2 -2
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +2 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
- data/lib/rubocop/cop/style/hash_except.rb +23 -12
- data/lib/rubocop/cop/style/hash_syntax.rb +4 -1
- data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
- data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +41 -12
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +9 -5
- data/lib/rubocop/cop/style/map_to_hash.rb +4 -1
- data/lib/rubocop/cop/style/map_to_set.rb +4 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -9
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +43 -36
- data/lib/rubocop/cop/style/multiline_method_signature.rb +6 -3
- data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
- data/lib/rubocop/cop/style/parallel_assignment.rb +26 -18
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -3
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +6 -4
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +183 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -2
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
- data/lib/rubocop/cop/style/require_order.rb +11 -5
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
- data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
- data/lib/rubocop/cop/style/semicolon.rb +12 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +5 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/trailing_body_on_class.rb +1 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/unless_logical_operators.rb +1 -0
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +33 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +1 -0
- data/lib/rubocop/cops_documentation_generator.rb +10 -3
- data/lib/rubocop/ext/regexp_node.rb +1 -1
- data/lib/rubocop/ext/regexp_parser.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
- data/lib/rubocop/options.rb +4 -1
- data/lib/rubocop/result_cache.rb +2 -2
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/server/cache.rb +1 -1
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/helper.rb +1 -1
- data/lib/rubocop/server/server_command/exec.rb +1 -1
- data/lib/rubocop/target_ruby.rb +3 -2
- data/lib/rubocop/version.rb +10 -6
- data/lib/rubocop.rb +8 -0
- metadata +20 -12
@@ -31,22 +31,26 @@ module RuboCop
|
|
31
31
|
def on_masgn(node)
|
32
32
|
lhs, rhs = *node
|
33
33
|
lhs_elements = *lhs
|
34
|
+
rhs = rhs.body if rhs.rescue_type?
|
34
35
|
rhs_elements = Array(rhs).compact # edge case for one constant
|
35
36
|
|
36
37
|
return if allowed_lhs?(lhs) || allowed_rhs?(rhs) ||
|
37
38
|
allowed_masign?(lhs_elements, rhs_elements)
|
38
39
|
|
39
|
-
|
40
|
+
range = node.source_range.begin.join(rhs.source_range.end)
|
41
|
+
|
42
|
+
add_offense(range) do |corrector|
|
43
|
+
autocorrect(corrector, node, lhs, rhs)
|
44
|
+
end
|
40
45
|
end
|
41
46
|
|
42
47
|
private
|
43
48
|
|
44
|
-
def autocorrect(corrector, node)
|
45
|
-
|
46
|
-
|
47
|
-
right_elements = Array(right).compact
|
49
|
+
def autocorrect(corrector, node, lhs, rhs)
|
50
|
+
left_elements = *lhs
|
51
|
+
right_elements = Array(rhs).compact
|
48
52
|
order = find_valid_order(left_elements, right_elements)
|
49
|
-
correction = assignment_corrector(node, order)
|
53
|
+
correction = assignment_corrector(node, rhs, order)
|
50
54
|
|
51
55
|
corrector.replace(correction.correction_range, correction.correction)
|
52
56
|
end
|
@@ -77,14 +81,19 @@ module RuboCop
|
|
77
81
|
node.block_type? || node.send_type?
|
78
82
|
end
|
79
83
|
|
80
|
-
def assignment_corrector(node, order)
|
81
|
-
|
84
|
+
def assignment_corrector(node, rhs, order)
|
85
|
+
if node.parent&.rescue_type?
|
86
|
+
_assignment, modifier = *node.parent
|
87
|
+
else
|
88
|
+
_assignment, modifier = *rhs.parent
|
89
|
+
end
|
90
|
+
|
82
91
|
if modifier_statement?(node.parent)
|
83
|
-
ModifierCorrector.new(node, config, order)
|
92
|
+
ModifierCorrector.new(node, rhs, modifier, config, order)
|
84
93
|
elsif rescue_modifier?(modifier)
|
85
|
-
RescueCorrector.new(node, config, order)
|
94
|
+
RescueCorrector.new(node, rhs, modifier, config, order)
|
86
95
|
else
|
87
|
-
GenericCorrector.new(node, config, order)
|
96
|
+
GenericCorrector.new(node, rhs, modifier, config, order)
|
88
97
|
end
|
89
98
|
end
|
90
99
|
|
@@ -181,10 +190,12 @@ module RuboCop
|
|
181
190
|
class GenericCorrector
|
182
191
|
include Alignment
|
183
192
|
|
184
|
-
attr_reader :
|
193
|
+
attr_reader :node, :rhs, :rescue_result, :config
|
185
194
|
|
186
|
-
def initialize(node, config, new_elements)
|
195
|
+
def initialize(node, rhs, modifier, config, new_elements)
|
187
196
|
@node = node
|
197
|
+
@rhs = rhs
|
198
|
+
_, _, @rescue_result = *modifier
|
188
199
|
@config = config
|
189
200
|
@new_elements = new_elements
|
190
201
|
end
|
@@ -228,13 +239,10 @@ module RuboCop
|
|
228
239
|
# protected by rescue
|
229
240
|
class RescueCorrector < GenericCorrector
|
230
241
|
def correction
|
231
|
-
_node, rescue_clause = *node.parent
|
232
|
-
_, _, rescue_result = *rescue_clause
|
233
|
-
|
234
242
|
# If the parallel assignment uses a rescue modifier and it is the
|
235
243
|
# only contents of a method, then we want to make use of the
|
236
244
|
# implicit begin
|
237
|
-
if
|
245
|
+
if rhs.parent.parent.parent&.def_type?
|
238
246
|
super + def_correction(rescue_result)
|
239
247
|
else
|
240
248
|
begin_correction(rescue_result)
|
@@ -242,7 +250,7 @@ module RuboCop
|
|
242
250
|
end
|
243
251
|
|
244
252
|
def correction_range
|
245
|
-
|
253
|
+
rhs.parent.parent.source_range
|
246
254
|
end
|
247
255
|
|
248
256
|
private
|
@@ -92,9 +92,8 @@ module RuboCop
|
|
92
92
|
|
93
93
|
def contains_delimiter?(node, delimiters)
|
94
94
|
delimiters_regexp = Regexp.union(delimiters)
|
95
|
-
|
96
|
-
|
97
|
-
.any? { |s| delimiters_regexp.match?(s) }
|
95
|
+
|
96
|
+
node.children.filter_map { |n| string_source(n) }.any?(delimiters_regexp)
|
98
97
|
end
|
99
98
|
|
100
99
|
def string_source(node)
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
|
45
45
|
# Report offense only if changing case doesn't change semantics,
|
46
46
|
# i.e., if the string would become dynamic or has special characters.
|
47
|
-
ast =
|
47
|
+
ast = parse(corrected(node.source)).ast
|
48
48
|
return if node.children != ast.children
|
49
49
|
|
50
50
|
add_offense(node.loc.begin) do |corrector|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for the instantiation of array using redundant `Array` constructor.
|
7
|
+
# Autocorrect replaces to array literal which is the simplest and fastest.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# Array.new([])
|
13
|
+
# Array[]
|
14
|
+
# Array([])
|
15
|
+
# Array.new(['foo', 'foo', 'foo'])
|
16
|
+
# Array['foo', 'foo', 'foo']
|
17
|
+
# Array(['foo', 'foo', 'foo'])
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# []
|
21
|
+
# ['foo', 'foo', 'foo']
|
22
|
+
# Array.new(3, 'foo')
|
23
|
+
# Array.new(3) { 'foo' }
|
24
|
+
#
|
25
|
+
class RedundantArrayConstructor < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
MSG = 'Remove the redundant `Array` constructor.'
|
29
|
+
|
30
|
+
RESTRICT_ON_SEND = %i[new [] Array].freeze
|
31
|
+
|
32
|
+
# @!method redundant_array_constructor(node)
|
33
|
+
def_node_matcher :redundant_array_constructor, <<~PATTERN
|
34
|
+
{
|
35
|
+
(send
|
36
|
+
(const {nil? cbase} :Array) :new
|
37
|
+
$(array ...))
|
38
|
+
(send
|
39
|
+
(const {nil? cbase} :Array) :[]
|
40
|
+
$...)
|
41
|
+
(send
|
42
|
+
nil? :Array
|
43
|
+
$(array ...))
|
44
|
+
}
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
def on_send(node)
|
48
|
+
return unless (array_literal = redundant_array_constructor(node))
|
49
|
+
|
50
|
+
receiver = node.receiver
|
51
|
+
selector = node.loc.selector
|
52
|
+
|
53
|
+
if node.method?(:new)
|
54
|
+
range = receiver.source_range.join(selector)
|
55
|
+
replacement = array_literal
|
56
|
+
elsif node.method?(:Array)
|
57
|
+
range = selector
|
58
|
+
replacement = array_literal
|
59
|
+
else
|
60
|
+
range = receiver
|
61
|
+
replacement = selector.begin.join(node.source_range.end)
|
62
|
+
end
|
63
|
+
|
64
|
+
register_offense(range, node, replacement)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def register_offense(range, node, replacement)
|
70
|
+
add_offense(range) do |corrector|
|
71
|
+
corrector.replace(node, replacement.source)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -3,11 +3,13 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Identifies places where `fetch(key) { value }`
|
7
|
-
# can be replaced by `fetch(key, value)`.
|
6
|
+
# Identifies places where `fetch(key) { value }` can be replaced by `fetch(key, value)`.
|
8
7
|
#
|
9
|
-
# In such cases `fetch(key, value)` method is faster
|
10
|
-
#
|
8
|
+
# In such cases `fetch(key, value)` method is faster than `fetch(key) { value }`.
|
9
|
+
#
|
10
|
+
# NOTE: The block string `'value'` in `hash.fetch(:key) { 'value' }` is detected
|
11
|
+
# when frozen string literal magic comment is enabled (i.e. `# frozen_string_literal: true`),
|
12
|
+
# but not when disabled.
|
11
13
|
#
|
12
14
|
# @safety
|
13
15
|
# This cop is unsafe because it cannot be guaranteed that the receiver
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Identifies usages of `any?`, `empty?` or `none?` predicate methods
|
7
|
+
# chained to `select`/`filter`/`find_all` and change them to use predicate method instead.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# arr.select { |x| x > 1 }.any?
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# arr.any? { |x| x > 1 }
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# arr.select { |x| x > 1 }.empty?
|
18
|
+
# arr.select { |x| x > 1 }.none?
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# arr.none? { |x| x > 1 }
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# relation.select(:name).any?
|
25
|
+
# arr.select { |x| x > 1 }.any?(&:odd?)
|
26
|
+
#
|
27
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
28
|
+
# # good
|
29
|
+
# arr.select { |x| x > 1 }.many?
|
30
|
+
#
|
31
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
32
|
+
# # bad
|
33
|
+
# arr.select { |x| x > 1 }.many?
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# arr.many? { |x| x > 1 }
|
37
|
+
#
|
38
|
+
class RedundantFilterChain < Base
|
39
|
+
extend AutoCorrector
|
40
|
+
|
41
|
+
MSG = 'Use `%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
|
42
|
+
|
43
|
+
RAILS_METHODS = %i[many?].freeze
|
44
|
+
RESTRICT_ON_SEND = (%i[any? empty? none? one?] + RAILS_METHODS).freeze
|
45
|
+
|
46
|
+
# @!method select_predicate?(node)
|
47
|
+
def_node_matcher :select_predicate?, <<~PATTERN
|
48
|
+
(send
|
49
|
+
{
|
50
|
+
(block $(send _ {:select :filter :find_all}) ...)
|
51
|
+
$(send _ {:select :filter :find_all} block_pass_type?)
|
52
|
+
}
|
53
|
+
${:#{RESTRICT_ON_SEND.join(' :')}})
|
54
|
+
PATTERN
|
55
|
+
|
56
|
+
REPLACEMENT_METHODS = {
|
57
|
+
any?: :any?,
|
58
|
+
empty?: :none?,
|
59
|
+
none?: :none?,
|
60
|
+
one?: :one?,
|
61
|
+
many?: :many?
|
62
|
+
}.freeze
|
63
|
+
private_constant :REPLACEMENT_METHODS
|
64
|
+
|
65
|
+
def on_send(node)
|
66
|
+
return if node.arguments? || node.block_node
|
67
|
+
|
68
|
+
select_predicate?(node) do |select_node, filter_method|
|
69
|
+
return if RAILS_METHODS.include?(filter_method) && !active_support_extensions_enabled?
|
70
|
+
|
71
|
+
register_offense(select_node, node)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def register_offense(select_node, predicate_node)
|
78
|
+
replacement = REPLACEMENT_METHODS[predicate_node.method_name]
|
79
|
+
message = format(MSG, prefer: replacement,
|
80
|
+
first_method: select_node.method_name,
|
81
|
+
second_method: predicate_node.method_name)
|
82
|
+
|
83
|
+
offense_range = offense_range(select_node, predicate_node)
|
84
|
+
|
85
|
+
add_offense(offense_range, message: message) do |corrector|
|
86
|
+
corrector.remove(predicate_range(predicate_node))
|
87
|
+
corrector.replace(select_node.loc.selector, replacement)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def offense_range(select_node, predicate_node)
|
92
|
+
select_node.loc.selector.join(predicate_node.loc.selector)
|
93
|
+
end
|
94
|
+
|
95
|
+
def predicate_range(predicate_node)
|
96
|
+
predicate_node.receiver.source_range.end.join(predicate_node.loc.selector)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Check for redundant line continuation.
|
7
|
+
#
|
8
|
+
# This cop marks a line continuation as redundant if removing the backslash
|
9
|
+
# does not result in a syntax error.
|
10
|
+
# However, a backslash at the end of a comment or
|
11
|
+
# for string concatenation is not redundant and is not considered an offense.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # bad
|
15
|
+
# foo. \
|
16
|
+
# bar
|
17
|
+
# foo \
|
18
|
+
# &.bar \
|
19
|
+
# .baz
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# foo.
|
23
|
+
# bar
|
24
|
+
# foo
|
25
|
+
# &.bar
|
26
|
+
# .baz
|
27
|
+
#
|
28
|
+
# # bad
|
29
|
+
# [foo, \
|
30
|
+
# bar]
|
31
|
+
# {foo: \
|
32
|
+
# bar}
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# [foo,
|
36
|
+
# bar]
|
37
|
+
# {foo:
|
38
|
+
# bar}
|
39
|
+
#
|
40
|
+
# # bad
|
41
|
+
# foo(bar, \
|
42
|
+
# baz)
|
43
|
+
#
|
44
|
+
# # good
|
45
|
+
# foo(bar,
|
46
|
+
# baz)
|
47
|
+
#
|
48
|
+
# # also good - backslash in string concatenation is not redundant
|
49
|
+
# foo('bar' \
|
50
|
+
# 'baz')
|
51
|
+
#
|
52
|
+
# # also good - backslash at the end of a comment is not redundant
|
53
|
+
# foo(bar, # \
|
54
|
+
# baz)
|
55
|
+
#
|
56
|
+
# # also good - backslash at the line following the newline begins with a + or -,
|
57
|
+
# # it is not redundant
|
58
|
+
# 1 \
|
59
|
+
# + 2 \
|
60
|
+
# - 3
|
61
|
+
#
|
62
|
+
# # also good - backslash with newline between the method name and its arguments,
|
63
|
+
# # it is not redundant.
|
64
|
+
# some_method \
|
65
|
+
# (argument)
|
66
|
+
#
|
67
|
+
class RedundantLineContinuation < Base
|
68
|
+
include MatchRange
|
69
|
+
extend AutoCorrector
|
70
|
+
|
71
|
+
MSG = 'Redundant line continuation.'
|
72
|
+
ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
|
73
|
+
ARGUMENT_TYPES = %i[
|
74
|
+
kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
|
75
|
+
tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
|
76
|
+
].freeze
|
77
|
+
|
78
|
+
def on_new_investigation
|
79
|
+
return unless processed_source.ast
|
80
|
+
|
81
|
+
each_match_range(processed_source.ast.source_range, /(\\\n)/) do |range|
|
82
|
+
next if require_line_continuation?(range)
|
83
|
+
next unless redundant_line_continuation?(range)
|
84
|
+
|
85
|
+
add_offense(range) do |corrector|
|
86
|
+
corrector.remove_leading(range, 1)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def require_line_continuation?(range)
|
94
|
+
!ends_with_backslash_without_comment?(range.source_line) ||
|
95
|
+
string_concatenation?(range.source_line) ||
|
96
|
+
start_with_arithmetic_operator?(processed_source[range.line]) ||
|
97
|
+
inside_string_literal_or_method_with_argument?(range)
|
98
|
+
end
|
99
|
+
|
100
|
+
def ends_with_backslash_without_comment?(source_line)
|
101
|
+
source_line.gsub(/#.+/, '').end_with?('\\')
|
102
|
+
end
|
103
|
+
|
104
|
+
def string_concatenation?(source_line)
|
105
|
+
/["']\s*\\\z/.match?(source_line)
|
106
|
+
end
|
107
|
+
|
108
|
+
def inside_string_literal_or_method_with_argument?(range)
|
109
|
+
processed_source.tokens.each_cons(2).any? do |token, next_token|
|
110
|
+
inside_string_literal?(range, token) || method_with_argument?(token, next_token)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def redundant_line_continuation?(range)
|
115
|
+
return true unless (node = find_node_for_line(range.line))
|
116
|
+
return false if argument_newline?(node)
|
117
|
+
|
118
|
+
source = node.parent ? node.parent.source : node.source
|
119
|
+
parse(source.gsub(/\\\n/, "\n")).valid_syntax?
|
120
|
+
end
|
121
|
+
|
122
|
+
def inside_string_literal?(range, token)
|
123
|
+
ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
|
124
|
+
end
|
125
|
+
|
126
|
+
# A method call without parentheses such as the following cannot remove `\`:
|
127
|
+
#
|
128
|
+
# do_something \
|
129
|
+
# argument
|
130
|
+
def method_with_argument?(current_token, next_token)
|
131
|
+
current_token.type == :tIDENTIFIER && ARGUMENT_TYPES.include?(next_token.type)
|
132
|
+
end
|
133
|
+
|
134
|
+
def argument_newline?(node)
|
135
|
+
node = node.children.first if node.root? && node.begin_type?
|
136
|
+
|
137
|
+
if argument_is_method?(node)
|
138
|
+
argument_newline?(node.first_argument)
|
139
|
+
else
|
140
|
+
return false unless method_call_with_arguments?(node)
|
141
|
+
|
142
|
+
node.loc.selector.line != node.first_argument.loc.line
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def find_node_for_line(line)
|
147
|
+
processed_source.ast.each_node do |node|
|
148
|
+
return node if same_line?(node, line)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def same_line?(node, line)
|
153
|
+
return unless (source_range = node.source_range)
|
154
|
+
|
155
|
+
if node.is_a?(AST::StrNode)
|
156
|
+
if node.heredoc?
|
157
|
+
(node.loc.heredoc_body.line..node.loc.heredoc_body.last_line).cover?(line)
|
158
|
+
else
|
159
|
+
(source_range.line..source_range.last_line).cover?(line)
|
160
|
+
end
|
161
|
+
else
|
162
|
+
source_range.line == line
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def argument_is_method?(node)
|
167
|
+
return false unless node.send_type?
|
168
|
+
return false unless (first_argument = node.first_argument)
|
169
|
+
|
170
|
+
method_call_with_arguments?(first_argument)
|
171
|
+
end
|
172
|
+
|
173
|
+
def method_call_with_arguments?(node)
|
174
|
+
node.call_type? && !node.arguments.empty?
|
175
|
+
end
|
176
|
+
|
177
|
+
def start_with_arithmetic_operator?(source_line)
|
178
|
+
%r{\A\s*[+\-*/%]}.match?(source_line)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def like_method_argument_parentheses?(node)
|
101
|
-
node.send_type? && node.arguments.one? &&
|
101
|
+
node.send_type? && node.arguments.one? && !node.parenthesized? &&
|
102
102
|
!node.arithmetic_operation? && node.first_argument.begin_type?
|
103
103
|
end
|
104
104
|
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
next if expr.type != :set || expr.expressions.size != 1
|
64
64
|
next if expr.negative?
|
65
65
|
next if %i[set posixclass nonposixclass].include?(expr.expressions.first.type)
|
66
|
-
next if
|
66
|
+
next if multiple_codepoints?(expr.expressions.first)
|
67
67
|
|
68
68
|
yield expr
|
69
69
|
end
|
@@ -80,7 +80,7 @@ module RuboCop
|
|
80
80
|
!non_redundant
|
81
81
|
end
|
82
82
|
|
83
|
-
def
|
83
|
+
def multiple_codepoints?(expression)
|
84
84
|
expression.respond_to?(:codepoints) && expression.codepoints.count >= 2
|
85
85
|
end
|
86
86
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.
|
7
|
+
# Autocorrect replaces to regexp literal which is the simplest and fastest.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# Regexp.new(/regexp/)
|
13
|
+
# Regexp.compile(/regexp/)
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# /regexp/
|
17
|
+
# Regexp.new('regexp')
|
18
|
+
# Regexp.compile('regexp')
|
19
|
+
#
|
20
|
+
class RedundantRegexpConstructor < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
23
|
+
MSG = 'Remove the redundant `Regexp.%<method>s`.'
|
24
|
+
RESTRICT_ON_SEND = %i[new compile].freeze
|
25
|
+
|
26
|
+
# @!method redundant_regexp_constructor(node)
|
27
|
+
def_node_matcher :redundant_regexp_constructor, <<~PATTERN
|
28
|
+
(send
|
29
|
+
(const {nil? cbase} :Regexp) {:new :compile}
|
30
|
+
(regexp $... (regopt $...)))
|
31
|
+
PATTERN
|
32
|
+
|
33
|
+
def on_send(node)
|
34
|
+
return unless (regexp, regopt = redundant_regexp_constructor(node))
|
35
|
+
|
36
|
+
add_offense(node, message: format(MSG, method: node.method_name)) do |corrector|
|
37
|
+
pattern = regexp.map(&:source).join
|
38
|
+
regopt = regopt.join
|
39
|
+
|
40
|
+
corrector.replace(node, "/#{pattern}/#{regopt}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
# Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
|
110
|
-
# It's for compatibility with
|
110
|
+
# It's for compatibility with regexp_parser 1.8 and will never be maintained.
|
111
111
|
else
|
112
112
|
def each_escape(node)
|
113
113
|
node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
|
@@ -36,7 +36,6 @@ module RuboCop
|
|
36
36
|
# STR
|
37
37
|
class RedundantStringEscape < Base
|
38
38
|
include MatchRange
|
39
|
-
include RangeHelp
|
40
39
|
extend AutoCorrector
|
41
40
|
|
42
41
|
MSG = 'Redundant escape of %<char>s inside string literal.'
|
@@ -64,10 +63,10 @@ module RuboCop
|
|
64
63
|
def str_contents_range(node)
|
65
64
|
if heredoc?(node)
|
66
65
|
node.loc.heredoc_body
|
66
|
+
elsif node.str_type?
|
67
|
+
node.source_range
|
67
68
|
elsif begin_loc_present?(node)
|
68
69
|
contents_range(node)
|
69
|
-
else
|
70
|
-
node.source_range
|
71
70
|
end
|
72
71
|
end
|
73
72
|
|
@@ -3,7 +3,16 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Enforces using
|
6
|
+
# Enforces using `//` or `%r` around regular expressions.
|
7
|
+
#
|
8
|
+
# NOTE: The following `%r` cases using a regexp starts with a blank or `=`
|
9
|
+
# as a method argument allowed to prevent syntax errors.
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# ----
|
13
|
+
# do_something %r{ regexp} # `do_something / regexp/` is an invalid syntax.
|
14
|
+
# do_something %r{=regexp} # `do_something /=regexp/` is an invalid syntax.
|
15
|
+
# ----
|
7
16
|
#
|
8
17
|
# @example EnforcedStyle: slashes (default)
|
9
18
|
# # bad
|
@@ -151,7 +160,7 @@ module RuboCop
|
|
151
160
|
|
152
161
|
def allowed_omit_parentheses_with_percent_r_literal?(node)
|
153
162
|
return false unless node.parent&.call_type?
|
154
|
-
return true if node.content.start_with?(' ')
|
163
|
+
return true if node.content.start_with?(' ', '=')
|
155
164
|
|
156
165
|
enforced_style = config.for_cop('Style/MethodCallWithArgsParentheses')['EnforcedStyle']
|
157
166
|
|
@@ -88,10 +88,7 @@ module RuboCop
|
|
88
88
|
return unless previous_older_sibling
|
89
89
|
|
90
90
|
add_offense(node, message: format(MSG, name: node.method_name)) do |corrector|
|
91
|
-
corrector
|
92
|
-
range_with_comments_and_lines(previous_older_sibling),
|
93
|
-
range_with_comments_and_lines(node.parent.if_type? ? node.parent : node)
|
94
|
-
)
|
91
|
+
autocorrect(corrector, node, previous_older_sibling)
|
95
92
|
end
|
96
93
|
end
|
97
94
|
|
@@ -109,11 +106,20 @@ module RuboCop
|
|
109
106
|
break unless sibling&.send_type? && sibling&.method?(node.method_name)
|
110
107
|
break unless sibling.arguments? && !sibling.receiver
|
111
108
|
break unless in_same_section?(sibling, node)
|
109
|
+
break unless node.first_argument.str_type? && sibling.first_argument.str_type?
|
112
110
|
|
113
|
-
node.first_argument.
|
111
|
+
node.first_argument.value < sibling.first_argument.value
|
114
112
|
end
|
115
113
|
end
|
116
114
|
|
115
|
+
def autocorrect(corrector, node, previous_older_sibling)
|
116
|
+
range1 = range_with_comments_and_lines(previous_older_sibling)
|
117
|
+
range2 = range_with_comments_and_lines(node.parent.if_type? ? node.parent : node)
|
118
|
+
|
119
|
+
corrector.remove(range2)
|
120
|
+
corrector.insert_before(range1, range2.source)
|
121
|
+
end
|
122
|
+
|
117
123
|
def search_node(node)
|
118
124
|
node.parent.if_type? ? node.parent : node
|
119
125
|
end
|
@@ -3,9 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks for uses of rescue in its modifier form
|
7
|
-
#
|
8
|
-
# The cop to check `rescue` in its modifier form is added for following
|
6
|
+
# Checks for uses of `rescue` in its modifier form is added for following
|
9
7
|
# reasons:
|
10
8
|
#
|
11
9
|
# * The syntax of modifier form `rescue` can be misleading because it
|