rubocop 1.73.2 → 1.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +31 -2
- data/lib/rubocop/config_loader_resolver.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +9 -3
- data/lib/rubocop/cop/lint/return_in_void_context.rb +4 -11
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +2 -11
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +29 -7
- data/lib/rubocop/cop/style/commented_keyword.rb +9 -2
- data/lib/rubocop/cop/style/comparable_between.rb +75 -0
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
- data/lib/rubocop/cop/style/format_string_token.rb +38 -11
- data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 440bee0e28f294bab2eba4c11e9c681342917c69ad4c00e36eceb88743767c29
|
4
|
+
data.tar.gz: 68e9e209a22e891a38b677f97344d2d10e9a8913dd999751472f301deed43b31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70db27a5b7a0e00696672a5b4fcd4e3bf35aa40c85ef65ccb630914ab110a5e5b657927aa1b1c8637be76b7041a90e2ad3c4ed188110266c048d0c4d6a4be0b4
|
7
|
+
data.tar.gz: e5599d30a4f776d85d202acad2ac03c7e4568e64a1c4038cb87b8ee3372b2428882924a91ea49853c98cf0614280d002918363eef41fe0990dc8b1895d8e9776
|
data/README.md
CHANGED
@@ -52,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
52
52
|
in your `Gemfile`:
|
53
53
|
|
54
54
|
```rb
|
55
|
-
gem 'rubocop', '~> 1.
|
55
|
+
gem 'rubocop', '~> 1.74', require: false
|
56
56
|
```
|
57
57
|
|
58
58
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -3104,6 +3104,8 @@ Naming/VariableNumber:
|
|
3104
3104
|
CheckMethodNames: true
|
3105
3105
|
CheckSymbols: true
|
3106
3106
|
AllowedIdentifiers:
|
3107
|
+
- TLS1_1 # OpenSSL::SSL::TLS1_1_VERSION
|
3108
|
+
- TLS1_2 # OpenSSL::SSL::TLS1_2_VERSION
|
3107
3109
|
- capture3 # Open3.capture3
|
3108
3110
|
- iso8601 # Time#iso8601
|
3109
3111
|
- rfc1123_date # CGI.rfc1123_date
|
@@ -3499,6 +3501,7 @@ Style/ClassAndModuleChildren:
|
|
3499
3501
|
SafeAutoCorrect: false
|
3500
3502
|
Enabled: true
|
3501
3503
|
VersionAdded: '0.19'
|
3504
|
+
VersionChanged: '1.74'
|
3502
3505
|
#
|
3503
3506
|
# Basically there are two different styles:
|
3504
3507
|
#
|
@@ -3514,7 +3517,21 @@ Style/ClassAndModuleChildren:
|
|
3514
3517
|
#
|
3515
3518
|
# The compact style is only forced, for classes or modules with one child.
|
3516
3519
|
EnforcedStyle: nested
|
3517
|
-
SupportedStyles:
|
3520
|
+
SupportedStyles: &supported_styles
|
3521
|
+
- nested
|
3522
|
+
- compact
|
3523
|
+
# Configure classes separately, if desired. If not set, or set to `nil`,
|
3524
|
+
# the `EnforcedStyle` value will be used.
|
3525
|
+
EnforcedStyleForClasses: ~
|
3526
|
+
SupportedStylesForClasses:
|
3527
|
+
- ~
|
3528
|
+
- nested
|
3529
|
+
- compact
|
3530
|
+
# Configure modules separately, if desired. If not set, or set to `nil`,
|
3531
|
+
# the `EnforcedStyle` value will be used.
|
3532
|
+
EnforcedStyleForModules: ~
|
3533
|
+
SupportedStylesForModules:
|
3534
|
+
- ~
|
3518
3535
|
- nested
|
3519
3536
|
- compact
|
3520
3537
|
|
@@ -3667,6 +3684,12 @@ Style/CommentedKeyword:
|
|
3667
3684
|
VersionAdded: '0.51'
|
3668
3685
|
VersionChanged: '1.19'
|
3669
3686
|
|
3687
|
+
Style/ComparableBetween:
|
3688
|
+
Description: 'Enforces the use of `Comparable#between?` instead of logical comparison.'
|
3689
|
+
Enabled: pending
|
3690
|
+
VersionAdded: '1.74'
|
3691
|
+
StyleGuide: '#ranges-or-between'
|
3692
|
+
|
3670
3693
|
Style/ComparableClamp:
|
3671
3694
|
Description: 'Enforces the use of `Comparable#clamp` instead of comparison by minimum and maximum.'
|
3672
3695
|
Enabled: pending
|
@@ -4069,8 +4092,14 @@ Style/FormatStringToken:
|
|
4069
4092
|
# style token in a format string to be allowed when enforced style is not
|
4070
4093
|
# `unannotated`.
|
4071
4094
|
MaxUnannotatedPlaceholdersAllowed: 1
|
4095
|
+
# The mode the cop operates in. Two values are allowed:
|
4096
|
+
# * aggressive (default): all strings are considered
|
4097
|
+
# * conservative:
|
4098
|
+
# only register offenses for strings given to `printf`, `sprintf`,
|
4099
|
+
# format` and `%` methods. Other strings are not considered.
|
4100
|
+
Mode: aggressive
|
4072
4101
|
VersionAdded: '0.49'
|
4073
|
-
VersionChanged: '1.
|
4102
|
+
VersionChanged: '1.74'
|
4074
4103
|
AllowedMethods: []
|
4075
4104
|
AllowedPatterns: []
|
4076
4105
|
|
@@ -9,7 +9,8 @@ module RuboCop
|
|
9
9
|
# @api private
|
10
10
|
class ConfigLoaderResolver # rubocop:disable Metrics/ClassLength
|
11
11
|
def resolve_plugins(rubocop_config, plugins)
|
12
|
-
|
12
|
+
plugins = Array(plugins) - ConfigLoader.loaded_plugins.map { |plugin| plugin.about.name }
|
13
|
+
return if plugins.empty?
|
13
14
|
|
14
15
|
Plugin.integrate_plugins(rubocop_config, plugins)
|
15
16
|
end
|
@@ -15,7 +15,7 @@ module RuboCop
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def violated?
|
18
|
-
return false if
|
18
|
+
return false if plugin_loaded?
|
19
19
|
|
20
20
|
affected_cops.any?
|
21
21
|
end
|
@@ -38,8 +38,9 @@ module RuboCop
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
def
|
42
|
-
|
41
|
+
def plugin_loaded?
|
42
|
+
# Plugins loaded via `require` are included in `loaded_features`.
|
43
|
+
config.loaded_plugins.include?(gem) || config.loaded_features.include?(gem)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
# Default rules for obsoletions are in config/obsoletion.yml
|
51
51
|
# Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
|
52
52
|
def load_rules # rubocop:disable Metrics/AbcSize
|
53
|
-
rules = LOAD_RULES_CACHE[self.class.files] ||=
|
53
|
+
rules = LOAD_RULES_CACHE[self.class.files.hash] ||=
|
54
54
|
self.class.files.each_with_object({}) do |filename, hash|
|
55
55
|
hash.merge!(YAML.safe_load(File.read(filename)) || {}) do |_key, first, second|
|
56
56
|
case first
|
@@ -46,6 +46,10 @@ module RuboCop
|
|
46
46
|
return unless node.lhs.truthy_literal?
|
47
47
|
|
48
48
|
add_offense(node.lhs) do |corrector|
|
49
|
+
# Don't autocorrect `'foo' && return` because having `return` as
|
50
|
+
# the leftmost node can lead to a void value expression syntax error.
|
51
|
+
next if node.rhs.type?(:return, :break, :next)
|
52
|
+
|
49
53
|
corrector.replace(node, node.rhs.source)
|
50
54
|
end
|
51
55
|
end
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
def on_return(return_node)
|
47
47
|
return if return_value?(return_node)
|
48
48
|
|
49
|
-
return_node.each_ancestor(:
|
49
|
+
return_node.each_ancestor(:any_block, :def, :defs) do |node|
|
50
50
|
break if scoped_node?(node)
|
51
51
|
|
52
52
|
# if a proc is passed to `Module#define_method` or
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
# non-local exit error
|
55
55
|
break if define_method?(node.send_node)
|
56
56
|
|
57
|
-
next
|
57
|
+
next if node.argument_list.empty?
|
58
58
|
|
59
59
|
if chained_send?(node.send_node)
|
60
60
|
add_offense(return_node.loc.keyword)
|
@@ -3,13 +3,13 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Checks for redundant uses of `to_s`, `to_sym`, `to_i`, `to_f`, `to_r`, `to_c`,
|
6
|
+
# Checks for redundant uses of `to_s`, `to_sym`, `to_i`, `to_f`, `to_d`, `to_r`, `to_c`,
|
7
7
|
# `to_a`, `to_h`, and `to_set`.
|
8
8
|
#
|
9
9
|
# When one of these methods is called on an object of the same type, that object
|
10
10
|
# is returned, making the call unnecessary. The cop detects conversion methods called
|
11
11
|
# on object literals, class constructors, class `[]` methods, and the `Kernel` methods
|
12
|
-
# `String()`, `Integer()`, `Float()`, `Rational()`, `Complex()
|
12
|
+
# `String()`, `Integer()`, `Float()`, BigDecimal(), `Rational()`, `Complex()`, and `Array()`.
|
13
13
|
#
|
14
14
|
# Specifically, these cases are detected for each conversion method:
|
15
15
|
#
|
@@ -98,6 +98,7 @@ module RuboCop
|
|
98
98
|
to_s: 'string_constructor?',
|
99
99
|
to_i: 'integer_constructor?',
|
100
100
|
to_f: 'float_constructor?',
|
101
|
+
to_d: 'bigdecimal_constructor?',
|
101
102
|
to_r: 'rational_constructor?',
|
102
103
|
to_c: 'complex_constructor?',
|
103
104
|
to_a: 'array_constructor?',
|
@@ -110,7 +111,7 @@ module RuboCop
|
|
110
111
|
TYPED_METHODS = { to_s: %i[inspect] }.freeze
|
111
112
|
|
112
113
|
CONVERSION_METHODS = Set[*LITERAL_NODE_TYPES.keys].freeze
|
113
|
-
RESTRICT_ON_SEND = CONVERSION_METHODS
|
114
|
+
RESTRICT_ON_SEND = CONVERSION_METHODS + [:to_d]
|
114
115
|
|
115
116
|
private_constant :LITERAL_NODE_TYPES, :CONSTRUCTOR_MAPPING
|
116
117
|
|
@@ -137,6 +138,11 @@ module RuboCop
|
|
137
138
|
#type_constructor?(:Float)
|
138
139
|
PATTERN
|
139
140
|
|
141
|
+
# @!method bigdecimal_constructor?(node)
|
142
|
+
def_node_matcher :bigdecimal_constructor?, <<~PATTERN
|
143
|
+
#type_constructor?(:BigDecimal)
|
144
|
+
PATTERN
|
145
|
+
|
140
146
|
# @!method rational_constructor?(node)
|
141
147
|
def_node_matcher :rational_constructor?, <<~PATTERN
|
142
148
|
#type_constructor?(:Rational)
|
@@ -35,22 +35,15 @@ module RuboCop
|
|
35
35
|
def on_return(return_node)
|
36
36
|
return unless return_node.descendants.any?
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
return
|
41
|
-
return unless context_node&.void_context?
|
38
|
+
def_node = return_node.each_ancestor(:def).first
|
39
|
+
return unless def_node&.void_context?
|
40
|
+
return if return_node.each_ancestor(:any_block).any?(&:lambda?)
|
42
41
|
|
43
42
|
add_offense(
|
44
43
|
return_node.loc.keyword,
|
45
|
-
message: format(message, method:
|
44
|
+
message: format(message, method: def_node.method_name)
|
46
45
|
)
|
47
46
|
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def non_void_context(return_node)
|
52
|
-
return_node.each_ancestor(:block, :def, :defs).first
|
53
|
-
end
|
54
47
|
end
|
55
48
|
end
|
56
49
|
end
|
@@ -51,7 +51,18 @@ module RuboCop
|
|
51
51
|
|
52
52
|
# @!method hash_initialized_with_mutable_shared_object?(node)
|
53
53
|
def_node_matcher :hash_initialized_with_mutable_shared_object?, <<~PATTERN
|
54
|
-
|
54
|
+
{
|
55
|
+
(send (const {nil? cbase} :Hash) :new [
|
56
|
+
{array hash (send (const {nil? cbase} {:Array :Hash}) :new)}
|
57
|
+
!#capacity_keyword_argument?
|
58
|
+
])
|
59
|
+
(send (const {nil? cbase} :Hash) :new hash #capacity_keyword_argument?)
|
60
|
+
}
|
61
|
+
PATTERN
|
62
|
+
|
63
|
+
# @!method capacity_keyword_argument?(node)
|
64
|
+
def_node_matcher :capacity_keyword_argument?, <<~PATTERN
|
65
|
+
(hash (pair (sym :capacity) _))
|
55
66
|
PATTERN
|
56
67
|
|
57
68
|
def on_send(node)
|
@@ -4,8 +4,8 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for useless constant scoping. Private constants must be defined using
|
7
|
-
# `private_constant
|
8
|
-
#
|
7
|
+
# `private_constant`. Even if `private` access modifier is used, it is public scope despite
|
8
|
+
# its appearance.
|
9
9
|
#
|
10
10
|
# It does not support autocorrection due to behavior change and multiple ways to fix it.
|
11
11
|
# Or a public constant may be intended.
|
@@ -26,14 +26,6 @@ module RuboCop
|
|
26
26
|
#
|
27
27
|
# # good
|
28
28
|
# class Foo
|
29
|
-
# class << self
|
30
|
-
# private
|
31
|
-
# PRIVATE_CONST = 42
|
32
|
-
# end
|
33
|
-
# end
|
34
|
-
#
|
35
|
-
# # good
|
36
|
-
# class Foo
|
37
29
|
# PUBLIC_CONST = 42 # If private scope is not intended.
|
38
30
|
# end
|
39
31
|
#
|
@@ -46,7 +38,6 @@ module RuboCop
|
|
46
38
|
PATTERN
|
47
39
|
|
48
40
|
def on_casgn(node)
|
49
|
-
return if node.each_ancestor(:sclass).any?
|
50
41
|
return unless after_private_modifier?(node.left_siblings)
|
51
42
|
return if private_constantize?(node.right_siblings, node.name)
|
52
43
|
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
|
36
36
|
|
37
37
|
comment_line_numbers.any? do |comment_line_number|
|
38
|
-
comment_line_number
|
38
|
+
comment_line_number.between?(node.first_line, node.last_line)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -3,14 +3,26 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks
|
7
|
-
#
|
6
|
+
# Checks that namespaced classes and modules are defined with a consistent style.
|
7
|
+
#
|
8
|
+
# With `nested` style, classes and modules should be defined separately (one constant
|
9
|
+
# on each line, without `::`). With `compact` style, classes and modules should be
|
10
|
+
# defined with fully qualified names (using `::` for namespaces).
|
11
|
+
#
|
12
|
+
# NOTE: The style chosen will affect `Module.nesting` for the class or module. Using
|
13
|
+
# `nested` style will result in each level being added, whereas `compact` style will
|
14
|
+
# only include the fully qualified class or module name.
|
15
|
+
#
|
16
|
+
# By default, `EnforcedStyle` applies to both classes and modules. If desired, separate
|
17
|
+
# styles can be defined for classes and modules by using `EnforcedStyleForClasses` and
|
18
|
+
# `EnforcedStyleForModules` respectively. If not set, or set to nil, the `EnforcedStyle`
|
19
|
+
# value will be used.
|
8
20
|
#
|
9
21
|
# @safety
|
10
22
|
# Autocorrection is unsafe.
|
11
23
|
#
|
12
|
-
# Moving from compact to nested children requires knowledge of whether the
|
13
|
-
# outer parent is a module or a class. Moving from nested to compact requires
|
24
|
+
# Moving from `compact` to `nested` children requires knowledge of whether the
|
25
|
+
# outer parent is a module or a class. Moving from `nested` to `compact` requires
|
14
26
|
# verification that the outer parent is defined elsewhere. RuboCop does not
|
15
27
|
# have the knowledge to perform either operation safely and thus requires
|
16
28
|
# manual oversight.
|
@@ -42,16 +54,18 @@ module RuboCop
|
|
42
54
|
def on_class(node)
|
43
55
|
return if node.parent_class && style != :nested
|
44
56
|
|
45
|
-
check_style(node, node.body)
|
57
|
+
check_style(node, node.body, style_for_classes)
|
46
58
|
end
|
47
59
|
|
48
60
|
def on_module(node)
|
49
|
-
check_style(node, node.body)
|
61
|
+
check_style(node, node.body, style_for_modules)
|
50
62
|
end
|
51
63
|
|
52
64
|
private
|
53
65
|
|
54
66
|
def nest_or_compact(corrector, node)
|
67
|
+
style = node.class_type? ? style_for_classes : style_for_modules
|
68
|
+
|
55
69
|
if style == :nested
|
56
70
|
nest_definition(corrector, node)
|
57
71
|
else
|
@@ -141,7 +155,7 @@ module RuboCop
|
|
141
155
|
node.source_range.source_line[/\A\s*/]
|
142
156
|
end
|
143
157
|
|
144
|
-
def check_style(node, body)
|
158
|
+
def check_style(node, body, style)
|
145
159
|
return if node.identifier.namespace&.cbase_type?
|
146
160
|
|
147
161
|
if style == :nested
|
@@ -183,6 +197,14 @@ module RuboCop
|
|
183
197
|
def compact_node_name?(node)
|
184
198
|
node.identifier.source.include?('::')
|
185
199
|
end
|
200
|
+
|
201
|
+
def style_for_classes
|
202
|
+
cop_config['EnforcedStyleForClasses'] || style
|
203
|
+
end
|
204
|
+
|
205
|
+
def style_for_modules
|
206
|
+
cop_config['EnforcedStyleForModules'] || style
|
207
|
+
end
|
186
208
|
end
|
187
209
|
end
|
188
210
|
end
|
@@ -9,8 +9,8 @@ module RuboCop
|
|
9
9
|
# These keywords are: `class`, `module`, `def`, `begin`, `end`.
|
10
10
|
#
|
11
11
|
# Note that some comments
|
12
|
-
# (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`)
|
13
|
-
#
|
12
|
+
# (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`),
|
13
|
+
# RBS::Inline annotation, and Steep annotation (`steep:ignore`) are allowed.
|
14
14
|
#
|
15
15
|
# Autocorrection removes comments from `end` keyword and keeps comments
|
16
16
|
# for `class`, `module`, `def` and `begin` above the keyword.
|
@@ -60,6 +60,8 @@ module RuboCop
|
|
60
60
|
SUBCLASS_DEFINITION = /\A\s*class\s+(\w|::)+\s*<\s*(\w|::)+/.freeze
|
61
61
|
METHOD_DEFINITION = /\A\s*def\s/.freeze
|
62
62
|
|
63
|
+
STEEP_REGEXP = /#\ssteep:ignore(\s|\z)/.freeze
|
64
|
+
|
63
65
|
def on_new_investigation
|
64
66
|
processed_source.comments.each do |comment|
|
65
67
|
next unless offensive?(comment) && (match = source_line(comment).match(REGEXP))
|
@@ -86,6 +88,7 @@ module RuboCop
|
|
86
88
|
def offensive?(comment)
|
87
89
|
line = source_line(comment)
|
88
90
|
return false if rbs_inline_annotation?(line, comment)
|
91
|
+
return false if steep_annotation?(comment)
|
89
92
|
|
90
93
|
KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
|
91
94
|
ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
|
@@ -105,6 +108,10 @@ module RuboCop
|
|
105
108
|
false
|
106
109
|
end
|
107
110
|
end
|
111
|
+
|
112
|
+
def steep_annotation?(comment)
|
113
|
+
comment.text.match?(STEEP_REGEXP)
|
114
|
+
end
|
108
115
|
end
|
109
116
|
end
|
110
117
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for logical comparison which can be replaced with `Comparable#between?`.
|
7
|
+
#
|
8
|
+
# NOTE: `Comparable#between?` is on average slightly slower than logical comparison,
|
9
|
+
# although the difference generally isn't observable. If you require maximum
|
10
|
+
# performance, consider using logical comparison.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# x >= min && x <= max
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# x <= max && x >= min
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# x.between?(min, max)
|
22
|
+
#
|
23
|
+
class ComparableBetween < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
|
26
|
+
MSG = 'Prefer `%<prefer>s` over logical comparison.'
|
27
|
+
|
28
|
+
# @!method logical_comparison_between_by_min_first?(node)
|
29
|
+
def_node_matcher :logical_comparison_between_by_min_first?, <<~PATTERN
|
30
|
+
(and
|
31
|
+
(send
|
32
|
+
{$_value :>= $_min | $_min :<= $_value})
|
33
|
+
(send
|
34
|
+
{$_value :<= $_max | $_max :>= $_value}))
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
# @!method logical_comparison_between_by_max_first?(node)
|
38
|
+
def_node_matcher :logical_comparison_between_by_max_first?, <<~PATTERN
|
39
|
+
(and
|
40
|
+
(send
|
41
|
+
{$_value :<= $_max | $_max :>= $_value})
|
42
|
+
(send
|
43
|
+
{$_value :>= $_min | $_min :<= $_value}))
|
44
|
+
PATTERN
|
45
|
+
|
46
|
+
def on_and(node)
|
47
|
+
logical_comparison_between_by_min_first?(node) do |*args|
|
48
|
+
min_and_value, max_and_value = args.each_slice(2).to_a
|
49
|
+
|
50
|
+
register_offense(node, min_and_value, max_and_value)
|
51
|
+
end
|
52
|
+
|
53
|
+
logical_comparison_between_by_max_first?(node) do |*args|
|
54
|
+
max_and_value, min_and_value = args.each_slice(2).to_a
|
55
|
+
|
56
|
+
register_offense(node, min_and_value, max_and_value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def register_offense(node, min_and_value, max_and_value)
|
63
|
+
value = (min_and_value & max_and_value).first
|
64
|
+
min = min_and_value.find { _1 != value }
|
65
|
+
max = max_and_value.find { _1 != value }
|
66
|
+
|
67
|
+
prefer = "#{value.source}.between?(#{min.source}, #{max.source})"
|
68
|
+
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
69
|
+
corrector.replace(node, prefer)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -60,8 +60,8 @@ module RuboCop
|
|
60
60
|
class ExponentialNotation < Base
|
61
61
|
include ConfigurableEnforcedStyle
|
62
62
|
MESSAGES = {
|
63
|
-
scientific: 'Use a mantissa
|
64
|
-
engineering: 'Use an exponent divisible by 3 and a mantissa
|
63
|
+
scientific: 'Use a mantissa >= 1 and < 10.',
|
64
|
+
engineering: 'Use an exponent divisible by 3 and a mantissa >= 0.1 and < 1000.',
|
65
65
|
integral: 'Use an integer as mantissa, without trailing zero.'
|
66
66
|
}.freeze
|
67
67
|
|
@@ -3,16 +3,24 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Use a consistent style for
|
6
|
+
# Use a consistent style for tokens within a format string.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# The reason is that _unannotated_ format is very similar
|
12
|
-
# to encoded URLs or Date/Time formatting strings.
|
8
|
+
# By default, all strings are evaluated. In some cases, this may be undesirable,
|
9
|
+
# as they could be used as arguments to a method that does not consider
|
10
|
+
# them to be tokens, but rather other identifiers or just part of the string.
|
13
11
|
#
|
14
|
-
#
|
15
|
-
#
|
12
|
+
# `AllowedMethods` or `AllowedPatterns` can be configured with in order to mark specific
|
13
|
+
# methods as always allowed, thereby avoiding an offense from the cop. By default, there
|
14
|
+
# are no allowed methods.
|
15
|
+
#
|
16
|
+
# Additionally, the cop can be made conservative by configuring it with
|
17
|
+
# `Mode: conservative` (default `aggressive`). In this mode, tokens (regardless
|
18
|
+
# of `EnforcedStyle`) are only considered if used in the format string argument to the
|
19
|
+
# methods `printf`, `sprintf`, `format` and `%`.
|
20
|
+
#
|
21
|
+
# NOTE: Tokens in the `unannotated` style (eg. `%s`) are always treated as if
|
22
|
+
# configured with `Conservative: true`. This is done in order to prevent false positives,
|
23
|
+
# because this format is very similar to encoded URLs or Date/Time formatting strings.
|
16
24
|
#
|
17
25
|
# @example EnforcedStyle: annotated (default)
|
18
26
|
#
|
@@ -82,6 +90,20 @@ module RuboCop
|
|
82
90
|
# # good
|
83
91
|
# redirect('foo/%{bar_id}')
|
84
92
|
#
|
93
|
+
# @example Mode: conservative, EnforcedStyle: annotated
|
94
|
+
# # In `conservative` mode, offenses are only registered for strings
|
95
|
+
# # given to a known formatting method.
|
96
|
+
#
|
97
|
+
# # good
|
98
|
+
# "%{greeting}"
|
99
|
+
# foo("%{greeting}")
|
100
|
+
#
|
101
|
+
# # bad
|
102
|
+
# format("%{greeting}", greeting: 'Hello')
|
103
|
+
# printf("%{greeting}", greeting: 'Hello')
|
104
|
+
# sprintf("%{greeting}", greeting: 'Hello')
|
105
|
+
# "%{greeting}" % { greeting: 'Hello' }
|
106
|
+
#
|
85
107
|
class FormatStringToken < Base
|
86
108
|
include ConfigurableEnforcedStyle
|
87
109
|
include AllowedMethods
|
@@ -153,8 +175,9 @@ module RuboCop
|
|
153
175
|
corrector.replace(token_range, correction)
|
154
176
|
end
|
155
177
|
|
156
|
-
def
|
157
|
-
detected_style == :unannotated
|
178
|
+
def allowed_string?(node, detected_style)
|
179
|
+
(detected_style == :unannotated || conservative?) &&
|
180
|
+
!format_string_in_typical_context?(node)
|
158
181
|
end
|
159
182
|
|
160
183
|
def message(detected_style)
|
@@ -203,7 +226,7 @@ module RuboCop
|
|
203
226
|
def collect_detections(node)
|
204
227
|
detections = []
|
205
228
|
tokens(node) do |detected_sequence, token_range|
|
206
|
-
unless
|
229
|
+
unless allowed_string?(node, detected_sequence.style)
|
207
230
|
detections << [detected_sequence, token_range]
|
208
231
|
end
|
209
232
|
end
|
@@ -222,6 +245,10 @@ module RuboCop
|
|
222
245
|
def max_unannotated_placeholders_allowed
|
223
246
|
cop_config['MaxUnannotatedPlaceholdersAllowed']
|
224
247
|
end
|
248
|
+
|
249
|
+
def conservative?
|
250
|
+
cop_config.fetch('Mode', :aggressive).to_sym == :conservative
|
251
|
+
end
|
225
252
|
end
|
226
253
|
end
|
227
254
|
end
|
@@ -164,8 +164,8 @@ module RuboCop
|
|
164
164
|
|
165
165
|
def too_long_due_to_comment_after_modifier?(node, comment)
|
166
166
|
source_length = processed_source.lines[node.first_line - 1].length
|
167
|
-
|
168
|
-
|
167
|
+
|
168
|
+
max_line_length.between?(source_length - comment.source_range.length, source_length)
|
169
169
|
end
|
170
170
|
|
171
171
|
def allowed_patterns
|
@@ -108,7 +108,7 @@ module RuboCop
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def call_in_literals?(node)
|
111
|
-
parent = node.parent&.
|
111
|
+
parent = node.parent&.any_block_type? ? node.parent.parent : node.parent
|
112
112
|
return false unless parent
|
113
113
|
|
114
114
|
parent.type?(:pair, :array, :range) ||
|
@@ -117,7 +117,7 @@ module RuboCop
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def call_in_logical_operators?(node)
|
120
|
-
parent = node.parent&.
|
120
|
+
parent = node.parent&.any_block_type? ? node.parent.parent : node.parent
|
121
121
|
return false unless parent
|
122
122
|
|
123
123
|
logical_operator?(parent) ||
|
@@ -153,7 +153,7 @@ module RuboCop
|
|
153
153
|
end
|
154
154
|
|
155
155
|
def call_in_argument_with_block?(node)
|
156
|
-
parent = node.parent&.
|
156
|
+
parent = node.parent&.any_block_type? && node.parent.parent
|
157
157
|
return false unless parent
|
158
158
|
|
159
159
|
parent.type?(:call, :super, :yield)
|
@@ -20,20 +20,30 @@ module RuboCop
|
|
20
20
|
|
21
21
|
MSG = 'Remove the redundant current directory path.'
|
22
22
|
RESTRICT_ON_SEND = %i[require_relative].freeze
|
23
|
-
|
23
|
+
CURRENT_DIRECTORY_PREFIX = %r{./+}.freeze
|
24
|
+
REDUNDANT_CURRENT_DIRECTORY_PREFIX = /\A#{CURRENT_DIRECTORY_PREFIX}/.freeze
|
24
25
|
|
25
26
|
def on_send(node)
|
26
27
|
return unless (first_argument = node.first_argument)
|
27
|
-
return unless first_argument.
|
28
|
-
return unless (
|
28
|
+
return unless (index = first_argument.source.index(CURRENT_DIRECTORY_PREFIX))
|
29
|
+
return unless (redundant_length = redundant_path_length(first_argument.str_content))
|
29
30
|
|
30
31
|
begin_pos = first_argument.source_range.begin.begin_pos + index
|
31
|
-
|
32
|
+
end_pos = begin_pos + redundant_length
|
33
|
+
range = range_between(begin_pos, end_pos)
|
32
34
|
|
33
35
|
add_offense(range) do |corrector|
|
34
36
|
corrector.remove(range)
|
35
37
|
end
|
36
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def redundant_path_length(path)
|
43
|
+
return unless (match = path&.match(REDUNDANT_CURRENT_DIRECTORY_PREFIX))
|
44
|
+
|
45
|
+
match[0].length
|
46
|
+
end
|
37
47
|
end
|
38
48
|
end
|
39
49
|
end
|
@@ -67,11 +67,13 @@ module RuboCop
|
|
67
67
|
node.parent && parentheses?(node.parent)
|
68
68
|
end
|
69
69
|
|
70
|
+
# rubocop:disable Metrics/AbcSize
|
70
71
|
def correct_rescue_block(corrector, node, parenthesized)
|
71
72
|
operation = node.body
|
72
73
|
|
73
74
|
node_indentation, node_offset = indentation_and_offset(node, parenthesized)
|
74
75
|
|
76
|
+
corrector.wrap(operation, '[', ']') if operation.array_type? && !operation.bracketed?
|
75
77
|
corrector.remove(range_between(operation.source_range.end_pos, node.source_range.end_pos))
|
76
78
|
corrector.insert_before(operation, "begin\n#{node_indentation}")
|
77
79
|
corrector.insert_after(heredoc_end(operation) || operation, <<~RESCUE_CLAUSE.chop)
|
@@ -81,6 +83,7 @@ module RuboCop
|
|
81
83
|
#{node_offset}end
|
82
84
|
RESCUE_CLAUSE
|
83
85
|
end
|
86
|
+
# rubocop:enable Metrics/AbcSize
|
84
87
|
|
85
88
|
def indentation_and_offset(node, parenthesized)
|
86
89
|
node_indentation = indentation(node)
|
@@ -12,7 +12,7 @@ module RuboCop
|
|
12
12
|
# @api private
|
13
13
|
LINT_SYNTAX_COP = "#{LINT_DEPARTMENT}/Syntax"
|
14
14
|
# @api private
|
15
|
-
COP_NAME_PATTERN = '([A-
|
15
|
+
COP_NAME_PATTERN = '([A-Za-z]\w+/)*(?:[A-Za-z]\w+)'
|
16
16
|
# @api private
|
17
17
|
COP_NAMES_PATTERN = "(?:#{COP_NAME_PATTERN} , )*#{COP_NAME_PATTERN}"
|
18
18
|
# @api private
|
data/lib/rubocop/version.rb
CHANGED
data/lib/rubocop.rb
CHANGED
@@ -509,6 +509,7 @@ require_relative 'rubocop/cop/style/combinable_loops'
|
|
509
509
|
require_relative 'rubocop/cop/style/command_literal'
|
510
510
|
require_relative 'rubocop/cop/style/comment_annotation'
|
511
511
|
require_relative 'rubocop/cop/style/commented_keyword'
|
512
|
+
require_relative 'rubocop/cop/style/comparable_between'
|
512
513
|
require_relative 'rubocop/cop/style/comparable_clamp'
|
513
514
|
require_relative 'rubocop/cop/style/concat_array_literals'
|
514
515
|
require_relative 'rubocop/cop/style/conditional_assignment'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.74.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
- Yuji Nakayama
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2025-03-
|
12
|
+
date: 2025-03-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -729,6 +729,7 @@ files:
|
|
729
729
|
- lib/rubocop/cop/style/command_literal.rb
|
730
730
|
- lib/rubocop/cop/style/comment_annotation.rb
|
731
731
|
- lib/rubocop/cop/style/commented_keyword.rb
|
732
|
+
- lib/rubocop/cop/style/comparable_between.rb
|
732
733
|
- lib/rubocop/cop/style/comparable_clamp.rb
|
733
734
|
- lib/rubocop/cop/style/concat_array_literals.rb
|
734
735
|
- lib/rubocop/cop/style/conditional_assignment.rb
|
@@ -1075,9 +1076,9 @@ licenses:
|
|
1075
1076
|
- MIT
|
1076
1077
|
metadata:
|
1077
1078
|
homepage_uri: https://rubocop.org/
|
1078
|
-
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.
|
1079
|
+
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.74.0
|
1079
1080
|
source_code_uri: https://github.com/rubocop/rubocop/
|
1080
|
-
documentation_uri: https://docs.rubocop.org/rubocop/1.
|
1081
|
+
documentation_uri: https://docs.rubocop.org/rubocop/1.74/
|
1081
1082
|
bug_tracker_uri: https://github.com/rubocop/rubocop/issues
|
1082
1083
|
rubygems_mfa_required: 'true'
|
1083
1084
|
rdoc_options: []
|