rubocop 1.36.0 → 1.37.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +21 -1
- data/lib/rubocop/arguments_env.rb +17 -0
- data/lib/rubocop/arguments_file.rb +17 -0
- data/lib/rubocop/cli/command/execute_runner.rb +7 -7
- data/lib/rubocop/cli/command/suggest_extensions.rb +8 -1
- data/lib/rubocop/cop/generator.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/create_empty_file.rb +37 -0
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +111 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +28 -3
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +11 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
- data/lib/rubocop/cop/lint/empty_class.rb +3 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +19 -7
- data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +29 -9
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +0 -10
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +3 -0
- data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
- data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +6 -5
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +24 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/character_literal.rb +1 -1
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- data/lib/rubocop/cop/style/collection_compact.rb +8 -1
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +40 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
- data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +181 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/static_class.rb +32 -1
- data/lib/rubocop/cop/style/symbol_array.rb +2 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +2 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
- data/lib/rubocop/options.rb +13 -13
- data/lib/rubocop/rspec/shared_contexts.rb +13 -1
- data/lib/rubocop/server/cache.rb +5 -1
- data/lib/rubocop/server/cli.rb +9 -2
- data/lib/rubocop/server/client_command/exec.rb +5 -0
- data/lib/rubocop/server/core.rb +2 -1
- data/lib/rubocop/server/socket_reader.rb +5 -1
- data/lib/rubocop/server.rb +1 -1
- data/lib/rubocop/version.rb +8 -3
- data/lib/rubocop.rb +3 -0
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: caf1d6d45b2da199a82152b2c5b20ffa6a5f99df5115dbd8fbf4c4e895fd00c5
|
4
|
+
data.tar.gz: 50520bd1d5496971e8b38347dfea57a3387a372b7a815b3c9ef2eb7c1fdc448a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0fa612429aa29b3ce4480fbbc7d77f1efc6862ac89098bfadf7c8f79a4e255709f6752f1b1075497b9ad17aa261afa006089152d10e0deb4f4361bce95537999
|
7
|
+
data.tar.gz: b55827239ce8508d6f884f03838c7fe8ca89268c93ac7ab88409af176e527c74d0d24a14680fa3c7c84353eb078a97699429015b69e6efdb051582914d37ff30
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
53
53
|
in your `Gemfile`:
|
54
54
|
|
55
55
|
```rb
|
56
|
-
gem 'rubocop', '~> 1.
|
56
|
+
gem 'rubocop', '~> 1.37', require: false
|
57
57
|
```
|
58
58
|
|
59
59
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -1707,6 +1707,11 @@ Lint/DuplicateHashKey:
|
|
1707
1707
|
VersionAdded: '0.34'
|
1708
1708
|
VersionChanged: '0.77'
|
1709
1709
|
|
1710
|
+
Lint/DuplicateMagicComment:
|
1711
|
+
Description: 'Check for duplicated magic comments.'
|
1712
|
+
Enabled: pending
|
1713
|
+
VersionAdded: '1.37'
|
1714
|
+
|
1710
1715
|
Lint/DuplicateMethods:
|
1711
1716
|
Description: 'Check for duplicate method definitions.'
|
1712
1717
|
Enabled: true
|
@@ -1957,6 +1962,8 @@ Lint/NestedMethodDefinition:
|
|
1957
1962
|
Description: 'Do not use nested method definitions.'
|
1958
1963
|
StyleGuide: '#no-nested-methods'
|
1959
1964
|
Enabled: true
|
1965
|
+
AllowedMethods: []
|
1966
|
+
AllowedPatterns: []
|
1960
1967
|
VersionAdded: '0.32'
|
1961
1968
|
|
1962
1969
|
Lint/NestedPercentLiteral:
|
@@ -2021,7 +2028,9 @@ Lint/OrAssignmentToConstant:
|
|
2021
2028
|
Lint/OrderedMagicComments:
|
2022
2029
|
Description: 'Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang.'
|
2023
2030
|
Enabled: true
|
2031
|
+
SafeAutoCorrect: false
|
2024
2032
|
VersionAdded: '0.53'
|
2033
|
+
VersionChanged: '1.37'
|
2025
2034
|
|
2026
2035
|
Lint/OutOfRangeRegexpRef:
|
2027
2036
|
Description: 'Checks for out of range reference for Regexp because it always returns nil.'
|
@@ -3850,7 +3859,7 @@ Style/HashSyntax:
|
|
3850
3859
|
- never
|
3851
3860
|
# accepts both shorthand and explicit use of hash literal value.
|
3852
3861
|
- either
|
3853
|
-
# like "
|
3862
|
+
# like "either", but will avoid mixing styles in a single hash
|
3854
3863
|
- consistent
|
3855
3864
|
# Force hashes that have a symbol value to use hash rockets
|
3856
3865
|
UseHashRocketsWithSymbolValues: false
|
@@ -4498,6 +4507,12 @@ Style/OpenStructUse:
|
|
4498
4507
|
Enabled: pending
|
4499
4508
|
VersionAdded: '1.23'
|
4500
4509
|
|
4510
|
+
Style/OperatorMethodCall:
|
4511
|
+
Description: 'Checks for redundant dot before operator method call.'
|
4512
|
+
StyleGuide: '#operator-method-call'
|
4513
|
+
Enabled: pending
|
4514
|
+
VersionAdded: '1.37'
|
4515
|
+
|
4501
4516
|
Style/OptionHash:
|
4502
4517
|
Description: "Don't use option hashes when you can use keyword arguments."
|
4503
4518
|
Enabled: false
|
@@ -4792,6 +4807,11 @@ Style/RedundantSortBy:
|
|
4792
4807
|
Enabled: true
|
4793
4808
|
VersionAdded: '0.36'
|
4794
4809
|
|
4810
|
+
Style/RedundantStringEscape:
|
4811
|
+
Description: 'Checks for redundant escapes in string literals.'
|
4812
|
+
Enabled: pending
|
4813
|
+
VersionAdded: '1.37'
|
4814
|
+
|
4795
4815
|
Style/RegexpLiteral:
|
4796
4816
|
Description: 'Use / or %r around regular expressions.'
|
4797
4817
|
StyleGuide: '#percent-r'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# This is a class that reads optional command line arguments to rubocop from environment variable.
|
5
|
+
# @api private
|
6
|
+
class ArgumentsEnv
|
7
|
+
def self.read_as_arguments
|
8
|
+
if (arguments = ENV.fetch('RUBOCOP_OPTS', '')).empty?
|
9
|
+
[]
|
10
|
+
else
|
11
|
+
require 'shellwords'
|
12
|
+
|
13
|
+
Shellwords.split(arguments)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# This is a class that reads optional command line arguments to rubocop from .rubocop file.
|
5
|
+
# @api private
|
6
|
+
class ArgumentsFile
|
7
|
+
def self.read_as_arguments
|
8
|
+
if File.exist?('.rubocop') && !File.directory?('.rubocop')
|
9
|
+
require 'shellwords'
|
10
|
+
|
11
|
+
File.read('.rubocop').shellsplit
|
12
|
+
else
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -41,13 +41,13 @@ module RuboCop
|
|
41
41
|
|
42
42
|
def with_redirect
|
43
43
|
if @options[:stderr]
|
44
|
-
orig_stdout = $stdout
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
orig_stdout = $stdout
|
45
|
+
begin
|
46
|
+
$stdout = $stderr
|
47
|
+
yield
|
48
|
+
ensure
|
49
|
+
$stdout = orig_stdout
|
50
|
+
end
|
51
51
|
else
|
52
52
|
yield
|
53
53
|
end
|
@@ -73,7 +73,14 @@ module RuboCop
|
|
73
73
|
def all_extensions
|
74
74
|
return [] unless lockfile.dependencies.any?
|
75
75
|
|
76
|
-
extensions = @config_store.for_pwd.for_all_cops['SuggestExtensions']
|
76
|
+
extensions = @config_store.for_pwd.for_all_cops['SuggestExtensions']
|
77
|
+
case extensions
|
78
|
+
when true
|
79
|
+
extensions = ConfigLoader.default_configuration.for_all_cops['SuggestExtensions']
|
80
|
+
when false, nil
|
81
|
+
extensions = {}
|
82
|
+
end
|
83
|
+
|
77
84
|
extensions.select { |_, v| (Array(v) & dependent_gems).any? }.keys
|
78
85
|
end
|
79
86
|
|
@@ -206,9 +206,8 @@ module RuboCop
|
|
206
206
|
end
|
207
207
|
|
208
208
|
def snake_case(camel_case_string)
|
209
|
-
return 'rspec' if camel_case_string == 'RSpec'
|
210
|
-
|
211
209
|
camel_case_string
|
210
|
+
.gsub('RSpec', 'Rspec')
|
212
211
|
.gsub(%r{([^A-Z/])([A-Z]+)}, '\1_\2')
|
213
212
|
.gsub(%r{([A-Z])([A-Z][^A-Z\d/]+)}, '\1_\2')
|
214
213
|
.downcase
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# Checks for uses of `create_file` with empty string second argument.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# create_file(path, '')
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# create_empty_file(path)
|
15
|
+
#
|
16
|
+
class CreateEmptyFile < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
19
|
+
MSG = 'Use `%<replacement>s`.'
|
20
|
+
RESTRICT_ON_SEND = %i[create_file].freeze
|
21
|
+
|
22
|
+
def on_send(node)
|
23
|
+
return if node.receiver
|
24
|
+
return unless (argument = node.arguments[1])
|
25
|
+
return unless argument.str_type? && argument.value.empty?
|
26
|
+
|
27
|
+
replacement = "create_empty_file(#{node.first_argument.source})"
|
28
|
+
message = format(MSG, replacement: replacement)
|
29
|
+
|
30
|
+
add_offense(node, message: message) do |corrector|
|
31
|
+
corrector.replace(node, replacement)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# Use `RUBY` for heredoc delimiter of example Ruby code.
|
7
|
+
#
|
8
|
+
# Some editors may apply better syntax highlighting by using appropriate language names for
|
9
|
+
# the delimiter.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# expect_offense(<<~CODE)
|
14
|
+
# example_ruby_code
|
15
|
+
# CODE
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# expect_offense(<<~RUBY)
|
19
|
+
# example_ruby_code
|
20
|
+
# RUBY
|
21
|
+
class ExampleHeredocDelimiter < Base
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
EXPECTED_HEREDOC_DELIMITER = 'RUBY'
|
25
|
+
|
26
|
+
MSG = 'Use `RUBY` for heredoc delimiter of example Ruby code.'
|
27
|
+
|
28
|
+
RESTRICT_ON_SEND = %i[
|
29
|
+
expect_correction
|
30
|
+
expect_no_corrections
|
31
|
+
expect_no_offenses
|
32
|
+
expect_offense
|
33
|
+
].freeze
|
34
|
+
|
35
|
+
# @param node [RuboCop::AST::SendNode]
|
36
|
+
# @return [void]
|
37
|
+
def on_send(node)
|
38
|
+
heredoc_node = heredoc_node_from(node)
|
39
|
+
return unless heredoc_node
|
40
|
+
return if expected_heredoc_delimiter?(heredoc_node)
|
41
|
+
return if expected_heredoc_delimiter_in_body?(heredoc_node)
|
42
|
+
|
43
|
+
add_offense(heredoc_node) do |corrector|
|
44
|
+
autocorrect(corrector, heredoc_node)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# @param corrector [RuboCop::Cop::Corrector]
|
51
|
+
# @param node [RuboCop::AST::StrNode]
|
52
|
+
# @return [void]
|
53
|
+
def autocorrect(corrector, node)
|
54
|
+
[
|
55
|
+
heredoc_openning_delimiter_range_from(node),
|
56
|
+
heredoc_closing_delimiter_range_from(node)
|
57
|
+
].each do |range|
|
58
|
+
corrector.replace(range, EXPECTED_HEREDOC_DELIMITER)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param node [RuboCop::AST::StrNode]
|
63
|
+
# @return [Boolean]
|
64
|
+
def expected_heredoc_delimiter_in_body?(node)
|
65
|
+
node.location.heredoc_body.source.lines.any? do |line|
|
66
|
+
line.strip == EXPECTED_HEREDOC_DELIMITER
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param node [RuboCop::AST::StrNode]
|
71
|
+
# @return [Boolean]
|
72
|
+
def expected_heredoc_delimiter?(node)
|
73
|
+
heredoc_delimiter_string_from(node) == EXPECTED_HEREDOC_DELIMITER
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param node [RuboCop::AST::SendNode]
|
77
|
+
# @return [RuboCop::AST::StrNode, nil]
|
78
|
+
def heredoc_node_from(node)
|
79
|
+
return unless node.first_argument.respond_to?(:heredoc?)
|
80
|
+
return unless node.first_argument.heredoc?
|
81
|
+
|
82
|
+
node.first_argument
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param node [RuboCop::AST::StrNode]
|
86
|
+
# @return [String]
|
87
|
+
def heredoc_delimiter_string_from(node)
|
88
|
+
node.source[Heredoc::OPENING_DELIMITER, 2]
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param node [RuboCop::AST::StrNode]
|
92
|
+
# @return [Parser::Source::Range]
|
93
|
+
def heredoc_openning_delimiter_range_from(node)
|
94
|
+
match_data = node.source.match(Heredoc::OPENING_DELIMITER)
|
95
|
+
node.location.expression.begin.adjust(
|
96
|
+
begin_pos: match_data.begin(2),
|
97
|
+
end_pos: match_data.end(2)
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
# @param node [RuboCop::AST::StrNode]
|
102
|
+
# @return [Parser::Source::Range]
|
103
|
+
def heredoc_closing_delimiter_range_from(node)
|
104
|
+
node.location.heredoc_end.end.adjust(
|
105
|
+
begin_pos: -heredoc_delimiter_string_from(node).length
|
106
|
+
)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'internal_affairs/cop_description'
|
4
|
+
require_relative 'internal_affairs/create_empty_file'
|
4
5
|
require_relative 'internal_affairs/empty_line_between_expect_offense_and_correction'
|
5
6
|
require_relative 'internal_affairs/example_description'
|
7
|
+
require_relative 'internal_affairs/example_heredoc_delimiter'
|
6
8
|
require_relative 'internal_affairs/inherit_deprecated_cop_class'
|
7
9
|
require_relative 'internal_affairs/location_line_equality_comparison'
|
8
10
|
require_relative 'internal_affairs/method_name_end_with'
|
@@ -343,7 +343,7 @@ module RuboCop
|
|
343
343
|
end
|
344
344
|
|
345
345
|
def skip_check?(base_loc, body_node)
|
346
|
-
return true if
|
346
|
+
return true if allowed_line?(base_loc)
|
347
347
|
return true unless body_node
|
348
348
|
|
349
349
|
# Don't check if expression is on same line as "then" keyword, etc.
|
@@ -169,19 +169,22 @@ module RuboCop
|
|
169
169
|
|
170
170
|
def qualifies_for_compact?(node, token, side: :right)
|
171
171
|
if side == :right
|
172
|
-
multi_dimensional_array?(node, token) &&
|
172
|
+
multi_dimensional_array?(node, token) && token.space_before?
|
173
173
|
else
|
174
|
-
multi_dimensional_array?(node, token, side: :left) &&
|
175
|
-
!next_to_bracket?(token, side: :left)
|
174
|
+
multi_dimensional_array?(node, token, side: :left) && token.space_after?
|
176
175
|
end
|
177
176
|
end
|
178
177
|
|
179
178
|
def multi_dimensional_array?(node, token, side: :right)
|
180
|
-
|
179
|
+
offset = side == :right ? -1 : +1
|
180
|
+
i = index_for(node, token) + offset
|
181
|
+
# TODO: change this type check once
|
182
|
+
# https://github.com/rubocop/rubocop-ast/pull/240 is merged
|
183
|
+
i += offset while processed_source.tokens_within(node)[i].new_line?
|
181
184
|
if side == :right
|
182
|
-
processed_source.tokens_within(node)[i
|
185
|
+
processed_source.tokens_within(node)[i].right_bracket?
|
183
186
|
else
|
184
|
-
processed_source.tokens_within(node)[i
|
187
|
+
processed_source.tokens_within(node)[i].left_array_bracket?
|
185
188
|
end
|
186
189
|
end
|
187
190
|
|
@@ -200,12 +203,13 @@ module RuboCop
|
|
200
203
|
end
|
201
204
|
|
202
205
|
def compact_corrections(corrector, node, left, right)
|
203
|
-
if
|
206
|
+
if multi_dimensional_array?(node, left, side: :left)
|
204
207
|
compact(corrector, left, :right)
|
205
208
|
elsif !left.space_after?
|
206
209
|
corrector.insert_after(left.pos, ' ')
|
207
210
|
end
|
208
|
-
|
211
|
+
|
212
|
+
if multi_dimensional_array?(node, right)
|
209
213
|
compact(corrector, right, :left)
|
210
214
|
elsif !right.space_before?
|
211
215
|
corrector.insert_before(right.pos, ' ')
|
@@ -213,7 +217,7 @@ module RuboCop
|
|
213
217
|
end
|
214
218
|
|
215
219
|
def compact(corrector, bracket, side)
|
216
|
-
range = side_space_range(range: bracket.pos, side: side)
|
220
|
+
range = side_space_range(range: bracket.pos, side: side, include_newlines: true)
|
217
221
|
corrector.remove(range)
|
218
222
|
end
|
219
223
|
end
|
@@ -46,10 +46,13 @@ module RuboCop
|
|
46
46
|
# # bad
|
47
47
|
# foo = { }
|
48
48
|
# bar = { }
|
49
|
+
# baz = {
|
50
|
+
# }
|
49
51
|
#
|
50
52
|
# # good
|
51
53
|
# foo = {}
|
52
54
|
# bar = {}
|
55
|
+
# baz = {}
|
53
56
|
#
|
54
57
|
# @example EnforcedStyleForEmptyBraces: space
|
55
58
|
# # The `space` EnforcedStyleForEmptyBraces style enforces that
|
@@ -60,8 +63,9 @@ module RuboCop
|
|
60
63
|
#
|
61
64
|
# # good
|
62
65
|
# foo = { }
|
63
|
-
# foo = {
|
64
|
-
# foo = {
|
66
|
+
# foo = { }
|
67
|
+
# foo = {
|
68
|
+
# }
|
65
69
|
#
|
66
70
|
class SpaceInsideHashLiteralBraces < Base
|
67
71
|
include SurroundingSpace
|
@@ -77,6 +81,7 @@ module RuboCop
|
|
77
81
|
|
78
82
|
check(tokens[0], tokens[1])
|
79
83
|
check(tokens[-2], tokens[-1]) if tokens.size > 2
|
84
|
+
check_whitespace_only_hash(node) if enforce_no_space_style_for_empty_braces?
|
80
85
|
end
|
81
86
|
|
82
87
|
private
|
@@ -103,7 +108,7 @@ module RuboCop
|
|
103
108
|
if is_same_braces && style == :compact
|
104
109
|
false
|
105
110
|
elsif is_empty_braces
|
106
|
-
|
111
|
+
!enforce_no_space_style_for_empty_braces?
|
107
112
|
else
|
108
113
|
style != :no_space
|
109
114
|
end
|
@@ -175,6 +180,26 @@ module RuboCop
|
|
175
180
|
|
176
181
|
range_between(begin_pos, range.end_pos - 1)
|
177
182
|
end
|
183
|
+
|
184
|
+
def check_whitespace_only_hash(node)
|
185
|
+
range = range_inside_hash(node)
|
186
|
+
return unless range.source.match?(/\A\s+\z/m)
|
187
|
+
|
188
|
+
add_offense(
|
189
|
+
range,
|
190
|
+
message: format(MSG, problem: 'empty hash literal braces detected')
|
191
|
+
) do |corrector|
|
192
|
+
corrector.remove(range)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def range_inside_hash(node)
|
197
|
+
range_between(node.location.begin.end_pos, node.location.end.begin_pos)
|
198
|
+
end
|
199
|
+
|
200
|
+
def enforce_no_space_style_for_empty_braces?
|
201
|
+
cop_config['EnforcedStyleForEmptyBraces'] == 'no_space'
|
202
|
+
end
|
178
203
|
end
|
179
204
|
end
|
180
205
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for duplicated magic comments.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
#
|
12
|
+
# # encoding: ascii
|
13
|
+
# # encoding: ascii
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
#
|
17
|
+
# # encoding: ascii
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
#
|
21
|
+
# # frozen_string_literal: true
|
22
|
+
# # frozen_string_literal: true
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
#
|
26
|
+
# # frozen_string_literal: true
|
27
|
+
#
|
28
|
+
class DuplicateMagicComment < Base
|
29
|
+
include FrozenStringLiteral
|
30
|
+
include RangeHelp
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
MSG = 'Duplicate magic comment detected.'
|
34
|
+
|
35
|
+
def on_new_investigation
|
36
|
+
return if processed_source.buffer.source.empty?
|
37
|
+
|
38
|
+
magic_comment_lines.each_value do |comment_lines|
|
39
|
+
next if comment_lines.count <= 1
|
40
|
+
|
41
|
+
comment_lines[1..].each do |comment_line|
|
42
|
+
range = processed_source.buffer.line_range(comment_line + 1)
|
43
|
+
|
44
|
+
register_offense(range)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def magic_comment_lines
|
52
|
+
comment_lines = { encoding_magic_comments: [], frozen_string_literal_magic_comments: [] }
|
53
|
+
|
54
|
+
leading_magic_comments.each.with_index do |magic_comment, index|
|
55
|
+
if magic_comment.encoding_specified?
|
56
|
+
comment_lines[:encoding_magic_comments] << index
|
57
|
+
elsif magic_comment.frozen_string_literal_specified?
|
58
|
+
comment_lines[:frozen_string_literal_magic_comments] << index
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
comment_lines
|
63
|
+
end
|
64
|
+
|
65
|
+
def register_offense(range)
|
66
|
+
add_offense(range) do |corrector|
|
67
|
+
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -133,7 +133,7 @@ module RuboCop
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def found_instance_method(node, name)
|
136
|
-
return unless (scope = node.parent_module_name)
|
136
|
+
return found_sclass_method(node, name) unless (scope = node.parent_module_name)
|
137
137
|
|
138
138
|
# Humanize the scope
|
139
139
|
scope = scope.sub(
|
@@ -145,6 +145,16 @@ module RuboCop
|
|
145
145
|
found_method(node, "#{scope}#{name}")
|
146
146
|
end
|
147
147
|
|
148
|
+
def found_sclass_method(node, name)
|
149
|
+
singleton_ancestor = node.each_ancestor.find(&:sclass_type?)
|
150
|
+
return unless singleton_ancestor
|
151
|
+
|
152
|
+
singleton_receiver_node = singleton_ancestor.children[0]
|
153
|
+
return unless singleton_receiver_node.send_type?
|
154
|
+
|
155
|
+
found_method(node, "#{singleton_receiver_node.method_name}.#{name}")
|
156
|
+
end
|
157
|
+
|
148
158
|
def found_method(node, method_name)
|
149
159
|
if @definitions.key?(method_name)
|
150
160
|
loc = case node.type
|
@@ -32,26 +32,40 @@ module RuboCop
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
35
36
|
def each_repeated_character_class_element_loc(node)
|
36
37
|
node.parsed_tree&.each_expression do |expr|
|
37
|
-
next if expr
|
38
|
+
next if skip_expression?(expr)
|
38
39
|
|
39
40
|
seen = Set.new
|
41
|
+
enum = expr.expressions.to_enum
|
42
|
+
expression_count = expr.expressions.count
|
40
43
|
|
41
|
-
|
42
|
-
|
44
|
+
expression_count.times do |current_number|
|
45
|
+
current_child = enum.next
|
46
|
+
next if within_interpolation?(node, current_child)
|
43
47
|
|
44
|
-
|
48
|
+
current_child_source = current_child.to_s
|
49
|
+
next_child = enum.peek if current_number + 1 < expression_count
|
45
50
|
|
46
|
-
|
51
|
+
if seen.include?(current_child_source)
|
52
|
+
next if start_with_escaped_zero_number?(current_child_source, next_child.to_s)
|
47
53
|
|
48
|
-
|
54
|
+
yield current_child.expression
|
55
|
+
end
|
56
|
+
|
57
|
+
seen << current_child_source
|
49
58
|
end
|
50
59
|
end
|
51
60
|
end
|
61
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
52
62
|
|
53
63
|
private
|
54
64
|
|
65
|
+
def skip_expression?(expr)
|
66
|
+
expr.type != :set || expr.token == :intersection
|
67
|
+
end
|
68
|
+
|
55
69
|
# Since we blank interpolations with a space for every char of the interpolation, we would
|
56
70
|
# mark every space (except the first) as duplicate if we do not skip regexp_parser nodes
|
57
71
|
# that are within an interpolation.
|
@@ -61,6 +75,11 @@ module RuboCop
|
|
61
75
|
interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
|
62
76
|
end
|
63
77
|
|
78
|
+
def start_with_escaped_zero_number?(current_child, next_child)
|
79
|
+
# Represents escaped code from `"\00"` (`"\u0000"`) to `"\07"` (`"\a"`).
|
80
|
+
current_child == '\\0' && next_child.match?(/[0-7]/)
|
81
|
+
end
|
82
|
+
|
64
83
|
def interpolation_locs(node)
|
65
84
|
@interpolation_locs ||= {}
|
66
85
|
|
@@ -85,7 +85,9 @@ module RuboCop
|
|
85
85
|
private
|
86
86
|
|
87
87
|
def body_or_allowed_comment_lines?(node)
|
88
|
-
|
88
|
+
return true if node.body
|
89
|
+
|
90
|
+
cop_config['AllowComments'] && processed_source.contains_comment?(node.source_range)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
end
|