rubocop 1.70.0 → 1.71.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 +17 -0
- data/lib/rubocop/cli/command/show_cops.rb +24 -2
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +7 -7
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +12 -2
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +12 -17
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -0
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -3
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_subset.rb +170 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +7 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -2
- data/lib/rubocop/cop/security/compound_hash.rb +1 -0
- data/lib/rubocop/cop/style/array_first_last.rb +18 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +6 -19
- data/lib/rubocop/cop/style/collection_methods.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +1 -1
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
- data/lib/rubocop/cop/style/hash_except.rb +5 -131
- data/lib/rubocop/cop/style/hash_slice.rb +65 -0
- data/lib/rubocop/cop/style/map_to_set.rb +3 -2
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/open_struct_use.rb +4 -4
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -10
- data/lib/rubocop/cop/style/redundant_parentheses.rb +3 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
- data/lib/rubocop/cop/style/string_methods.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
- data/lib/rubocop/cops_documentation_generator.rb +13 -13
- data/lib/rubocop/directive_comment.rb +9 -8
- data/lib/rubocop/options.rb +2 -1
- data/lib/rubocop/result_cache.rb +13 -13
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/target_finder.rb +1 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f4339f6b223b2a7fd5f68764dd3030e5cb83925c0605414459ed0f3d2543510
|
4
|
+
data.tar.gz: 525042279be387c345b3efd57ed7ca976e3eda5b15ba9723485b72f3a083816e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 404c792e4624474f907576ef9c73fc3ee09a5736c63becf75197fe40d5e9fdefb7c2cb6bc22326857d3b5065f50badd1a6a4d8f7cecd219fb6ec7280bb95a97a
|
7
|
+
data.tar.gz: 6e3071938d0f6d7850a732c41ce55890c6a2ba8bcd352df28203c136453cf249fd21a10c9c3d1ea7762376466a669a287efb56c8b7505877d8b17cacdd5dd059
|
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.71', 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
@@ -1616,6 +1616,12 @@ Lint/AmbiguousRegexpLiteral:
|
|
1616
1616
|
VersionAdded: '0.17'
|
1617
1617
|
VersionChanged: '0.83'
|
1618
1618
|
|
1619
|
+
Lint/ArrayLiteralInRegexp:
|
1620
|
+
Description: 'Checks for an array literal interpolated inside a regexp.'
|
1621
|
+
Enabled: pending
|
1622
|
+
VersionAdded: '1.71'
|
1623
|
+
SafeAutoCorrect: false
|
1624
|
+
|
1619
1625
|
Lint/AssignmentInCondition:
|
1620
1626
|
Description: "Don't use assignment in conditions."
|
1621
1627
|
StyleGuide: '#safe-assignment-in-condition'
|
@@ -4063,6 +4069,9 @@ Style/FrozenStringLiteralComment:
|
|
4063
4069
|
# exist in a file.
|
4064
4070
|
- never
|
4065
4071
|
SafeAutoCorrect: false
|
4072
|
+
Exclude:
|
4073
|
+
# Prevent the Ruby warning: `'frozen_string_literal' is ignored after any tokens` when using Active Admin.
|
4074
|
+
- '**/*.arb'
|
4066
4075
|
|
4067
4076
|
Style/GlobalStdStream:
|
4068
4077
|
Description: 'Enforces the use of `$stdout/$stderr/$stdin` instead of `STDOUT/STDERR/STDIN`.'
|
@@ -4141,6 +4150,14 @@ Style/HashLikeCase:
|
|
4141
4150
|
# to trigger this cop
|
4142
4151
|
MinBranchesCount: 3
|
4143
4152
|
|
4153
|
+
Style/HashSlice:
|
4154
|
+
Description: >-
|
4155
|
+
Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
|
4156
|
+
that can be replaced with `Hash#slice` method.
|
4157
|
+
Enabled: pending
|
4158
|
+
Safe: false
|
4159
|
+
VersionAdded: '1.71'
|
4160
|
+
|
4144
4161
|
Style/HashSyntax:
|
4145
4162
|
Description: >-
|
4146
4163
|
Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax
|
@@ -9,11 +9,31 @@ module RuboCop
|
|
9
9
|
class ShowCops < Base
|
10
10
|
self.command_name = :show_cops
|
11
11
|
|
12
|
+
ExactMatcher = Struct.new(:pattern) do
|
13
|
+
def match?(name)
|
14
|
+
name == pattern
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
WildcardMatcher = Struct.new(:pattern) do
|
19
|
+
def match?(name)
|
20
|
+
File.fnmatch(pattern, name, File::FNM_PATHNAME)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
12
24
|
def initialize(env)
|
13
25
|
super
|
14
26
|
|
15
27
|
# Load the configs so the require()s are done for custom cops
|
16
28
|
@config = @config_store.for(Dir.pwd)
|
29
|
+
|
30
|
+
@cop_matchers = @options[:show_cops].map do |pattern|
|
31
|
+
if pattern.include?('*')
|
32
|
+
WildcardMatcher.new(pattern)
|
33
|
+
else
|
34
|
+
ExactMatcher.new(pattern)
|
35
|
+
end
|
36
|
+
end
|
17
37
|
end
|
18
38
|
|
19
39
|
def run
|
@@ -24,7 +44,7 @@ module RuboCop
|
|
24
44
|
|
25
45
|
def print_available_cops
|
26
46
|
registry = Cop::Registry.global
|
27
|
-
show_all = @
|
47
|
+
show_all = @cop_matchers.empty?
|
28
48
|
|
29
49
|
puts "# Available cops (#{registry.length}) + config for #{Dir.pwd}: " if show_all
|
30
50
|
|
@@ -56,7 +76,9 @@ module RuboCop
|
|
56
76
|
|
57
77
|
def selected_cops_of_department(cops, department)
|
58
78
|
cops_of_department(cops, department).select do |cop|
|
59
|
-
@
|
79
|
+
@cop_matchers.any? do |matcher|
|
80
|
+
matcher.match?(cop.cop_name)
|
81
|
+
end
|
60
82
|
end
|
61
83
|
end
|
62
84
|
|
@@ -22,7 +22,7 @@ module RuboCop
|
|
22
22
|
|
23
23
|
def on_send(node)
|
24
24
|
return unless (parent = node.parent)
|
25
|
-
return unless parent.
|
25
|
+
return unless parent.call_type? && parent.method?(:expression)
|
26
26
|
return unless parent.receiver.receiver
|
27
27
|
|
28
28
|
offense = node.loc.selector.join(parent.source_range.end)
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
31
31
|
corrector.replace(offense, 'source_range')
|
32
32
|
end
|
33
33
|
end
|
34
|
+
alias on_csend on_send
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
@@ -27,8 +27,8 @@ module RuboCop
|
|
27
27
|
# @!method arguments_first_or_last?(node)
|
28
28
|
def_node_matcher :arguments_first_or_last?, <<~PATTERN
|
29
29
|
{
|
30
|
-
(
|
31
|
-
(
|
30
|
+
(call (call !nil? :arguments) ${:first :last})
|
31
|
+
(call (call !nil? :arguments) :[] (int ${0 -1}))
|
32
32
|
}
|
33
33
|
PATTERN
|
34
34
|
|
@@ -47,6 +47,7 @@ module RuboCop
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
|
+
alias on_csend on_send
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# Checks for cops that define `on_send` without define `on_csend`.
|
7
|
+
#
|
8
|
+
# Although in some cases it can be predetermined that safe navigation
|
9
|
+
# will never be used with the code checked by a specific cop, in general
|
10
|
+
# it is good practice to handle safe navigation methods if handling any
|
11
|
+
# `send` node.
|
12
|
+
#
|
13
|
+
# NOTE: It is expected to disable this cop for cops that check for method calls
|
14
|
+
# on receivers that cannot be nil (`self`, a literal, a constant), and
|
15
|
+
# method calls that will never have a receiver (ruby keywords like `raise`,
|
16
|
+
# macros like `attr_reader`, DSL methods, etc.), and other checks that wouldn't
|
17
|
+
# make sense to support safe navigation.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# # bad
|
21
|
+
# class MyCop < RuboCop::Cop:Base
|
22
|
+
# def on_send(node)
|
23
|
+
# # ...
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # good - explicit method definition
|
28
|
+
# class MyCop < RuboCop::Cop:Base
|
29
|
+
# def on_send(node)
|
30
|
+
# # ...
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# def on_csend(node)
|
34
|
+
# # ...
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # good - alias
|
39
|
+
# class MyCop < RuboCop::Cop:Base
|
40
|
+
# def on_send(node)
|
41
|
+
# # ...
|
42
|
+
# end
|
43
|
+
# alias on_csend on_send
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# # good - alias_method
|
47
|
+
# class MyCop < RuboCop::Cop:Base
|
48
|
+
# def on_send(node)
|
49
|
+
# # ...
|
50
|
+
# end
|
51
|
+
# alias_method :on_csend, :on_send
|
52
|
+
# end
|
53
|
+
class OnSendWithoutOnCSend < Base
|
54
|
+
RESTRICT_ON_SEND = %i[alias_method].freeze
|
55
|
+
MSG = 'Cop defines `on_send` but not `on_csend`.'
|
56
|
+
|
57
|
+
def on_new_investigation
|
58
|
+
@on_send_definition = nil
|
59
|
+
@on_csend_definition = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_investigation_end
|
63
|
+
return unless @on_send_definition && !@on_csend_definition
|
64
|
+
|
65
|
+
add_offense(@on_send_definition)
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_def(node)
|
69
|
+
@on_send_definition = node if node.method?(:on_send)
|
70
|
+
@on_csend_definition = node if node.method?(:on_csend)
|
71
|
+
end
|
72
|
+
|
73
|
+
def on_alias(node)
|
74
|
+
@on_send_definition = node if node.new_identifier.value == :on_send
|
75
|
+
@on_csend_definition = node if node.new_identifier.value == :on_csend
|
76
|
+
end
|
77
|
+
|
78
|
+
def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
|
79
|
+
new_identifier = node.first_argument
|
80
|
+
return unless new_identifier.basic_literal?
|
81
|
+
|
82
|
+
new_identifier = new_identifier.value
|
83
|
+
|
84
|
+
@on_send_definition = node if new_identifier == :on_send
|
85
|
+
@on_csend_definition = node if new_identifier == :on_csend
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -47,7 +47,7 @@ module RuboCop
|
|
47
47
|
# @!method redundant_source_range(node)
|
48
48
|
def_node_matcher :redundant_source_range, <<~PATTERN
|
49
49
|
{
|
50
|
-
(
|
50
|
+
(call $(call _ :source_range) :source)
|
51
51
|
(send nil? :add_offense $(send _ :source_range) ...)
|
52
52
|
(send _ {
|
53
53
|
:replace :insert_before :insert_before_multi :insert_after :insert_after_multi
|
@@ -67,6 +67,7 @@ module RuboCop
|
|
67
67
|
corrector.remove(source_range.loc.dot.join(selector))
|
68
68
|
end
|
69
69
|
end
|
70
|
+
alias on_csend on_send
|
70
71
|
end
|
71
72
|
end
|
72
73
|
end
|
@@ -34,8 +34,8 @@ module RuboCop
|
|
34
34
|
# @!method single_line_comparison(node)
|
35
35
|
def_node_matcher :single_line_comparison, <<~PATTERN
|
36
36
|
{
|
37
|
-
(send (
|
38
|
-
(send (
|
37
|
+
(send (call $_receiver {:line :first_line}) {:== :!=} (call _receiver :last_line))
|
38
|
+
(send (call $_receiver :last_line) {:== :!=} (call _receiver {:line :first_line}))
|
39
39
|
}
|
40
40
|
PATTERN
|
41
41
|
|
@@ -43,7 +43,8 @@ module RuboCop
|
|
43
43
|
return unless (receiver = single_line_comparison(node))
|
44
44
|
|
45
45
|
bang = node.method?(:!=) ? '!' : ''
|
46
|
-
|
46
|
+
dot = receiver.parent.loc.dot.source
|
47
|
+
preferred = "#{bang}#{extract_receiver(receiver)}#{dot}single_line?"
|
47
48
|
|
48
49
|
add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
|
49
50
|
corrector.replace(node, preferred)
|
@@ -53,7 +54,7 @@ module RuboCop
|
|
53
54
|
private
|
54
55
|
|
55
56
|
def extract_receiver(node)
|
56
|
-
node = node.receiver if node.
|
57
|
+
node = node.receiver if node.call_type? && %i[loc source_range].include?(node.method_name)
|
57
58
|
node.source
|
58
59
|
end
|
59
60
|
end
|
@@ -18,6 +18,7 @@ require_relative 'internal_affairs/node_matcher_directive'
|
|
18
18
|
require_relative 'internal_affairs/node_type_predicate'
|
19
19
|
require_relative 'internal_affairs/numblock_handler'
|
20
20
|
require_relative 'internal_affairs/offense_location_keyword'
|
21
|
+
require_relative 'internal_affairs/on_send_without_on_csend'
|
21
22
|
require_relative 'internal_affairs/operator_keyword'
|
22
23
|
require_relative 'internal_affairs/processed_source_buffer_name'
|
23
24
|
require_relative 'internal_affairs/redundant_context_config_parameter'
|
@@ -3,23 +3,23 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Layout
|
6
|
-
# Checks if the code style follows the ExpectedOrder configuration:
|
6
|
+
# Checks if the code style follows the `ExpectedOrder` configuration:
|
7
7
|
#
|
8
8
|
# `Categories` allows us to map macro names into a category.
|
9
9
|
#
|
10
10
|
# Consider an example of code style that covers the following order:
|
11
11
|
#
|
12
|
-
# * Module inclusion (include
|
12
|
+
# * Module inclusion (`include`, `prepend`, `extend`)
|
13
13
|
# * Constants
|
14
|
-
# * Associations (has_one
|
15
|
-
# * Public attribute macros (attr_accessor
|
16
|
-
# * Other macros (validates
|
14
|
+
# * Associations (`has_one`, `has_many`)
|
15
|
+
# * Public attribute macros (`attr_accessor`, `attr_writer`, `attr_reader`)
|
16
|
+
# * Other macros (`validates`, `validate`)
|
17
17
|
# * Public class methods
|
18
18
|
# * Initializer
|
19
19
|
# * Public instance methods
|
20
|
-
# * Protected attribute macros (attr_accessor
|
20
|
+
# * Protected attribute macros (`attr_accessor`, `attr_writer`, `attr_reader`)
|
21
21
|
# * Protected instance methods
|
22
|
-
# * Private attribute macros (attr_accessor
|
22
|
+
# * Private attribute macros (`attr_accessor`, `attr_writer`, `attr_reader`)
|
23
23
|
# * Private instance methods
|
24
24
|
#
|
25
25
|
# You can configure the following order:
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks if empty lines exist around the bodies of `begin`
|
7
7
|
# sections. This cop doesn't check empty lines at `begin` body
|
8
8
|
# beginning/end and around method definition body.
|
9
|
-
# `
|
9
|
+
# `Layout/EmptyLinesAroundBeginBody` or `Layout/EmptyLinesAroundMethodBody`
|
10
10
|
# can be used for this purpose.
|
11
11
|
#
|
12
12
|
# @example
|
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
# where the opening brace and the first key are on separate lines. The
|
8
8
|
# other keys' indentations are handled by the HashAlignment cop.
|
9
9
|
#
|
10
|
-
# By default, Hash literals that are arguments in a method call with
|
10
|
+
# By default, `Hash` literals that are arguments in a method call with
|
11
11
|
# parentheses, and where the opening curly brace of the hash is on the
|
12
12
|
# same line as the opening parenthesis of the method call, shall have
|
13
13
|
# their first key indented one step (two spaces) more than the position
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
|
52
52
|
def on_hash(node)
|
53
53
|
# node.loc.begin tells us whether the hash opens with a {
|
54
|
-
# If it doesn't,
|
54
|
+
# If it doesn't, Layout/FirstMethodArgumentLineBreak will handle it
|
55
55
|
return unless node.loc.begin
|
56
56
|
|
57
57
|
check_children_line_break(node, node.children, ignore_last: ignore_last_element?)
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
52
52
|
def on_hash(node)
|
53
53
|
# This cop only deals with hashes wrapped by a set of curly
|
54
54
|
# braces like {foo: 1}. That is, not a kwargs hashes.
|
55
|
-
#
|
55
|
+
# Layout/MultilineMethodArgumentLineBreaks handles those.
|
56
56
|
return unless starts_with_curly_brace?(node)
|
57
57
|
return unless node.loc.begin
|
58
58
|
|
@@ -36,6 +36,7 @@ module RuboCop
|
|
36
36
|
ACCEPT_LEFT_PAREN = %w[break defined? next not rescue return super yield].freeze
|
37
37
|
ACCEPT_LEFT_SQUARE_BRACKET = %w[super yield].freeze
|
38
38
|
ACCEPT_NAMESPACE_OPERATOR = 'super'
|
39
|
+
RESTRICT_ON_SEND = %i[!].freeze
|
39
40
|
|
40
41
|
def on_and(node)
|
41
42
|
check(node, [:operator].freeze) if node.keyword?
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for an array literal interpolated inside a regexp.
|
7
|
+
#
|
8
|
+
# When interpolating an array literal, it is converted to a string. This means
|
9
|
+
# that when inside a regexp, it acts as a character class but with additional
|
10
|
+
# quotes, spaces and commas that are likely not intended. For example,
|
11
|
+
# `/#{%w[a b c]}/` parses as `/["a", "b", "c"]/` (or `/["a, bc]/` without
|
12
|
+
# repeated characters).
|
13
|
+
#
|
14
|
+
# The cop can autocorrect to a character class (if all items in the array are a
|
15
|
+
# single character) or alternation (if the array contains longer items).
|
16
|
+
#
|
17
|
+
# NOTE: This only considers interpolated arrays that contain only strings, symbols,
|
18
|
+
# integers, and floats. Any other type is not easily convertible to a character class
|
19
|
+
# or regexp alternation.
|
20
|
+
#
|
21
|
+
# @safety
|
22
|
+
# Autocorrection is unsafe because it will change the regexp pattern, by
|
23
|
+
# removing the additional quotes, spaces and commas from the character class.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# # bad
|
27
|
+
# /#{%w[a b c]}/
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
# /[abc]/
|
31
|
+
#
|
32
|
+
# # bad
|
33
|
+
# /#{%w[foo bar baz]}/
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# /(?:foo|bar|baz)/
|
37
|
+
#
|
38
|
+
# # bad - construct a regexp rather than interpolate an array of identifiers
|
39
|
+
# /#{[foo, bar]}/
|
40
|
+
#
|
41
|
+
class ArrayLiteralInRegexp < Base
|
42
|
+
include Interpolation
|
43
|
+
extend AutoCorrector
|
44
|
+
|
45
|
+
LITERAL_TYPES = %i[str sym int float true false nil].freeze
|
46
|
+
private_constant :LITERAL_TYPES
|
47
|
+
|
48
|
+
MSG_CHARACTER_CLASS = 'Use a character class instead of interpolating an array in a regexp.'
|
49
|
+
MSG_ALTERNATION = 'Use alternation instead of interpolating an array in a regexp.'
|
50
|
+
MSG_UNKNOWN = 'Use alternation or a character class instead of interpolating an array ' \
|
51
|
+
'in a regexp.'
|
52
|
+
|
53
|
+
def on_interpolation(begin_node)
|
54
|
+
final_node = begin_node.children.last
|
55
|
+
|
56
|
+
return unless begin_node.parent.regexp_type?
|
57
|
+
return unless final_node.array_type?
|
58
|
+
|
59
|
+
if array_of_literal_values?(final_node)
|
60
|
+
register_array_of_literal_values(begin_node, final_node)
|
61
|
+
else
|
62
|
+
register_array_of_nonliteral_values(begin_node)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def array_of_literal_values?(node)
|
69
|
+
node.each_value.all? { |value| value.type?(*LITERAL_TYPES) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def register_array_of_literal_values(begin_node, node)
|
73
|
+
array_values = array_values(node)
|
74
|
+
|
75
|
+
if character_class?(array_values)
|
76
|
+
message = MSG_CHARACTER_CLASS
|
77
|
+
replacement = character_class_for(array_values)
|
78
|
+
else
|
79
|
+
message = MSG_ALTERNATION
|
80
|
+
replacement = alternation_for(array_values)
|
81
|
+
end
|
82
|
+
|
83
|
+
add_offense(begin_node, message: message) do |corrector|
|
84
|
+
corrector.replace(begin_node, replacement)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def register_array_of_nonliteral_values(node)
|
89
|
+
# Add offense but do not correct if the array contains any nonliteral values.
|
90
|
+
add_offense(node, message: MSG_UNKNOWN)
|
91
|
+
end
|
92
|
+
|
93
|
+
def array_values(node)
|
94
|
+
node.each_value.map do |value|
|
95
|
+
value.respond_to?(:value) ? value.value : value.source
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def character_class?(values)
|
100
|
+
values.all? { |v| v.to_s.length == 1 }
|
101
|
+
end
|
102
|
+
|
103
|
+
def character_class_for(values)
|
104
|
+
"[#{escape_values(values).join}]"
|
105
|
+
end
|
106
|
+
|
107
|
+
def alternation_for(values)
|
108
|
+
"(?:#{escape_values(values).join('|')})"
|
109
|
+
end
|
110
|
+
|
111
|
+
def escape_values(values)
|
112
|
+
# This may add extraneous escape characters, but they can be cleaned up
|
113
|
+
# by `Style/RedundantRegexpEscape`.
|
114
|
+
values.map { |value| Regexp.escape(value.to_s) }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -36,7 +36,8 @@ module RuboCop
|
|
36
36
|
# # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
|
37
37
|
#
|
38
38
|
class FloatComparison < Base
|
39
|
-
|
39
|
+
MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
|
40
|
+
MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
|
40
41
|
|
41
42
|
EQUALITY_METHODS = %i[== != eql? equal?].freeze
|
42
43
|
FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
|
@@ -52,8 +53,10 @@ module RuboCop
|
|
52
53
|
|
53
54
|
return if literal_safe?(lhs) || literal_safe?(rhs)
|
54
55
|
|
55
|
-
|
56
|
+
message = node.method?(:!=) ? MSG_INEQUALITY : MSG_EQUALITY
|
57
|
+
add_offense(node, message: message) if float?(lhs) || float?(rhs)
|
56
58
|
end
|
59
|
+
alias on_csend on_send
|
57
60
|
|
58
61
|
private
|
59
62
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Identifies Float literals which are, like, really really really
|
6
|
+
# Identifies `Float` literals which are, like, really really really
|
7
7
|
# really really really really really big. Too big. No-one needs Floats
|
8
8
|
# that big. If you need a float that big, something is wrong with you.
|
9
9
|
#
|
@@ -5,6 +5,9 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# Checks for interpolated literals.
|
7
7
|
#
|
8
|
+
# NOTE: Array literals interpolated in regexps are not handled by this cop, but
|
9
|
+
# by `Lint/ArrayLiteralInRegexp` instead.
|
10
|
+
#
|
8
11
|
# @example
|
9
12
|
#
|
10
13
|
# # bad
|
@@ -55,8 +58,10 @@ module RuboCop
|
|
55
58
|
node &&
|
56
59
|
!special_keyword?(node) &&
|
57
60
|
prints_as_self?(node) &&
|
58
|
-
# Special case for Layout/TrailingWhitespace
|
59
|
-
!(space_literal?(node) && ends_heredoc_line?(node))
|
61
|
+
# Special case for `Layout/TrailingWhitespace`
|
62
|
+
!(space_literal?(node) && ends_heredoc_line?(node)) &&
|
63
|
+
# Handled by `Lint/ArrayLiteralInRegexp`
|
64
|
+
!array_in_regexp?(node)
|
60
65
|
end
|
61
66
|
|
62
67
|
def special_keyword?(node)
|
@@ -64,6 +69,11 @@ module RuboCop
|
|
64
69
|
(node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
|
65
70
|
end
|
66
71
|
|
72
|
+
def array_in_regexp?(node)
|
73
|
+
grandparent = node.parent.parent
|
74
|
+
node.array_type? && grandparent.regexp_type?
|
75
|
+
end
|
76
|
+
|
67
77
|
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
68
78
|
def autocorrected_value(node)
|
69
79
|
case node.type
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
# Offenses are registered for regexp character classes like `/[A-z]/`
|
9
9
|
# as well as range objects like `('A'..'z')`.
|
10
10
|
#
|
11
|
-
# NOTE: Range objects cannot be autocorrected.
|
11
|
+
# NOTE: `Range` objects cannot be autocorrected.
|
12
12
|
#
|
13
13
|
# @safety
|
14
14
|
# The cop autocorrects regexp character classes
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Do not mix named captures and numbered captures in a Regexp literal
|
6
|
+
# Do not mix named captures and numbered captures in a `Regexp` literal
|
7
7
|
# because numbered capture is ignored if they're mixed.
|
8
8
|
# Replace numbered captures with non-capturing groupings or
|
9
9
|
# named captures.
|