rubocop 1.36.0 → 1.39.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 -3
- 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/comment_config.rb +36 -1
- data/lib/rubocop/cop/commissioner.rb +3 -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_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
- data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +30 -3
- data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +6 -2
- 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 +28 -9
- 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 +20 -8
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
- 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 +23 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +38 -10
- 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/suppressed_exception.rb +1 -1
- 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/metrics/abc_size.rb +1 -1
- 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/range_help.rb +23 -0
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +10 -8
- data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
- data/lib/rubocop/cop/registry.rb +10 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +5 -7
- data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +2 -2
- data/lib/rubocop/cop/style/character_literal.rb +1 -1
- data/lib/rubocop/cop/style/class_equality_comparison.rb +8 -6
- data/lib/rubocop/cop/style/collection_compact.rb +12 -3
- 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/guard_clause.rb +62 -21
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
- data/lib/rubocop/cop/style/hash_except.rb +4 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +25 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
- data/lib/rubocop/cop/style/module_function.rb +28 -6
- 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/object_then.rb +3 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +53 -0
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- 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_each.rb +116 -0
- 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_regexp_escape.rb +12 -3
- 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/cop/team.rb +3 -4
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +2 -1
- data/lib/rubocop/ext/processed_source.rb +2 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
- data/lib/rubocop/formatter/offense_count_formatter.rb +8 -5
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +6 -3
- data/lib/rubocop/options.rb +19 -15
- data/lib/rubocop/rspec/cop_helper.rb +21 -1
- data/lib/rubocop/rspec/shared_contexts.rb +14 -1
- data/lib/rubocop/runner.rb +15 -11
- 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 +18 -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 +4 -0
- metadata +13 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 881807be0f0f6eea20bd13bd8f08fdb158a5b155c8d3a22fd748683a68c1fef1
|
4
|
+
data.tar.gz: 2a8e7d4b02f1ba468e02a4c20f8e3b830ce2a1d8ff0210f86aaeafab597c8c88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11ea36bec754b07912e06b5481f964d10a6dbf5bfd56f99d8a8842ca46d56ae03a342a283d843336f977760c28a697ee995aa98268254a55b1218fa57a9fb5c7
|
7
|
+
data.tar.gz: b5096cb4589d9bafdab0b6ab409ea9e7841dc06b274aeb7f7d5a26e703cb216c2a428d695fb2a087637467f1cdd5ac005398c66ee3e7d28d49cb4b203a87667d
|
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.39', 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.'
|
@@ -2799,6 +2808,7 @@ Naming/MethodParameterName:
|
|
2799
2808
|
- by
|
2800
2809
|
- db
|
2801
2810
|
- id
|
2811
|
+
- if
|
2802
2812
|
- in
|
2803
2813
|
- io
|
2804
2814
|
- ip
|
@@ -3439,7 +3449,7 @@ Style/Copyright:
|
|
3439
3449
|
|
3440
3450
|
Style/DateTime:
|
3441
3451
|
Description: 'Use Time over DateTime.'
|
3442
|
-
StyleGuide: '#date
|
3452
|
+
StyleGuide: '#date-time'
|
3443
3453
|
Enabled: false
|
3444
3454
|
VersionAdded: '0.51'
|
3445
3455
|
VersionChanged: '0.92'
|
@@ -3810,8 +3820,9 @@ Style/HashExcept:
|
|
3810
3820
|
Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
|
3811
3821
|
that can be replaced with `Hash#except` method.
|
3812
3822
|
Enabled: pending
|
3823
|
+
Safe: false
|
3813
3824
|
VersionAdded: '1.7'
|
3814
|
-
VersionChanged: '1.
|
3825
|
+
VersionChanged: '1.39'
|
3815
3826
|
|
3816
3827
|
Style/HashLikeCase:
|
3817
3828
|
Description: >-
|
@@ -3850,7 +3861,7 @@ Style/HashSyntax:
|
|
3850
3861
|
- never
|
3851
3862
|
# accepts both shorthand and explicit use of hash literal value.
|
3852
3863
|
- either
|
3853
|
-
# like "
|
3864
|
+
# like "either", but will avoid mixing styles in a single hash
|
3854
3865
|
- consistent
|
3855
3866
|
# Force hashes that have a symbol value to use hash rockets
|
3856
3867
|
UseHashRocketsWithSymbolValues: false
|
@@ -4498,6 +4509,12 @@ Style/OpenStructUse:
|
|
4498
4509
|
Enabled: pending
|
4499
4510
|
VersionAdded: '1.23'
|
4500
4511
|
|
4512
|
+
Style/OperatorMethodCall:
|
4513
|
+
Description: 'Checks for redundant dot before operator method call.'
|
4514
|
+
StyleGuide: '#operator-method-call'
|
4515
|
+
Enabled: pending
|
4516
|
+
VersionAdded: '1.37'
|
4517
|
+
|
4501
4518
|
Style/OptionHash:
|
4502
4519
|
Description: "Don't use option hashes when you can use keyword arguments."
|
4503
4520
|
Enabled: false
|
@@ -4681,6 +4698,12 @@ Style/RedundantConditional:
|
|
4681
4698
|
Enabled: true
|
4682
4699
|
VersionAdded: '0.50'
|
4683
4700
|
|
4701
|
+
Style/RedundantEach:
|
4702
|
+
Description: 'Checks for redundant `each`.'
|
4703
|
+
Enabled: pending
|
4704
|
+
Safe: false
|
4705
|
+
VersionAdded: '1.38'
|
4706
|
+
|
4684
4707
|
Style/RedundantException:
|
4685
4708
|
Description: "Checks for an obsolete RuntimeException argument in raise/fail."
|
4686
4709
|
StyleGuide: '#no-explicit-runtimeerror'
|
@@ -4792,6 +4815,11 @@ Style/RedundantSortBy:
|
|
4792
4815
|
Enabled: true
|
4793
4816
|
VersionAdded: '0.36'
|
4794
4817
|
|
4818
|
+
Style/RedundantStringEscape:
|
4819
|
+
Description: 'Checks for redundant escapes in string literals.'
|
4820
|
+
Enabled: pending
|
4821
|
+
VersionAdded: '1.37'
|
4822
|
+
|
4795
4823
|
Style/RegexpLiteral:
|
4796
4824
|
Description: 'Use / or %r around regular expressions.'
|
4797
4825
|
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
|
|
@@ -4,10 +4,31 @@ module RuboCop
|
|
4
4
|
# This class parses the special `rubocop:disable` comments in a source
|
5
5
|
# and provides a way to check if each cop is enabled at arbitrary line.
|
6
6
|
class CommentConfig
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
CONFIG_DISABLED_LINE_RANGE_MIN = -Float::INFINITY
|
10
|
+
|
11
|
+
# This class provides an API compatible with RuboCop::DirectiveComment
|
12
|
+
# to be used for cops that are disabled in the config file
|
13
|
+
class ConfigDisabledCopDirectiveComment
|
14
|
+
attr_reader :text, :loc, :line_number
|
15
|
+
|
16
|
+
Loc = Struct.new(:expression)
|
17
|
+
Expression = Struct.new(:line)
|
18
|
+
|
19
|
+
def initialize(cop_name)
|
20
|
+
@text = "# rubocop:disable #{cop_name}"
|
21
|
+
@line_number = CONFIG_DISABLED_LINE_RANGE_MIN
|
22
|
+
@loc = Loc.new(Expression.new(CONFIG_DISABLED_LINE_RANGE_MIN))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
7
26
|
CopAnalysis = Struct.new(:line_ranges, :start_line_number)
|
8
27
|
|
9
28
|
attr_reader :processed_source
|
10
29
|
|
30
|
+
def_delegators :@processed_source, :config, :registry
|
31
|
+
|
11
32
|
def initialize(processed_source)
|
12
33
|
@processed_source = processed_source
|
13
34
|
end
|
@@ -25,7 +46,11 @@ module RuboCop
|
|
25
46
|
end
|
26
47
|
|
27
48
|
def extra_enabled_comments
|
28
|
-
|
49
|
+
disable_count = Hash.new(0)
|
50
|
+
registry.disabled(config).each do |cop|
|
51
|
+
disable_count[cop.cop_name] += 1
|
52
|
+
end
|
53
|
+
extra_enabled_comments_with_names(extras: Hash.new { |h, k| h[k] = [] }, names: disable_count)
|
29
54
|
end
|
30
55
|
|
31
56
|
def comment_only_line?(line_number)
|
@@ -50,6 +75,7 @@ module RuboCop
|
|
50
75
|
|
51
76
|
def analyze # rubocop:todo Metrics/AbcSize
|
52
77
|
analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
|
78
|
+
inject_disabled_cops_directives(analyses)
|
53
79
|
|
54
80
|
each_directive do |directive|
|
55
81
|
directive.cop_names.each do |cop_name|
|
@@ -64,6 +90,15 @@ module RuboCop
|
|
64
90
|
end
|
65
91
|
end
|
66
92
|
|
93
|
+
def inject_disabled_cops_directives(analyses)
|
94
|
+
registry.disabled(config).each do |cop|
|
95
|
+
analyses[cop.cop_name] = analyze_cop(
|
96
|
+
analyses[cop.cop_name],
|
97
|
+
DirectiveComment.new(ConfigDisabledCopDirectiveComment.new(cop.cop_name))
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
67
102
|
def analyze_cop(analysis, directive)
|
68
103
|
# Disabling cops after comments like `#=SomeDslDirective` does not related to single line
|
69
104
|
if !comment_only_line?(directive.line_number) || directive.single_line?
|
@@ -159,9 +159,11 @@ module RuboCop
|
|
159
159
|
def with_cop_error_handling(cop, node = nil)
|
160
160
|
yield
|
161
161
|
rescue StandardError => e
|
162
|
-
raise e if @options[:raise_error]
|
162
|
+
raise e if @options[:raise_error] # For internal testing
|
163
163
|
|
164
164
|
err = ErrorWithAnalyzedFileLocation.new(cause: e, node: node, cop: cop)
|
165
|
+
raise err if @options[:raise_cop_error] # From user-input option
|
166
|
+
|
165
167
|
@errors << err
|
166
168
|
end
|
167
169
|
end
|
@@ -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'
|
@@ -90,7 +90,7 @@ module RuboCop
|
|
90
90
|
# which lines start inside a string literal?
|
91
91
|
return [] if ast.nil?
|
92
92
|
|
93
|
-
ast.each_node(:str, :dstr).
|
93
|
+
ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
|
94
94
|
loc = str.location
|
95
95
|
|
96
96
|
if str.heredoc?
|
@@ -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.
|
@@ -42,6 +42,14 @@ module RuboCop
|
|
42
42
|
# ' long'
|
43
43
|
class LineContinuationLeadingSpace < Base
|
44
44
|
include RangeHelp
|
45
|
+
extend AutoCorrector
|
46
|
+
|
47
|
+
LINE_1_ENDING = /['"]\s*\\\n/.freeze
|
48
|
+
LINE_2_BEGINNING = /\A\s*['"]/.freeze
|
49
|
+
LEADING_STYLE_OFFENSE = /(?<trailing_spaces>\s+)(?<ending>#{LINE_1_ENDING})/.freeze
|
50
|
+
TRAILING_STYLE_OFFENSE = /(?<beginning>#{LINE_2_BEGINNING})(?<leading_spaces>\s+)/.freeze
|
51
|
+
private_constant :LINE_1_ENDING, :LINE_2_BEGINNING,
|
52
|
+
:LEADING_STYLE_OFFENSE, :TRAILING_STYLE_OFFENSE
|
45
53
|
|
46
54
|
def on_dstr(node)
|
47
55
|
end_of_first_line = node.loc.expression.begin_pos - node.loc.expression.column
|
@@ -52,9 +60,9 @@ module RuboCop
|
|
52
60
|
next unless continuation?(raw_line_one)
|
53
61
|
|
54
62
|
if enforced_style_leading?
|
55
|
-
investigate_leading_style(raw_line_one, end_of_first_line)
|
63
|
+
investigate_leading_style(raw_line_one, raw_line_two, end_of_first_line)
|
56
64
|
else
|
57
|
-
investigate_trailing_style(raw_line_two, end_of_first_line)
|
65
|
+
investigate_trailing_style(raw_line_one, raw_line_two, end_of_first_line)
|
58
66
|
end
|
59
67
|
end
|
60
68
|
end
|
@@ -65,24 +73,37 @@ module RuboCop
|
|
65
73
|
processed_source.raw_source.lines[node.first_line - 1, line_range(node).size]
|
66
74
|
end
|
67
75
|
|
68
|
-
def investigate_leading_style(first_line, end_of_first_line)
|
69
|
-
matches = first_line.match(
|
76
|
+
def investigate_leading_style(first_line, second_line, end_of_first_line)
|
77
|
+
matches = first_line.match(LEADING_STYLE_OFFENSE)
|
70
78
|
return if matches.nil?
|
71
79
|
|
72
|
-
|
80
|
+
offense_range = leading_offense_range(end_of_first_line, matches)
|
81
|
+
add_offense(offense_range) do |corrector|
|
82
|
+
insert_pos = end_of_first_line + second_line[LINE_2_BEGINNING].length
|
83
|
+
autocorrect(corrector, offense_range, insert_pos, matches[:trailing_spaces])
|
84
|
+
end
|
73
85
|
end
|
74
86
|
|
75
|
-
def investigate_trailing_style(second_line, end_of_first_line)
|
76
|
-
matches = second_line.match(
|
87
|
+
def investigate_trailing_style(first_line, second_line, end_of_first_line)
|
88
|
+
matches = second_line.match(TRAILING_STYLE_OFFENSE)
|
77
89
|
return if matches.nil?
|
78
90
|
|
79
|
-
|
91
|
+
offense_range = trailing_offense_range(end_of_first_line, matches)
|
92
|
+
add_offense(offense_range) do |corrector|
|
93
|
+
insert_pos = end_of_first_line - first_line[LINE_1_ENDING].length
|
94
|
+
autocorrect(corrector, offense_range, insert_pos, matches[:leading_spaces])
|
95
|
+
end
|
80
96
|
end
|
81
97
|
|
82
98
|
def continuation?(line)
|
83
99
|
line.end_with?("\\\n")
|
84
100
|
end
|
85
101
|
|
102
|
+
def autocorrect(corrector, offense_range, insert_pos, spaces)
|
103
|
+
corrector.remove(offense_range)
|
104
|
+
corrector.replace(range_between(insert_pos, insert_pos), spaces)
|
105
|
+
end
|
106
|
+
|
86
107
|
def leading_offense_range(end_of_first_line, matches)
|
87
108
|
end_pos = end_of_first_line - matches[:ending].length
|
88
109
|
begin_pos = end_pos - matches[:trailing_spaces].length
|
@@ -92,7 +92,7 @@ module RuboCop
|
|
92
92
|
# which lines start inside a string literal?
|
93
93
|
return [] if ast.nil?
|
94
94
|
|
95
|
-
ast.each_node(:str, :dstr).
|
95
|
+
ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
|
96
96
|
loc = str.location
|
97
97
|
|
98
98
|
if str.heredoc?
|
@@ -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
|
@@ -6,6 +6,9 @@ module RuboCop
|
|
6
6
|
# Checks for unnecessary additional spaces inside array percent literals
|
7
7
|
# (i.e. %i/%w).
|
8
8
|
#
|
9
|
+
# Note that blank percent literals (e.g. `%i( )`) are checked by
|
10
|
+
# `Layout/SpaceInsidePercentLiteralDelimiters`.
|
11
|
+
#
|
9
12
|
# @example
|
10
13
|
#
|
11
14
|
# # bad
|