rubocop 1.22.3 → 1.26.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -3
- data/config/default.yml +110 -19
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
- data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
- data/lib/rubocop/cli/command/show_docs_url.rb +48 -0
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +2 -1
- data/lib/rubocop/config_loader_resolver.rb +1 -1
- data/lib/rubocop/cop/badge.rb +7 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/if_then_corrector.rb +55 -0
- data/lib/rubocop/cop/documentation.rb +19 -2
- data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
- data/lib/rubocop/cop/gemspec/require_mfa.rb +145 -0
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -3
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
- data/lib/rubocop/cop/generator.rb +7 -11
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +46 -0
- data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +47 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +3 -1
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +36 -9
- data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/comment_indentation.rb +31 -2
- data/lib/rubocop/cop/layout/dot_position.rb +4 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +5 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +7 -2
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +7 -8
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_colon.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_first_arg.rb +4 -0
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
- data/lib/rubocop/cop/lint/ambiguous_range.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -1
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +16 -4
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +6 -0
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +10 -5
- data/lib/rubocop/cop/lint/inherit_exception.rb +19 -28
- data/lib/rubocop/cop/lint/number_conversion.rb +5 -2
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +10 -6
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +5 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +3 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
- data/lib/rubocop/cop/lint/useless_times.rb +13 -9
- data/lib/rubocop/cop/metrics/block_length.rb +1 -0
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -9
- data/lib/rubocop/cop/metrics/method_length.rb +1 -0
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +1 -1
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +5 -0
- data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +4 -3
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +82 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +17 -6
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -5
- data/lib/rubocop/cop/naming/block_forwarding.rb +121 -0
- data/lib/rubocop/cop/naming/file_name.rb +37 -4
- data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +11 -1
- data/lib/rubocop/cop/security/yaml_load.rb +9 -3
- data/lib/rubocop/cop/style/character_literal.rb +8 -1
- data/lib/rubocop/cop/style/collection_compact.rb +31 -13
- data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
- data/lib/rubocop/cop/style/def_with_parentheses.rb +16 -11
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +10 -0
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/file_read.rb +112 -0
- data/lib/rubocop/cop/style/file_write.rb +124 -0
- data/lib/rubocop/cop/style/for.rb +4 -0
- data/lib/rubocop/cop/style/format_string_token.rb +2 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +2 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +36 -0
- data/lib/rubocop/cop/style/hash_transform_keys.rb +6 -6
- data/lib/rubocop/cop/style/hash_transform_values.rb +6 -6
- data/lib/rubocop/cop/style/if_inside_else.rb +15 -0
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
- data/lib/rubocop/cop/style/lambda_call.rb +12 -20
- data/lib/rubocop/cop/style/map_to_hash.rb +68 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -13
- data/lib/rubocop/cop/style/nested_file_dirname.rb +66 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +10 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +18 -39
- data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +3 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
- data/lib/rubocop/cop/style/quoted_symbols.rb +11 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -6
- data/lib/rubocop/cop/style/redundant_interpolation.rb +17 -3
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +5 -1
- data/lib/rubocop/cop/style/redundant_self.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -5
- data/lib/rubocop/cop/style/sample.rb +5 -3
- data/lib/rubocop/cop/style/select_by_regexp.rb +6 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +53 -13
- data/lib/rubocop/cop/style/string_concatenation.rb +7 -1
- data/lib/rubocop/cop/style/swap_values.rb +2 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +16 -2
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
- data/lib/rubocop/cop/style/unless_else.rb +4 -0
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +9 -1
- data/lib/rubocop/cop/variable_force.rb +1 -5
- data/lib/rubocop/cops_documentation_generator.rb +2 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -2
- data/lib/rubocop/formatter/html_formatter.rb +5 -2
- data/lib/rubocop/formatter/json_formatter.rb +4 -1
- data/lib/rubocop/options.rb +14 -3
- data/lib/rubocop/remote_config.rb +2 -4
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/yaml_duplication_checker.rb +1 -1
- data/lib/rubocop.rb +12 -0
- metadata +22 -7
@@ -30,15 +30,17 @@ module RuboCop
|
|
30
30
|
def on_send(node)
|
31
31
|
return unless arrow_lambda_with_args?(node)
|
32
32
|
|
33
|
-
lambda_node = range_of_offense(node)
|
34
|
-
|
35
33
|
if style == :require_space && !space_after_arrow?(node)
|
34
|
+
lambda_node = range_of_offense(node)
|
35
|
+
|
36
36
|
add_offense(lambda_node, message: MSG_REQUIRE_SPACE) do |corrector|
|
37
|
-
corrector.insert_before(node
|
37
|
+
corrector.insert_before(lambda_arguments(node), ' ')
|
38
38
|
end
|
39
39
|
elsif style == :require_no_space && space_after_arrow?(node)
|
40
|
-
|
41
|
-
|
40
|
+
space = space_after_arrow(node)
|
41
|
+
|
42
|
+
add_offense(space, message: MSG_REQUIRE_NO_SPACE) do |corrector|
|
43
|
+
corrector.remove(space)
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
@@ -66,6 +68,10 @@ module RuboCop
|
|
66
68
|
node.parent.arguments.loc.expression.end_pos
|
67
69
|
)
|
68
70
|
end
|
71
|
+
|
72
|
+
def lambda_arguments(node)
|
73
|
+
node.parent.children[1]
|
74
|
+
end
|
69
75
|
end
|
70
76
|
end
|
71
77
|
end
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
# Ranges have quite low precedence, which leads to unexpected behaviour when
|
9
9
|
# using a range with other operators. This cop avoids that by making ranges
|
10
10
|
# explicit by requiring parenthesis around complex range boundaries (anything
|
11
|
-
# that is not a
|
11
|
+
# that is not a literal: numerics, strings, symbols, etc.).
|
12
12
|
#
|
13
13
|
# This cop can be configured with `RequireParenthesesForMethodChains` in order to
|
14
14
|
# specify whether method chains (including `self.foo`) should be wrapped in parens
|
@@ -81,7 +81,7 @@ module RuboCop
|
|
81
81
|
|
82
82
|
def acceptable?(node)
|
83
83
|
node.begin_type? ||
|
84
|
-
node.
|
84
|
+
node.literal? ||
|
85
85
|
node.variable? || node.const_type? || node.self_type? ||
|
86
86
|
(node.call_type? && acceptable_call?(node))
|
87
87
|
end
|
@@ -30,7 +30,11 @@ module RuboCop
|
|
30
30
|
|
31
31
|
def on_new_investigation
|
32
32
|
processed_source.diagnostics.each do |diagnostic|
|
33
|
-
|
33
|
+
if target_ruby_version >= 3.0
|
34
|
+
next unless diagnostic.reason == :ambiguous_regexp
|
35
|
+
else
|
36
|
+
next unless diagnostic.reason == :ambiguous_literal
|
37
|
+
end
|
34
38
|
|
35
39
|
offense_node = find_offense_node_by(diagnostic)
|
36
40
|
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
# File.exists?(some_path)
|
13
13
|
# Dir.exists?(some_path)
|
14
14
|
# iterator?
|
15
|
+
# ENV.freeze # Calling `Env.freeze` raises `TypeError` since Ruby 2.7.
|
15
16
|
# Socket.gethostbyname(host)
|
16
17
|
# Socket.gethostbyaddr(host)
|
17
18
|
#
|
@@ -22,6 +23,7 @@ module RuboCop
|
|
22
23
|
# File.exist?(some_path)
|
23
24
|
# Dir.exist?(some_path)
|
24
25
|
# block_given?
|
26
|
+
# ENV # `ENV.freeze` cannot prohibit changes to environment variables.
|
25
27
|
# Addrinfo.getaddrinfo(nodename, service)
|
26
28
|
# Addrinfo.tcp(host, port).getnameinfo
|
27
29
|
class DeprecatedClassMethods < Base
|
@@ -106,6 +108,9 @@ module RuboCop
|
|
106
108
|
|
107
109
|
DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?),
|
108
110
|
|
111
|
+
DeprecatedClassMethod.new(:freeze, class_constant: :ENV) =>
|
112
|
+
Replacement.new(nil, class_constant: :ENV),
|
113
|
+
|
109
114
|
DeprecatedClassMethod.new(:gethostbyaddr, class_constant: :Socket, correctable: false) =>
|
110
115
|
Replacement.new(:getnameinfo, class_constant: :Addrinfo, instance_method: true),
|
111
116
|
|
@@ -120,11 +125,18 @@ module RuboCop
|
|
120
125
|
|
121
126
|
def on_send(node)
|
122
127
|
check(node) do |deprecated|
|
123
|
-
|
128
|
+
prefer = replacement(deprecated)
|
129
|
+
message = format(MSG, current: deprecated, prefer: prefer)
|
130
|
+
current_method = node.loc.selector
|
131
|
+
|
132
|
+
add_offense(current_method, message: message) do |corrector|
|
133
|
+
next unless deprecated.correctable?
|
124
134
|
|
125
|
-
|
126
|
-
|
127
|
-
|
135
|
+
if (preferred_method = prefer.method)
|
136
|
+
corrector.replace(current_method, preferred_method)
|
137
|
+
else
|
138
|
+
corrector.remove(node.loc.dot)
|
139
|
+
corrector.remove(current_method)
|
128
140
|
end
|
129
141
|
end
|
130
142
|
end
|
@@ -55,8 +55,14 @@ module RuboCop
|
|
55
55
|
...)
|
56
56
|
PATTERN
|
57
57
|
|
58
|
+
# @!method digest_const?(node)
|
59
|
+
def_node_matcher :digest_const?, <<~PATTERN
|
60
|
+
(const _ :Digest)
|
61
|
+
PATTERN
|
62
|
+
|
58
63
|
def on_send(node)
|
59
64
|
return if node.arguments.any? { |arg| arg.variable? || arg.send_type? || arg.const_type? }
|
65
|
+
return if digest_const?(node.receiver)
|
60
66
|
return unless algorithm_const(node)
|
61
67
|
|
62
68
|
message = message(node)
|
@@ -20,6 +20,10 @@ module RuboCop
|
|
20
20
|
# # good
|
21
21
|
# io.wait_writable(timeout)
|
22
22
|
#
|
23
|
+
# @safety
|
24
|
+
# This cop's autocorrection is unsafe because `NoMethodError` occurs
|
25
|
+
# if `require 'io/wait'` is not called.
|
26
|
+
#
|
23
27
|
class IncompatibleIoSelectWithFiberScheduler < Base
|
24
28
|
extend AutoCorrector
|
25
29
|
|
@@ -29,11 +33,12 @@ module RuboCop
|
|
29
33
|
# @!method io_select(node)
|
30
34
|
def_node_matcher :io_select, <<~PATTERN
|
31
35
|
(send
|
32
|
-
(const {nil? cbase} :IO) :select
|
36
|
+
(const {nil? cbase} :IO) :select $...)
|
33
37
|
PATTERN
|
34
38
|
|
35
39
|
def on_send(node)
|
36
|
-
|
40
|
+
read, write, _excepts, timeout = *io_select(node)
|
41
|
+
return unless read
|
37
42
|
return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
|
38
43
|
|
39
44
|
preferred = preferred_method(read, write, timeout)
|
@@ -47,13 +52,13 @@ module RuboCop
|
|
47
52
|
private
|
48
53
|
|
49
54
|
def scheduler_compatible?(io1, io2)
|
50
|
-
return false unless io1
|
55
|
+
return false unless io1&.array_type? && io1.values.size == 1
|
51
56
|
|
52
|
-
io2
|
57
|
+
io2&.array_type? ? io2.values.empty? : (io2.nil? || io2.nil_type?)
|
53
58
|
end
|
54
59
|
|
55
60
|
def preferred_method(read, write, timeout)
|
56
|
-
timeout_argument = timeout.
|
61
|
+
timeout_argument = timeout.nil? ? '' : "(#{timeout.source})"
|
57
62
|
|
58
63
|
if read.array_type? && read.values[0]
|
59
64
|
"#{read.values[0].source}.wait_readable#{timeout_argument}"
|
@@ -3,12 +3,16 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# This cop looks for error classes inheriting from `Exception
|
7
|
-
#
|
8
|
-
# `
|
9
|
-
# `RuntimeError` (default) or `StandardError` instead.
|
6
|
+
# This cop looks for error classes inheriting from `Exception`.
|
7
|
+
# It is configurable to suggest using either `StandardError` (default) or
|
8
|
+
# `RuntimeError` instead.
|
10
9
|
#
|
11
|
-
# @
|
10
|
+
# @safety
|
11
|
+
# This cop's autocorrection is unsafe because `rescue` that omit
|
12
|
+
# exception class handle `StandardError` and its subclasses,
|
13
|
+
# but not `Exception` and its subclasses.
|
14
|
+
#
|
15
|
+
# @example EnforcedStyle: standard_error (default)
|
12
16
|
# # bad
|
13
17
|
#
|
14
18
|
# class C < Exception; end
|
@@ -17,11 +21,11 @@ module RuboCop
|
|
17
21
|
#
|
18
22
|
# # good
|
19
23
|
#
|
20
|
-
# class C <
|
24
|
+
# class C < StandardError; end
|
21
25
|
#
|
22
|
-
# C = Class.new(
|
26
|
+
# C = Class.new(StandardError)
|
23
27
|
#
|
24
|
-
# @example EnforcedStyle:
|
28
|
+
# @example EnforcedStyle: runtime_error
|
25
29
|
# # bad
|
26
30
|
#
|
27
31
|
# class C < Exception; end
|
@@ -30,31 +34,18 @@ module RuboCop
|
|
30
34
|
#
|
31
35
|
# # good
|
32
36
|
#
|
33
|
-
# class C <
|
37
|
+
# class C < RuntimeError; end
|
34
38
|
#
|
35
|
-
# C = Class.new(
|
39
|
+
# C = Class.new(RuntimeError)
|
36
40
|
class InheritException < Base
|
37
41
|
include ConfigurableEnforcedStyle
|
38
42
|
extend AutoCorrector
|
39
43
|
|
40
|
-
MSG = 'Inherit from `%<prefer>s` instead of
|
44
|
+
MSG = 'Inherit from `%<prefer>s` instead of `Exception`.'
|
41
45
|
PREFERRED_BASE_CLASS = {
|
42
46
|
runtime_error: 'RuntimeError',
|
43
47
|
standard_error: 'StandardError'
|
44
48
|
}.freeze
|
45
|
-
ILLEGAL_CLASSES = %w[
|
46
|
-
Exception
|
47
|
-
SystemStackError
|
48
|
-
NoMemoryError
|
49
|
-
SecurityError
|
50
|
-
NotImplementedError
|
51
|
-
LoadError
|
52
|
-
SyntaxError
|
53
|
-
ScriptError
|
54
|
-
Interrupt
|
55
|
-
SignalException
|
56
|
-
SystemExit
|
57
|
-
].freeze
|
58
49
|
|
59
50
|
RESTRICT_ON_SEND = %i[new].freeze
|
60
51
|
|
@@ -66,7 +57,7 @@ module RuboCop
|
|
66
57
|
PATTERN
|
67
58
|
|
68
59
|
def on_class(node)
|
69
|
-
return unless node.parent_class &&
|
60
|
+
return unless node.parent_class && exception_class?(node.parent_class)
|
70
61
|
|
71
62
|
message = message(node.parent_class)
|
72
63
|
|
@@ -77,7 +68,7 @@ module RuboCop
|
|
77
68
|
|
78
69
|
def on_send(node)
|
79
70
|
constant = class_new_call?(node)
|
80
|
-
return unless constant &&
|
71
|
+
return unless constant && exception_class?(constant)
|
81
72
|
|
82
73
|
message = message(constant)
|
83
74
|
|
@@ -92,8 +83,8 @@ module RuboCop
|
|
92
83
|
format(MSG, prefer: preferred_base_class, current: node.const_name)
|
93
84
|
end
|
94
85
|
|
95
|
-
def
|
96
|
-
|
86
|
+
def exception_class?(class_node)
|
87
|
+
class_node.const_name == 'Exception'
|
97
88
|
end
|
98
89
|
|
99
90
|
def preferred_base_class
|
@@ -30,6 +30,7 @@ module RuboCop
|
|
30
30
|
# '10'.to_i
|
31
31
|
# '10.2'.to_f
|
32
32
|
# '10'.to_c
|
33
|
+
# '1/3'.to_r
|
33
34
|
# ['1', '2', '3'].map(&:to_i)
|
34
35
|
# foo.try(:to_f)
|
35
36
|
# bar.send(:to_c)
|
@@ -39,6 +40,7 @@ module RuboCop
|
|
39
40
|
# Integer('10', 10)
|
40
41
|
# Float('10.2')
|
41
42
|
# Complex('10')
|
43
|
+
# Rational('1/3')
|
42
44
|
# ['1', '2', '3'].map { |i| Integer(i, 10) }
|
43
45
|
# foo.try { |i| Float(i) }
|
44
46
|
# bar.send { |i| Complex(i) }
|
@@ -59,13 +61,14 @@ module RuboCop
|
|
59
61
|
CONVERSION_METHOD_CLASS_MAPPING = {
|
60
62
|
to_i: "#{Integer.name}(%<number_object>s, 10)",
|
61
63
|
to_f: "#{Float.name}(%<number_object>s)",
|
62
|
-
to_c: "#{Complex.name}(%<number_object>s)"
|
64
|
+
to_c: "#{Complex.name}(%<number_object>s)",
|
65
|
+
to_r: "#{Rational.name}(%<number_object>s)"
|
63
66
|
}.freeze
|
64
67
|
MSG = 'Replace unsafe number conversion with number '\
|
65
68
|
'class parsing, instead of using '\
|
66
69
|
'`%<current>s`, use stricter '\
|
67
70
|
'`%<corrected_method>s`.'
|
68
|
-
CONVERSION_METHODS = %i[Integer Float Complex to_i to_f to_c].freeze
|
71
|
+
CONVERSION_METHODS = %i[Integer Float Complex Rational to_i to_f to_c to_r].freeze
|
69
72
|
METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
|
70
73
|
|
71
74
|
# @!method to_method(node)
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
include RangeHelp
|
20
20
|
extend AutoCorrector
|
21
21
|
|
22
|
-
MSG = '`
|
22
|
+
MSG = '`%<argument>s` interpreted as grouped expression.'
|
23
23
|
|
24
24
|
def on_send(node)
|
25
25
|
return if valid_context?(node)
|
@@ -28,8 +28,9 @@ module RuboCop
|
|
28
28
|
return unless space_length.positive?
|
29
29
|
|
30
30
|
range = space_range(node.first_argument.source_range, space_length)
|
31
|
+
message = format(MSG, argument: node.first_argument.source)
|
31
32
|
|
32
|
-
add_offense(range) { |corrector| corrector.remove(range) }
|
33
|
+
add_offense(range, message: message) { |corrector| corrector.remove(range) }
|
33
34
|
end
|
34
35
|
alias on_csend on_send
|
35
36
|
|
@@ -41,7 +42,11 @@ module RuboCop
|
|
41
42
|
end
|
42
43
|
|
43
44
|
node.operator_method? || node.setter_method? || chained_calls?(node) ||
|
44
|
-
|
45
|
+
valid_first_argument?(node.first_argument)
|
46
|
+
end
|
47
|
+
|
48
|
+
def valid_first_argument?(first_arg)
|
49
|
+
first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg)
|
45
50
|
end
|
46
51
|
|
47
52
|
def first_argument_starts_with_left_parenthesis?(node)
|
@@ -53,9 +58,8 @@ module RuboCop
|
|
53
58
|
first_argument.send_type? && (node.children.last&.children&.count || 0) > 1
|
54
59
|
end
|
55
60
|
|
56
|
-
def
|
57
|
-
|
58
|
-
first_argument.operator_keyword?
|
61
|
+
def ternary_expression?(node)
|
62
|
+
node.if_type? && node.ternary?
|
59
63
|
end
|
60
64
|
|
61
65
|
def spaces_before_left_parenthesis(node)
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
6
6
|
# Sort globbed results by default in Ruby 3.0.
|
7
7
|
# This cop checks for redundant `sort` method to `Dir.glob` and `Dir[]`.
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe, in case of having a file and a directory with
|
11
|
+
# identical names, since directory will be loaded before the file, which
|
12
|
+
# will break `exe/files.rb` that rely on `exe.rb` file.
|
13
|
+
#
|
9
14
|
# @example
|
10
15
|
#
|
11
16
|
# # bad
|
@@ -147,13 +147,14 @@ module RuboCop
|
|
147
147
|
# will be ignored.
|
148
148
|
return unless node.value.to_s.match?(/\A[a-z0-9_]/i)
|
149
149
|
|
150
|
-
correction = node.value.inspect
|
150
|
+
correction = node.value.inspect
|
151
|
+
correction = correction.delete_prefix(':') if node.parent.colon?
|
151
152
|
return if properly_quoted?(node.source, correction)
|
152
153
|
|
153
154
|
register_offense(
|
154
155
|
node,
|
155
156
|
correction: correction,
|
156
|
-
message: format(MSG, correction: "#{correction}:")
|
157
|
+
message: format(MSG, correction: node.parent.colon? ? "#{correction}:" : correction)
|
157
158
|
)
|
158
159
|
end
|
159
160
|
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop looks for `ruby2_keywords` calls for methods that do not need it.
|
7
|
+
#
|
8
|
+
# `ruby2_keywords` should only be called on methods that accept an argument splat
|
9
|
+
# (`*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
|
10
|
+
# a keyword splat (`**kwargs`).
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # good (splat argument without keyword arguments)
|
14
|
+
# ruby2_keywords def foo(*args); end
|
15
|
+
#
|
16
|
+
# # bad (no arguments)
|
17
|
+
# ruby2_keywords def foo; end
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# def foo; end
|
21
|
+
#
|
22
|
+
# # bad (positional argument)
|
23
|
+
# ruby2_keywords def foo(arg); end
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# def foo(arg); end
|
27
|
+
#
|
28
|
+
# # bad (double splatted argument)
|
29
|
+
# ruby2_keywords def foo(**args); end
|
30
|
+
#
|
31
|
+
# # good
|
32
|
+
# def foo(**args); end
|
33
|
+
#
|
34
|
+
# # bad (keyword arguments)
|
35
|
+
# ruby2_keywords def foo(i:, j:); end
|
36
|
+
#
|
37
|
+
# # good
|
38
|
+
# def foo(i:, j:); end
|
39
|
+
#
|
40
|
+
# # bad (splat argument with keyword arguments)
|
41
|
+
# ruby2_keywords def foo(*args, i:, j:); end
|
42
|
+
#
|
43
|
+
# # good
|
44
|
+
# def foo(*args, i:, j:); end
|
45
|
+
#
|
46
|
+
# # bad (splat argument with double splat)
|
47
|
+
# ruby2_keywords def foo(*args, **kwargs); end
|
48
|
+
#
|
49
|
+
# # good
|
50
|
+
# def foo(*args, **kwargs); end
|
51
|
+
#
|
52
|
+
# # bad (ruby2_keywords given a symbol)
|
53
|
+
# def foo; end
|
54
|
+
# ruby2_keywords :foo
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# def foo; end
|
58
|
+
#
|
59
|
+
# # bad (ruby2_keywords with dynamic method)
|
60
|
+
# define_method(:foo) { |arg| }
|
61
|
+
# ruby2_keywords :foo
|
62
|
+
#
|
63
|
+
# # good
|
64
|
+
# define_method(:foo) { |arg| }
|
65
|
+
#
|
66
|
+
class UselessRuby2Keywords < Base
|
67
|
+
MSG = '`ruby2_keywords` is unnecessary for method `%<method_name>s`.'
|
68
|
+
RESTRICT_ON_SEND = %i[ruby2_keywords].freeze
|
69
|
+
|
70
|
+
# Looks for statically or dynamically defined methods with a given name
|
71
|
+
# @!method method_definition(node, method_name)
|
72
|
+
def_node_matcher :method_definition, <<~PATTERN
|
73
|
+
{
|
74
|
+
(def %1 ...)
|
75
|
+
({block numblock} (send _ :define_method (sym %1)) ...)
|
76
|
+
}
|
77
|
+
PATTERN
|
78
|
+
|
79
|
+
def on_send(node)
|
80
|
+
if node.first_argument.def_type?
|
81
|
+
inspect_def(node, node.first_argument)
|
82
|
+
elsif node.first_argument.sym_type?
|
83
|
+
inspect_sym(node, node.first_argument)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def inspect_def(node, def_node)
|
90
|
+
return if allowed_arguments(def_node.arguments)
|
91
|
+
|
92
|
+
add_offense(node.loc.selector, message: format(MSG, method_name: def_node.method_name))
|
93
|
+
end
|
94
|
+
|
95
|
+
def inspect_sym(node, sym_node)
|
96
|
+
return unless node.parent
|
97
|
+
|
98
|
+
method_name = sym_node.value
|
99
|
+
definition = node.parent.each_child_node.detect { |n| method_definition(n, method_name) }
|
100
|
+
|
101
|
+
return unless definition
|
102
|
+
return if allowed_arguments(definition.arguments)
|
103
|
+
|
104
|
+
add_offense(node, message: format(MSG, method_name: method_name))
|
105
|
+
end
|
106
|
+
|
107
|
+
# `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
|
108
|
+
def allowed_arguments(arguments)
|
109
|
+
return false if arguments.empty?
|
110
|
+
|
111
|
+
arguments.each_child_node(:restarg).any? &&
|
112
|
+
arguments.each_child_node(:kwarg, :kwoptarg, :kwrestarg).none?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -51,20 +51,24 @@ module RuboCop
|
|
51
51
|
node = node.block_node if node.block_literal?
|
52
52
|
|
53
53
|
add_offense(node, message: format(MSG, count: count)) do |corrector|
|
54
|
-
next
|
55
|
-
|
56
|
-
|
57
|
-
remove_node(corrector, node)
|
58
|
-
elsif !proc_name.empty?
|
59
|
-
autocorrect_block_pass(corrector, node, proc_name)
|
60
|
-
else
|
61
|
-
autocorrect_block(corrector, node)
|
62
|
-
end
|
54
|
+
next if !own_line?(node) || node.parent&.send_type?
|
55
|
+
|
56
|
+
autocorrect(corrector, count, node, proc_name)
|
63
57
|
end
|
64
58
|
end
|
65
59
|
|
66
60
|
private
|
67
61
|
|
62
|
+
def autocorrect(corrector, count, node, proc_name)
|
63
|
+
if never_process?(count, node)
|
64
|
+
remove_node(corrector, node)
|
65
|
+
elsif !proc_name.empty?
|
66
|
+
autocorrect_block_pass(corrector, node, proc_name)
|
67
|
+
else
|
68
|
+
autocorrect_block(corrector, node)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
68
72
|
def never_process?(count, node)
|
69
73
|
count < 1 || (node.block_type? && node.body.nil?)
|
70
74
|
end
|
@@ -46,15 +46,6 @@ module RuboCop
|
|
46
46
|
1
|
47
47
|
end
|
48
48
|
|
49
|
-
def block_method(node)
|
50
|
-
case node.type
|
51
|
-
when :block
|
52
|
-
node.method_name
|
53
|
-
when :block_pass
|
54
|
-
node.parent.method_name
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
49
|
def count_block?(block)
|
59
50
|
KNOWN_ITERATING_METHODS.include? block.method_name
|
60
51
|
end
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
|
45
45
|
# @!method module_definition?(node)
|
46
46
|
def_node_matcher :module_definition?, <<~PATTERN
|
47
|
-
(casgn nil? _ (block (send (const {nil? cbase} :Module) :new) ...))
|
47
|
+
(casgn nil? _ ({block numblock} (send (const {nil? cbase} :Module) :new) ...))
|
48
48
|
PATTERN
|
49
49
|
|
50
50
|
def message(length, max_length)
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
# as they add less complexity than positional or optional parameters.
|
11
11
|
#
|
12
12
|
# NOTE: Explicit block argument `&block` is not counted to prevent
|
13
|
-
#
|
13
|
+
# erroneous change that is avoided by making block argument implicit.
|
14
14
|
#
|
15
15
|
# @example Max: 3
|
16
16
|
# # good
|
@@ -13,6 +13,11 @@ module RuboCop
|
|
13
13
|
# @api private
|
14
14
|
module EnforceSuperclass
|
15
15
|
def self.included(base)
|
16
|
+
warn Rainbow(
|
17
|
+
'`RuboCop::Cop::EnforceSuperclass` is deprecated and will be removed in RuboCop 2.0. ' \
|
18
|
+
'Please upgrade to RuboCop Rails 2.9 or newer to continue.'
|
19
|
+
).yellow
|
20
|
+
|
16
21
|
# @!method class_definition(node)
|
17
22
|
base.def_node_matcher :class_definition, <<~PATTERN
|
18
23
|
(class (const _ !:#{base::SUPERCLASS}) #{base::BASE_PATTERN} ...)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for checking gem declarations.
|
6
|
+
module GemspecHelp
|
7
|
+
extend NodePattern::Macros
|
8
|
+
|
9
|
+
# @!method gem_specification?(node)
|
10
|
+
def_node_matcher :gem_specification?, <<~PATTERN
|
11
|
+
(block
|
12
|
+
(send
|
13
|
+
(const
|
14
|
+
(const {cbase nil?} :Gem) :Specification) :new)
|
15
|
+
(args
|
16
|
+
(arg $_)) ...)
|
17
|
+
PATTERN
|
18
|
+
|
19
|
+
# @!method gem_specification(node)
|
20
|
+
def_node_search :gem_specification, <<~PATTERN
|
21
|
+
(block
|
22
|
+
(send
|
23
|
+
(const
|
24
|
+
(const {cbase nil?} :Gem) :Specification) :new)
|
25
|
+
(args
|
26
|
+
(arg $_)) ...)
|
27
|
+
PATTERN
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|