rubocop 1.75.8 → 1.81.1
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 +20 -16
- data/config/default.yml +117 -26
- data/config/obsoletion.yml +6 -3
- data/exe/rubocop +1 -8
- data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
- data/lib/rubocop/cli.rb +18 -3
- data/lib/rubocop/config_loader.rb +4 -39
- data/lib/rubocop/config_store.rb +5 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +35 -6
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +30 -4
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/lint/void.rb +7 -0
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_name.rb +127 -13
- data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
- data/lib/rubocop/cop/style/array_intersect.rb +98 -34
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
- data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -2
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
- data/lib/rubocop/cop/style/map_to_set.rb +1 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
- data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_format.rb +18 -3
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_self.rb +8 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +32 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/utils/format_string.rb +10 -0
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +25 -8
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/lsp/diagnostic.rb +25 -24
- data/lib/rubocop/lsp/routes.rb +65 -9
- data/lib/rubocop/lsp/runtime.rb +2 -2
- data/lib/rubocop/lsp/server.rb +2 -2
- data/lib/rubocop/lsp/stdin_runner.rb +0 -16
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/result_cache.rb +14 -12
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/runner.rb +6 -4
- data/lib/rubocop/server/cache.rb +4 -2
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/target_finder.rb +9 -9
- data/lib/rubocop/target_ruby.rb +10 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +12 -1
- data/lib/ruby_lsp/rubocop/addon.rb +25 -10
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +22 -8
@@ -22,14 +22,6 @@ module RuboCop
|
|
22
22
|
class << self
|
23
23
|
include FileFinder
|
24
24
|
|
25
|
-
PENDING_BANNER = <<~BANNER
|
26
|
-
The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.
|
27
|
-
|
28
|
-
Please also note that you can opt-in to new cops by default by adding this to your config:
|
29
|
-
AllCops:
|
30
|
-
NewCops: enable
|
31
|
-
BANNER
|
32
|
-
|
33
25
|
attr_accessor :debug, :ignore_parent_exclusion, :disable_pending_cops, :enable_pending_cops,
|
34
26
|
:ignore_unrecognized_cops
|
35
27
|
attr_writer :default_configuration
|
@@ -83,7 +75,9 @@ module RuboCop
|
|
83
75
|
|
84
76
|
puts "configuration from #{absolute_path}" if debug?
|
85
77
|
|
86
|
-
|
78
|
+
unless hash.is_a?(Hash)
|
79
|
+
raise(ValidationError, "Malformed configuration in #{absolute_path}")
|
80
|
+
end
|
87
81
|
|
88
82
|
hash
|
89
83
|
end
|
@@ -132,21 +126,7 @@ module RuboCop
|
|
132
126
|
add_excludes_from_files(config, config_file)
|
133
127
|
end
|
134
128
|
|
135
|
-
merge_with_default(config, config_file)
|
136
|
-
unless possible_new_cops?(merged_config)
|
137
|
-
pending_cops = pending_cops_only_qualified(merged_config.pending_cops)
|
138
|
-
warn_on_pending_cops(pending_cops) unless pending_cops.empty?
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def pending_cops_only_qualified(pending_cops)
|
144
|
-
pending_cops.select { |cop| Cop::Registry.qualified_cop?(cop.name) }
|
145
|
-
end
|
146
|
-
|
147
|
-
def possible_new_cops?(config)
|
148
|
-
disable_pending_cops || enable_pending_cops ||
|
149
|
-
config.disabled_new_cops? || config.enabled_new_cops?
|
129
|
+
merge_with_default(config, config_file)
|
150
130
|
end
|
151
131
|
|
152
132
|
def add_excludes_from_files(config, config_file)
|
@@ -208,21 +188,6 @@ module RuboCop
|
|
208
188
|
ConfigFinder.project_root
|
209
189
|
end
|
210
190
|
|
211
|
-
def warn_on_pending_cops(pending_cops)
|
212
|
-
warn Rainbow(PENDING_BANNER).yellow
|
213
|
-
|
214
|
-
pending_cops.each { |cop| warn_pending_cop cop }
|
215
|
-
|
216
|
-
warn Rainbow('For more information: https://docs.rubocop.org/rubocop/versioning.html').yellow
|
217
|
-
end
|
218
|
-
|
219
|
-
def warn_pending_cop(cop)
|
220
|
-
version = cop.metadata['VersionAdded'] || 'N/A'
|
221
|
-
|
222
|
-
warn Rainbow("#{cop.name}: # new in #{version}").yellow
|
223
|
-
warn Rainbow(' Enabled: true').yellow
|
224
|
-
end
|
225
|
-
|
226
191
|
# Merges the given configuration with the default one.
|
227
192
|
def merge_with_default(config, config_file, unset_nil: true)
|
228
193
|
resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
|
data/lib/rubocop/config_store.rb
CHANGED
@@ -25,6 +25,11 @@ module RuboCop
|
|
25
25
|
@validated = true
|
26
26
|
end
|
27
27
|
|
28
|
+
def apply_options!(options)
|
29
|
+
self.options_config = options[:config] if options[:config]
|
30
|
+
force_default_config! if options[:force_default_config]
|
31
|
+
end
|
32
|
+
|
28
33
|
def options_config=(options_config)
|
29
34
|
loaded_config = ConfigLoader.load_file(options_config)
|
30
35
|
@options_config = ConfigLoader.merge_with_default(loaded_config, options_config)
|
@@ -35,8 +35,8 @@ module RuboCop
|
|
35
35
|
# `false` is the same as `disabled` for backward compatibility.
|
36
36
|
return false if ['disabled', false].include?(cop_config['AutoCorrect'])
|
37
37
|
|
38
|
-
# When LSP is enabled, it is considered as editing
|
39
|
-
# and autocorrection with `AutoCorrect: contextual` will not be performed.
|
38
|
+
# When LSP is enabled or the `--editor-mode` option is on, it is considered as editing
|
39
|
+
# source code, and autocorrection with `AutoCorrect: contextual` will not be performed.
|
40
40
|
return false if contextual_autocorrect? && LSP.enabled?
|
41
41
|
|
42
42
|
# :safe_autocorrect is a derived option based on several command-line
|
@@ -94,7 +94,7 @@ module RuboCop
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def surrounding_heredoc?(node)
|
97
|
-
node.
|
97
|
+
node.any_str_type? && node.heredoc?
|
98
98
|
end
|
99
99
|
|
100
100
|
def heredoc_range(node)
|
@@ -106,7 +106,7 @@ module RuboCop
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def string_continuation?(node)
|
109
|
-
node.
|
109
|
+
node.any_str_type? && node.source.match?(/\\\s*$/)
|
110
110
|
end
|
111
111
|
|
112
112
|
def multiline_string?(node)
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
|
46
46
|
gem_declarations(processed_source.ast)
|
47
47
|
.each_cons(2) do |previous, current|
|
48
|
-
next unless consecutive_lines(previous, current)
|
48
|
+
next unless consecutive_lines?(previous, current)
|
49
49
|
next unless case_insensitive_out_of_order?(gem_name(current), gem_name(previous))
|
50
50
|
|
51
51
|
register_offense(previous, current)
|
@@ -29,10 +29,13 @@ module RuboCop
|
|
29
29
|
def align_end(corrector, processed_source, node, align_to)
|
30
30
|
@processed_source = processed_source
|
31
31
|
whitespace = whitespace_range(node)
|
32
|
-
return false unless whitespace.source.strip.empty?
|
33
|
-
|
34
32
|
column = alignment_column(align_to)
|
35
|
-
|
33
|
+
|
34
|
+
if whitespace.source.strip.empty?
|
35
|
+
corrector.replace(whitespace, ' ' * column)
|
36
|
+
else
|
37
|
+
corrector.insert_after(whitespace, "\n#{' ' * column}")
|
38
|
+
end
|
36
39
|
end
|
37
40
|
|
38
41
|
private
|
@@ -54,7 +57,7 @@ module RuboCop
|
|
54
57
|
def inside_string_ranges(node)
|
55
58
|
return [] unless node.is_a?(Parser::AST::Node)
|
56
59
|
|
57
|
-
node.each_node(:
|
60
|
+
node.each_node(:any_str).filter_map { |n| inside_string_range(n) }
|
58
61
|
end
|
59
62
|
|
60
63
|
def inside_string_range(node)
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
class ForToEachCorrector
|
7
7
|
extend NodePattern::Macros
|
8
8
|
|
9
|
-
CORRECTION = '%<collection>s
|
9
|
+
CORRECTION = '%<collection>s%<dot>seach do |%<argument>s|'
|
10
10
|
|
11
11
|
def initialize(for_node)
|
12
12
|
@for_node = for_node
|
@@ -25,7 +25,12 @@ module RuboCop
|
|
25
25
|
attr_reader :for_node, :variable_node, :collection_node
|
26
26
|
|
27
27
|
def correction
|
28
|
-
format(
|
28
|
+
format(
|
29
|
+
CORRECTION,
|
30
|
+
collection: collection_source,
|
31
|
+
dot: collection_node.csend_type? ? '&.' : '.',
|
32
|
+
argument: variable_node.source
|
33
|
+
)
|
29
34
|
end
|
30
35
|
|
31
36
|
def collection_source
|
@@ -10,8 +10,11 @@ module RuboCop
|
|
10
10
|
COMMA_REGEXP = /(?<=\))\s*,/.freeze
|
11
11
|
|
12
12
|
def correct(corrector, node)
|
13
|
-
|
14
|
-
corrector.remove(node.loc.
|
13
|
+
buffer = node.source_range.source_buffer
|
14
|
+
corrector.remove(range_with_surrounding_space(range: node.loc.begin, buffer: buffer,
|
15
|
+
side: :right, whitespace: true))
|
16
|
+
corrector.remove(range_with_surrounding_space(range: node.loc.end, buffer: buffer,
|
17
|
+
side: :left))
|
15
18
|
handle_orphaned_comma(corrector, node)
|
16
19
|
|
17
20
|
return unless ternary_condition?(node) && next_char_is_question_mark?(node)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Gemspec
|
6
|
+
# Use consistent style for Gemspec attributes assignment.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# # This example uses two styles for assignment of metadata attribute.
|
12
|
+
# Gem::Specification.new do |spec|
|
13
|
+
# spec.metadata = { 'key' => 'value' }
|
14
|
+
# spec.metadata['another-key'] = 'another-value'
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# Gem::Specification.new do |spec|
|
19
|
+
# spec.metadata['key'] = 'value'
|
20
|
+
# spec.metadata['another-key'] = 'another-value'
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# Gem::Specification.new do |spec|
|
25
|
+
# spec.metadata = { 'key' => 'value', 'another-key' => 'another-value' }
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # bad
|
29
|
+
# # This example uses two styles for assignment of authors attribute.
|
30
|
+
# Gem::Specification.new do |spec|
|
31
|
+
# spec.authors = %w[author-0 author-1]
|
32
|
+
# spec.authors[2] = 'author-2'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# Gem::Specification.new do |spec|
|
37
|
+
# spec.authors = %w[author-0 author-1 author-2]
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# Gem::Specification.new do |spec|
|
42
|
+
# spec.authors[0] = 'author-0'
|
43
|
+
# spec.authors[1] = 'author-1'
|
44
|
+
# spec.authors[2] = 'author-2'
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # good
|
48
|
+
# # This example uses consistent assignment per attribute,
|
49
|
+
# # even though two different styles are used overall.
|
50
|
+
# Gem::Specification.new do |spec|
|
51
|
+
# spec.metadata = { 'key' => 'value' }
|
52
|
+
# spec.authors[0] = 'author-0'
|
53
|
+
# spec.authors[1] = 'author-1'
|
54
|
+
# spec.authors[2] = 'author-2'
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
class AttributeAssignment < Base
|
58
|
+
include GemspecHelp
|
59
|
+
|
60
|
+
MSG = 'Use consistent style for Gemspec attributes assignment.'
|
61
|
+
|
62
|
+
def on_new_investigation
|
63
|
+
return if processed_source.blank?
|
64
|
+
|
65
|
+
assignments = source_assignments(processed_source.ast)
|
66
|
+
indexed_assignments = source_indexed_assignments(processed_source.ast)
|
67
|
+
|
68
|
+
assignments.keys.intersection(indexed_assignments.keys).each do |attribute|
|
69
|
+
indexed_assignments[attribute].each do |node|
|
70
|
+
add_offense(node)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def source_assignments(ast)
|
78
|
+
assignment_method_declarations(ast)
|
79
|
+
.select(&:assignment_method?)
|
80
|
+
.group_by(&:method_name)
|
81
|
+
.transform_keys { |method_name| method_name.to_s.delete_suffix('=').to_sym }
|
82
|
+
end
|
83
|
+
|
84
|
+
def source_indexed_assignments(ast)
|
85
|
+
indexed_assignment_method_declarations(ast)
|
86
|
+
.group_by { |node| node.children.first.method_name }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -54,22 +54,6 @@ module RuboCop
|
|
54
54
|
MSG = '`%<assignment>s` method calls already given on line ' \
|
55
55
|
'%<line_of_first_occurrence>d of the gemspec.'
|
56
56
|
|
57
|
-
# @!method assignment_method_declarations(node)
|
58
|
-
def_node_search :assignment_method_declarations, <<~PATTERN
|
59
|
-
(send
|
60
|
-
(lvar #match_block_variable_name?) _ ...)
|
61
|
-
PATTERN
|
62
|
-
|
63
|
-
# @!method indexed_assignment_method_declarations(node)
|
64
|
-
def_node_search :indexed_assignment_method_declarations, <<~PATTERN
|
65
|
-
(send
|
66
|
-
(send (lvar #match_block_variable_name?) _)
|
67
|
-
:[]=
|
68
|
-
literal?
|
69
|
-
_
|
70
|
-
)
|
71
|
-
PATTERN
|
72
|
-
|
73
57
|
def on_new_investigation
|
74
58
|
return if processed_source.blank?
|
75
59
|
|
@@ -96,12 +80,6 @@ module RuboCop
|
|
96
80
|
end
|
97
81
|
end
|
98
82
|
|
99
|
-
def match_block_variable_name?(receiver_name)
|
100
|
-
gem_specification(processed_source.ast) do |block_variable_name|
|
101
|
-
return block_variable_name == receiver_name
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
83
|
def duplicated_assignment_method_nodes
|
106
84
|
assignment_method_declarations(processed_source.ast)
|
107
85
|
.select(&:assignment_method?)
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
71
71
|
|
72
72
|
dependency_declarations(processed_source.ast)
|
73
73
|
.each_cons(2) do |previous, current|
|
74
|
-
next unless consecutive_lines(previous, current)
|
74
|
+
next unless consecutive_lines?(previous, current)
|
75
75
|
next unless case_insensitive_out_of_order?(gem_name(current), gem_name(previous))
|
76
76
|
next unless get_dependency_name(previous) == get_dependency_name(current)
|
77
77
|
|
@@ -74,6 +74,14 @@ module RuboCop
|
|
74
74
|
}
|
75
75
|
PATTERN
|
76
76
|
|
77
|
+
# @!method metadata_assignment(node)
|
78
|
+
def_node_search :metadata_assignment, <<~PATTERN
|
79
|
+
`{
|
80
|
+
(send _ :metadata= _)
|
81
|
+
(send (send _ :metadata) :[]= (str _) _)
|
82
|
+
}
|
83
|
+
PATTERN
|
84
|
+
|
77
85
|
# @!method rubygems_mfa_required(node)
|
78
86
|
def_node_search :rubygems_mfa_required, <<~PATTERN
|
79
87
|
(pair (str "rubygems_mfa_required") $_)
|
@@ -131,9 +139,15 @@ module RuboCop
|
|
131
139
|
end
|
132
140
|
|
133
141
|
def insert_mfa_required(corrector, node, block_var)
|
134
|
-
|
142
|
+
require_mfa_directive = <<~RUBY.strip
|
135
143
|
#{block_var}.metadata['rubygems_mfa_required'] = 'true'
|
136
144
|
RUBY
|
145
|
+
|
146
|
+
if (last_assignment = metadata_assignment(processed_source.ast).to_a.last)
|
147
|
+
corrector.insert_after(last_assignment, "\n#{require_mfa_directive}")
|
148
|
+
else
|
149
|
+
corrector.insert_before(node.loc.end, "#{require_mfa_directive}\n")
|
150
|
+
end
|
137
151
|
end
|
138
152
|
|
139
153
|
def change_value(corrector, value)
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
/\A(does not|doesn't) (register|find|flag|report)/ => 'registers',
|
47
47
|
/\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense',
|
48
48
|
/\Aregisters no offense/ => 'registers an offense',
|
49
|
-
/\A(accepts|register)\b/ => 'registers'
|
49
|
+
/\A(accepts|allows|register)\b/ => 'registers'
|
50
50
|
}.freeze
|
51
51
|
|
52
52
|
EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
|
@@ -110,8 +110,8 @@ module RuboCop
|
|
110
110
|
def directive_offense_type(directive, actual_name)
|
111
111
|
return :missing_directive unless directive
|
112
112
|
|
113
|
-
return :wrong_scope if wrong_scope(directive, actual_name)
|
114
|
-
return :no_scope if no_scope(directive, actual_name)
|
113
|
+
return :wrong_scope if wrong_scope?(directive, actual_name)
|
114
|
+
return :no_scope if no_scope?(directive, actual_name)
|
115
115
|
|
116
116
|
# The method directive being prefixed by 'self.' is always an offense.
|
117
117
|
# The matched method_name does not contain the receiver but the
|
@@ -121,11 +121,11 @@ module RuboCop
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
-
def wrong_scope(directive, actual_name)
|
124
|
+
def wrong_scope?(directive, actual_name)
|
125
125
|
!actual_name.start_with?('self.') && directive[:has_scope_directive]
|
126
126
|
end
|
127
127
|
|
128
|
-
def no_scope(directive, actual_name)
|
128
|
+
def no_scope?(directive, actual_name)
|
129
129
|
actual_name.start_with?('self.') && !directive[:has_scope_directive]
|
130
130
|
end
|
131
131
|
|
@@ -29,6 +29,9 @@ module RuboCop
|
|
29
29
|
NODE_GROUPS = {
|
30
30
|
any_block: %i[block numblock itblock],
|
31
31
|
any_def: %i[def defs],
|
32
|
+
any_match_pattern: %i[match_pattern match_pattern_p],
|
33
|
+
any_str: %i[str dstr xstr],
|
34
|
+
any_sym: %i[sym dsym],
|
32
35
|
argument: %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg forward_arg shadowarg],
|
33
36
|
boolean: %i[true false],
|
34
37
|
call: %i[send csend],
|
@@ -209,7 +212,7 @@ module RuboCop
|
|
209
212
|
# A heredoc can be a `dstr` without interpolation, but if there is interpolation
|
210
213
|
# there'll be a `begin` node, in which case, we cannot evaluate the pattern.
|
211
214
|
def acceptable_heredoc?(node)
|
212
|
-
node.
|
215
|
+
node.any_str_type? && node.heredoc? && node.each_child_node(:begin).none?
|
213
216
|
end
|
214
217
|
|
215
218
|
def process_pattern(pattern_node)
|
@@ -66,8 +66,9 @@ module RuboCop
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def autocorrect_to_explicit_predicate(corrector, node, group_name)
|
69
|
-
|
70
|
-
|
69
|
+
range = node.loc.selector.begin.join(node.source_range.end)
|
70
|
+
|
71
|
+
corrector.replace(range, "#{group_name}_type?")
|
71
72
|
end
|
72
73
|
|
73
74
|
def autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
|
79
|
-
new_identifier = node.first_argument
|
79
|
+
return unless (new_identifier = node.first_argument)
|
80
80
|
return unless new_identifier.basic_literal?
|
81
81
|
|
82
82
|
new_identifier = new_identifier.value
|
@@ -76,28 +76,40 @@ module RuboCop
|
|
76
76
|
# # good
|
77
77
|
# class ErrorA < BaseError; end
|
78
78
|
# class ErrorB < BaseError; end
|
79
|
-
# class ErrorC < BaseError; end
|
80
79
|
#
|
81
80
|
# # good
|
82
81
|
# class ErrorA < BaseError; end
|
83
82
|
#
|
84
83
|
# class ErrorB < BaseError; end
|
85
84
|
#
|
86
|
-
#
|
85
|
+
# # good - DefLikeMacros: [memoize]
|
86
|
+
# memoize :attribute_a
|
87
|
+
# memoize :attribute_b
|
88
|
+
#
|
89
|
+
# # good
|
90
|
+
# memoize :attribute_a
|
91
|
+
#
|
92
|
+
# memoize :attribute_b
|
87
93
|
#
|
88
94
|
# @example AllowAdjacentOneLineDefs: false
|
89
95
|
#
|
90
96
|
# # bad
|
91
97
|
# class ErrorA < BaseError; end
|
92
98
|
# class ErrorB < BaseError; end
|
93
|
-
# class ErrorC < BaseError; end
|
94
99
|
#
|
95
100
|
# # good
|
96
101
|
# class ErrorA < BaseError; end
|
97
102
|
#
|
98
103
|
# class ErrorB < BaseError; end
|
99
104
|
#
|
100
|
-
#
|
105
|
+
# # bad - DefLikeMacros: [memoize]
|
106
|
+
# memoize :attribute_a
|
107
|
+
# memoize :attribute_b
|
108
|
+
#
|
109
|
+
# # good
|
110
|
+
# memoize :attribute_a
|
111
|
+
#
|
112
|
+
# memoize :attribute_b
|
101
113
|
#
|
102
114
|
class EmptyLineBetweenDefs < Base
|
103
115
|
include RangeHelp
|
@@ -158,6 +170,8 @@ module RuboCop
|
|
158
170
|
def def_location(correction_node)
|
159
171
|
if correction_node.any_block_type?
|
160
172
|
correction_node.source_range.join(correction_node.children.first.source_range)
|
173
|
+
elsif correction_node.send_type?
|
174
|
+
correction_node.source_range
|
161
175
|
else
|
162
176
|
correction_node.loc.keyword.join(correction_node.loc.name)
|
163
177
|
end
|
@@ -175,8 +189,14 @@ module RuboCop
|
|
175
189
|
end
|
176
190
|
|
177
191
|
def macro_candidate?(node)
|
178
|
-
|
179
|
-
|
192
|
+
macro_candidate = if node.any_block_type?
|
193
|
+
node.send_node
|
194
|
+
elsif node.send_type?
|
195
|
+
node
|
196
|
+
end
|
197
|
+
return false unless macro_candidate
|
198
|
+
|
199
|
+
macro_candidate.macro? && empty_line_between_macros.include?(macro_candidate.method_name)
|
180
200
|
end
|
181
201
|
|
182
202
|
def method_candidate?(node)
|
@@ -240,7 +260,9 @@ module RuboCop
|
|
240
260
|
end
|
241
261
|
|
242
262
|
def def_start(node)
|
243
|
-
|
263
|
+
node = node.send_node if node.any_block_type?
|
264
|
+
|
265
|
+
if node.send_type?
|
244
266
|
node.source_range.line
|
245
267
|
else
|
246
268
|
node.loc.keyword.line
|
@@ -252,11 +274,7 @@ module RuboCop
|
|
252
274
|
end
|
253
275
|
|
254
276
|
def end_loc(node)
|
255
|
-
|
256
|
-
node.source_range.end
|
257
|
-
else
|
258
|
-
node.loc.end
|
259
|
-
end
|
277
|
+
node.source_range.end
|
260
278
|
end
|
261
279
|
|
262
280
|
def autocorrect_remove_lines(corrector, newline_pos, count)
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Layout
|
6
|
+
# Checks for an empty line after a module inclusion method (`extend`,
|
7
|
+
# `include` and `prepend`), or a group of them.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# class Foo
|
12
|
+
# include Bar
|
13
|
+
# attr_reader :baz
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# class Foo
|
18
|
+
# include Bar
|
19
|
+
#
|
20
|
+
# attr_reader :baz
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # also good - multiple module inclusions grouped together
|
24
|
+
# class Foo
|
25
|
+
# extend Bar
|
26
|
+
# include Baz
|
27
|
+
# prepend Qux
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
class EmptyLinesAfterModuleInclusion < Base
|
31
|
+
include RangeHelp
|
32
|
+
extend AutoCorrector
|
33
|
+
|
34
|
+
MSG = 'Add an empty line after module inclusion.'
|
35
|
+
|
36
|
+
MODULE_INCLUSION_METHODS = %i[include extend prepend].freeze
|
37
|
+
|
38
|
+
RESTRICT_ON_SEND = MODULE_INCLUSION_METHODS
|
39
|
+
|
40
|
+
def on_send(node)
|
41
|
+
return if node.receiver || node.arguments.empty?
|
42
|
+
return if node.parent&.type?(:send, :any_block)
|
43
|
+
|
44
|
+
return if next_line_empty_or_enable_directive_comment?(node.last_line)
|
45
|
+
|
46
|
+
next_line_node = next_line_node(node)
|
47
|
+
return unless require_empty_line?(next_line_node)
|
48
|
+
|
49
|
+
add_offense(node) { |corrector| autocorrect(corrector, node) }
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def autocorrect(corrector, node)
|
55
|
+
node_range = range_by_whole_lines(node.source_range)
|
56
|
+
|
57
|
+
next_line = node_range.last_line + 1
|
58
|
+
if enable_directive_comment?(next_line)
|
59
|
+
node_range = processed_source.comment_at_line(next_line)
|
60
|
+
end
|
61
|
+
|
62
|
+
corrector.insert_after(node_range, "\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
def next_line_empty_or_enable_directive_comment?(line)
|
66
|
+
line_empty?(line) || (enable_directive_comment?(line + 1) && line_empty?(line + 1))
|
67
|
+
end
|
68
|
+
|
69
|
+
def enable_directive_comment?(line)
|
70
|
+
return false unless (comment = processed_source.comment_at_line(line))
|
71
|
+
|
72
|
+
DirectiveComment.new(comment).enabled?
|
73
|
+
end
|
74
|
+
|
75
|
+
def line_empty?(line)
|
76
|
+
processed_source[line].nil? || processed_source[line].blank?
|
77
|
+
end
|
78
|
+
|
79
|
+
def require_empty_line?(node)
|
80
|
+
return false unless node
|
81
|
+
|
82
|
+
!allowed_method?(node)
|
83
|
+
end
|
84
|
+
|
85
|
+
def allowed_method?(node)
|
86
|
+
node = node.body if node.respond_to?(:modifier_form?) && node.modifier_form?
|
87
|
+
|
88
|
+
return false unless node.send_type?
|
89
|
+
|
90
|
+
MODULE_INCLUSION_METHODS.include?(node.method_name)
|
91
|
+
end
|
92
|
+
|
93
|
+
def next_line_node(node)
|
94
|
+
return if node.parent.if_type?
|
95
|
+
|
96
|
+
node.right_sibling
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|