rubocop 1.60.2 → 1.62.0
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/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +41 -12
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli.rb +6 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_finder.rb +12 -2
- data/lib/rubocop/config_validator.rb +14 -5
- data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
- data/lib/rubocop/cop/base.rb +17 -8
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +2 -0
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -9
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/syntax.rb +1 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
- data/lib/rubocop/cop/lint/void.rb +6 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +29 -8
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -5
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -8
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -5
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +5 -8
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +4 -0
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
- data/lib/rubocop/cop/style/raise_args.rb +3 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -2
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +17 -6
- data/lib/rubocop/cop/style/redundant_return.rb +6 -0
- data/lib/rubocop/cop/style/sample.rb +1 -3
- data/lib/rubocop/cops_documentation_generator.rb +4 -2
- data/lib/rubocop/formatter/html_formatter.rb +30 -10
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/lsp/logger.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +1 -1
- data/lib/rubocop/lsp/server.rb +5 -2
- data/lib/rubocop/lsp/severity.rb +1 -1
- data/lib/rubocop/lsp.rb +29 -0
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/options.rb +11 -0
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/rspec/cop_helper.rb +8 -2
- data/lib/rubocop/rspec/expect_offense.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts.rb +36 -17
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +9 -2
- data/lib/rubocop/target_finder.rb +84 -78
- data/lib/rubocop/target_ruby.rb +82 -80
- data/lib/rubocop/version.rb +18 -3
- metadata +9 -6
@@ -100,10 +100,10 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
|
|
100
100
|
let(:cur_cop_config) do
|
101
101
|
RuboCop::ConfigLoader
|
102
102
|
.default_configuration.for_cop(cop_class)
|
103
|
-
.merge(
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
.merge(
|
104
|
+
'Enabled' => true, # in case it is 'pending'
|
105
|
+
'AutoCorrect' => 'always' # in case defaults set it to 'disabled' or false
|
106
|
+
)
|
107
107
|
.merge(cop_config)
|
108
108
|
end
|
109
109
|
|
@@ -128,56 +128,75 @@ RSpec.shared_context 'mock console output' do
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
-
RSpec.shared_context 'lsp
|
131
|
+
RSpec.shared_context 'lsp' do
|
132
132
|
before do
|
133
|
-
|
133
|
+
RuboCop::LSP.enable
|
134
|
+
end
|
135
|
+
|
136
|
+
after do
|
137
|
+
RuboCop::LSP.disable
|
134
138
|
end
|
135
139
|
end
|
136
140
|
|
137
141
|
RSpec.shared_context 'ruby 2.0' do
|
138
|
-
|
142
|
+
# Prism supports parsing Ruby 3.3+.
|
143
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.0 }
|
139
144
|
end
|
140
145
|
|
141
146
|
RSpec.shared_context 'ruby 2.1' do
|
142
|
-
|
147
|
+
# Prism supports parsing Ruby 3.3+.
|
148
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.1 }
|
143
149
|
end
|
144
150
|
|
145
151
|
RSpec.shared_context 'ruby 2.2' do
|
146
|
-
|
152
|
+
# Prism supports parsing Ruby 3.3+.
|
153
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.2 }
|
147
154
|
end
|
148
155
|
|
149
156
|
RSpec.shared_context 'ruby 2.3' do
|
150
|
-
|
157
|
+
# Prism supports parsing Ruby 3.3+.
|
158
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.3 }
|
151
159
|
end
|
152
160
|
|
153
161
|
RSpec.shared_context 'ruby 2.4' do
|
154
|
-
|
162
|
+
# Prism supports parsing Ruby 3.3+.
|
163
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.4 }
|
155
164
|
end
|
156
165
|
|
157
166
|
RSpec.shared_context 'ruby 2.5' do
|
158
|
-
|
167
|
+
# Prism supports parsing Ruby 3.3+.
|
168
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.5 }
|
159
169
|
end
|
160
170
|
|
161
171
|
RSpec.shared_context 'ruby 2.6' do
|
162
|
-
|
172
|
+
# Prism supports parsing Ruby 3.3+.
|
173
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.6 }
|
163
174
|
end
|
164
175
|
|
165
176
|
RSpec.shared_context 'ruby 2.7' do
|
166
|
-
|
177
|
+
# Prism supports parsing Ruby 3.3+.
|
178
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.7 }
|
167
179
|
end
|
168
180
|
|
169
181
|
RSpec.shared_context 'ruby 3.0' do
|
170
|
-
|
182
|
+
# Prism supports parsing Ruby 3.3+.
|
183
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.0 }
|
171
184
|
end
|
172
185
|
|
173
186
|
RSpec.shared_context 'ruby 3.1' do
|
174
|
-
|
187
|
+
# Prism supports parsing Ruby 3.3+.
|
188
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.1 }
|
175
189
|
end
|
176
190
|
|
177
191
|
RSpec.shared_context 'ruby 3.2' do
|
178
|
-
|
192
|
+
# Prism supports parsing Ruby 3.3+.
|
193
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.2 }
|
179
194
|
end
|
180
195
|
|
181
196
|
RSpec.shared_context 'ruby 3.3' do
|
182
197
|
let(:ruby_version) { 3.3 }
|
183
198
|
end
|
199
|
+
|
200
|
+
RSpec.shared_context 'ruby 3.4' do
|
201
|
+
let(:ruby_version) { 3.4 }
|
202
|
+
end
|
@@ -13,7 +13,7 @@ RSpec.configure do |config|
|
|
13
13
|
config.include HostEnvironmentSimulatorHelper
|
14
14
|
config.include_context 'config', :config
|
15
15
|
config.include_context 'isolated environment', :isolated_environment
|
16
|
-
config.include_context 'lsp
|
16
|
+
config.include_context 'lsp', :lsp
|
17
17
|
config.include_context 'maintain registry', :restore_registry
|
18
18
|
config.include_context 'ruby 2.0', :ruby20
|
19
19
|
config.include_context 'ruby 2.1', :ruby21
|
@@ -27,4 +27,5 @@ RSpec.configure do |config|
|
|
27
27
|
config.include_context 'ruby 3.1', :ruby31
|
28
28
|
config.include_context 'ruby 3.2', :ruby32
|
29
29
|
config.include_context 'ruby 3.3', :ruby33
|
30
|
+
config.include_context 'ruby 3.4', :ruby34
|
30
31
|
end
|
data/lib/rubocop/runner.rb
CHANGED
@@ -467,15 +467,21 @@ module RuboCop
|
|
467
467
|
end
|
468
468
|
end
|
469
469
|
|
470
|
+
# rubocop:disable Metrics/MethodLength
|
470
471
|
def get_processed_source(file)
|
471
472
|
config = @config_store.for_file(file)
|
472
473
|
ruby_version = config.target_ruby_version
|
474
|
+
parser_engine = config.parser_engine
|
473
475
|
|
474
476
|
processed_source = if @options[:stdin]
|
475
|
-
ProcessedSource.new(
|
477
|
+
ProcessedSource.new(
|
478
|
+
@options[:stdin], ruby_version, file, parser_engine: parser_engine
|
479
|
+
)
|
476
480
|
else
|
477
481
|
begin
|
478
|
-
ProcessedSource.from_file(
|
482
|
+
ProcessedSource.from_file(
|
483
|
+
file, ruby_version, parser_engine: parser_engine
|
484
|
+
)
|
479
485
|
rescue Errno::ENOENT
|
480
486
|
raise RuboCop::Error, "No such file or directory: #{file}"
|
481
487
|
end
|
@@ -484,6 +490,7 @@ module RuboCop
|
|
484
490
|
processed_source.registry = mobilized_cop_classes(config)
|
485
491
|
processed_source
|
486
492
|
end
|
493
|
+
# rubocop:enable Metrics/MethodLength
|
487
494
|
|
488
495
|
# A Cop::Team instance is stateful and may change when inspecting.
|
489
496
|
# The "standby" team for a given config is an initialized but
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RuboCop
|
4
|
-
# This class finds target files to inspect by scanning the directory tree
|
5
|
-
# and picking ruby files.
|
4
|
+
# This class finds target files to inspect by scanning the directory tree and picking ruby files.
|
6
5
|
# @api private
|
7
6
|
class TargetFinder
|
8
7
|
HIDDEN_PATH_SUBSTRING = "#{File::SEPARATOR}."
|
@@ -12,21 +11,8 @@ module RuboCop
|
|
12
11
|
@options = options
|
13
12
|
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def debug?
|
20
|
-
@options[:debug]
|
21
|
-
end
|
22
|
-
|
23
|
-
def fail_fast?
|
24
|
-
@options[:fail_fast]
|
25
|
-
end
|
26
|
-
|
27
|
-
# Generate a list of target files by expanding globbing patterns
|
28
|
-
# (if any). If args is empty, recursively find all Ruby source
|
29
|
-
# files under the current directory
|
14
|
+
# Generate a list of target files by expanding globbing patterns (if any). If args is empty,
|
15
|
+
# recursively find all Ruby source files under the current directory
|
30
16
|
# @return [Array] array of file paths
|
31
17
|
def find(args, mode)
|
32
18
|
return target_files_in_dir if args.empty?
|
@@ -44,12 +30,11 @@ module RuboCop
|
|
44
30
|
files.map { |f| File.expand_path(f) }.uniq
|
45
31
|
end
|
46
32
|
|
47
|
-
# Finds all Ruby source files under the current or other supplied
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# so you can include other Ruby files like Rakefiles and gemspecs.
|
33
|
+
# Finds all Ruby source files under the current or other supplied directory. A Ruby source file
|
34
|
+
# is defined as a file with the `.rb` extension or a file with no extension that has a ruby
|
35
|
+
# shebang line as its first line.
|
36
|
+
# It is possible to specify includes and excludes using the config file, so you can include
|
37
|
+
# other Ruby files like Rakefiles and gemspecs.
|
53
38
|
# @param base_dir Root directory under which to search for
|
54
39
|
# ruby source files
|
55
40
|
# @return [Array] Array of filenames
|
@@ -66,20 +51,10 @@ module RuboCop
|
|
66
51
|
target_files.sort_by!(&order)
|
67
52
|
end
|
68
53
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end && ruby_file?(file)
|
74
|
-
|
75
|
-
base_dir_config.file_to_include?(file)
|
76
|
-
end
|
77
|
-
|
78
|
-
# Search for files recursively starting at the given base directory using
|
79
|
-
# the given flags that determine how the match is made. Excluded files will
|
80
|
-
# be removed later by the caller, but as an optimization find_files removes
|
81
|
-
# the top level directories that are excluded in configuration in the
|
82
|
-
# normal way (dir/**/*).
|
54
|
+
# Search for files recursively starting at the given base directory using the given flags that
|
55
|
+
# determine how the match is made. Excluded files will be removed later by the caller, but as an
|
56
|
+
# optimization find_files removes the top level directories that are excluded in configuration
|
57
|
+
# in the normal way (dir/**/*).
|
83
58
|
def find_files(base_dir, flags)
|
84
59
|
# get all wanted directories first to improve speed of finding all files
|
85
60
|
exclude_pattern = combined_exclude_glob_patterns(base_dir)
|
@@ -93,6 +68,17 @@ module RuboCop
|
|
93
68
|
Dir.glob(patterns, flags).select { |path| FileTest.file?(path) }
|
94
69
|
end
|
95
70
|
|
71
|
+
private
|
72
|
+
|
73
|
+
def to_inspect?(file, hidden_files, base_dir_config)
|
74
|
+
return false if base_dir_config.file_to_exclude?(file)
|
75
|
+
return true if !hidden_files.bsearch do |hidden_file|
|
76
|
+
file <=> hidden_file
|
77
|
+
end && ruby_file?(file)
|
78
|
+
|
79
|
+
base_dir_config.file_to_include?(file)
|
80
|
+
end
|
81
|
+
|
96
82
|
def wanted_dir_patterns(base_dir, exclude_pattern, flags)
|
97
83
|
# Escape glob characters in base_dir to avoid unwanted behavior.
|
98
84
|
base_dir = base_dir.gsub(/[\\\{\}\[\]\*\?]/) do |reserved_glob_character|
|
@@ -124,21 +110,6 @@ module RuboCop
|
|
124
110
|
"#{base_dir}/{#{patterns.join(',')}}"
|
125
111
|
end
|
126
112
|
|
127
|
-
def ruby_extension?(file)
|
128
|
-
ruby_extensions.include?(File.extname(file))
|
129
|
-
end
|
130
|
-
|
131
|
-
def ruby_extensions
|
132
|
-
@ruby_extensions ||= begin
|
133
|
-
ext_patterns = all_cops_include.select { |pattern| pattern.start_with?('**/*.') }
|
134
|
-
ext_patterns.map { |pattern| pattern.sub('**/*', '') }
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def ruby_filename?(file)
|
139
|
-
ruby_filenames.include?(File.basename(file))
|
140
|
-
end
|
141
|
-
|
142
113
|
def ruby_filenames
|
143
114
|
@ruby_filenames ||= begin
|
144
115
|
file_patterns = all_cops_include.reject { |pattern| pattern.start_with?('**/*.') }
|
@@ -150,53 +121,72 @@ module RuboCop
|
|
150
121
|
@all_cops_include ||= @config_store.for_pwd.for_all_cops['Include'].map(&:to_s)
|
151
122
|
end
|
152
123
|
|
153
|
-
def
|
154
|
-
|
124
|
+
def process_explicit_path(path, mode)
|
125
|
+
files = path.include?('*') ? Dir[path] : [path]
|
155
126
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
warn("Unprocessable file #{file}: #{e.class}, #{e.message}") if debug?
|
127
|
+
if mode == :only_recognized_file_types || force_exclusion?
|
128
|
+
files.select! { |file| included_file?(file) }
|
129
|
+
end
|
160
130
|
|
161
|
-
|
131
|
+
force_exclusion? ? without_excluded(files) : files
|
162
132
|
end
|
163
133
|
|
164
|
-
def
|
165
|
-
|
134
|
+
def without_excluded(files)
|
135
|
+
files.reject do |file|
|
136
|
+
# When --ignore-parent-exclusion is given, we must look at the configuration associated with
|
137
|
+
# the file, but in the default case when --ignore-parent-exclusion is not given, can safely
|
138
|
+
# look only at the configuration for the current directory, since it's only the Exclude
|
139
|
+
# parameters we're going to check.
|
140
|
+
config = @config_store.for(ignore_parent_exclusion? ? file : '.')
|
141
|
+
config.file_to_exclude?(file)
|
142
|
+
end
|
166
143
|
end
|
167
144
|
|
168
|
-
def
|
169
|
-
|
145
|
+
def included_file?(file)
|
146
|
+
ruby_file?(file) || configured_include?(file)
|
170
147
|
end
|
171
148
|
|
172
149
|
def ruby_file?(file)
|
173
150
|
stdin? || ruby_extension?(file) || ruby_filename?(file) || ruby_executable?(file)
|
174
151
|
end
|
175
152
|
|
176
|
-
def
|
177
|
-
@
|
153
|
+
def stdin?
|
154
|
+
@options.key?(:stdin)
|
178
155
|
end
|
179
156
|
|
180
|
-
def
|
181
|
-
|
157
|
+
def ruby_extension?(file)
|
158
|
+
ruby_extensions.include?(File.extname(file))
|
182
159
|
end
|
183
160
|
|
184
|
-
def
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
files.select! { |file| included_file?(file) }
|
161
|
+
def ruby_extensions
|
162
|
+
@ruby_extensions ||= begin
|
163
|
+
ext_patterns = all_cops_include.select { |pattern| pattern.start_with?('**/*.') }
|
164
|
+
ext_patterns.map { |pattern| pattern.sub('**/*', '') }
|
189
165
|
end
|
166
|
+
end
|
190
167
|
|
191
|
-
|
168
|
+
def ruby_filename?(file)
|
169
|
+
ruby_filenames.include?(File.basename(file))
|
170
|
+
end
|
192
171
|
|
193
|
-
|
194
|
-
|
195
|
-
config.file_to_exclude?(file)
|
196
|
-
end
|
172
|
+
def configured_include?(file)
|
173
|
+
@config_store.for_pwd.file_to_include?(file)
|
197
174
|
end
|
198
175
|
|
199
|
-
|
176
|
+
def ruby_executable?(file)
|
177
|
+
return false unless File.extname(file).empty? && File.exist?(file)
|
178
|
+
|
179
|
+
first_line = File.open(file, &:readline)
|
180
|
+
/#!.*(#{ruby_interpreters(file).join('|')})/.match?(first_line)
|
181
|
+
rescue EOFError, ArgumentError => e
|
182
|
+
warn("Unprocessable file #{file}: #{e.class}, #{e.message}") if debug?
|
183
|
+
|
184
|
+
false
|
185
|
+
end
|
186
|
+
|
187
|
+
def ruby_interpreters(file)
|
188
|
+
@config_store.for(file).for_all_cops['RubyInterpreters']
|
189
|
+
end
|
200
190
|
|
201
191
|
def order
|
202
192
|
if fail_fast?
|
@@ -206,5 +196,21 @@ module RuboCop
|
|
206
196
|
:itself
|
207
197
|
end
|
208
198
|
end
|
199
|
+
|
200
|
+
def force_exclusion?
|
201
|
+
@options[:force_exclusion]
|
202
|
+
end
|
203
|
+
|
204
|
+
def ignore_parent_exclusion?
|
205
|
+
@options[:ignore_parent_exclusion]
|
206
|
+
end
|
207
|
+
|
208
|
+
def debug?
|
209
|
+
@options[:debug]
|
210
|
+
end
|
211
|
+
|
212
|
+
def fail_fast?
|
213
|
+
@options[:fail_fast]
|
214
|
+
end
|
209
215
|
end
|
210
216
|
end
|
data/lib/rubocop/target_ruby.rb
CHANGED
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
# The kind of Ruby that code inspected by RuboCop is written in.
|
5
5
|
# @api private
|
6
6
|
class TargetRuby
|
7
|
-
KNOWN_RUBIES = [2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3].freeze
|
7
|
+
KNOWN_RUBIES = [2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4].freeze
|
8
8
|
DEFAULT_VERSION = 2.7
|
9
9
|
|
10
10
|
OBSOLETE_RUBIES = {
|
@@ -48,6 +48,86 @@ module RuboCop
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
# The target ruby version may be found in a .gemspec file.
|
52
|
+
# @api private
|
53
|
+
class GemspecFile < Source
|
54
|
+
extend NodePattern::Macros
|
55
|
+
|
56
|
+
GEMSPEC_EXTENSION = '.gemspec'
|
57
|
+
|
58
|
+
# @!method required_ruby_version(node)
|
59
|
+
def_node_search :required_ruby_version, <<~PATTERN
|
60
|
+
(send _ :required_ruby_version= $_)
|
61
|
+
PATTERN
|
62
|
+
|
63
|
+
# @!method gem_requirement_versions(node)
|
64
|
+
def_node_matcher :gem_requirement_versions, <<~PATTERN
|
65
|
+
(send (const(const _ :Gem):Requirement) :new
|
66
|
+
{$str+ | (send $str :freeze)+ | (array $str+) | (array (send $str :freeze)+)}
|
67
|
+
)
|
68
|
+
PATTERN
|
69
|
+
|
70
|
+
def name
|
71
|
+
"`required_ruby_version` parameter (in #{gemspec_filename})"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def find_version
|
77
|
+
file = gemspec_filepath
|
78
|
+
return unless file && File.file?(file)
|
79
|
+
|
80
|
+
right_hand_side = version_from_gemspec_file(file)
|
81
|
+
return if right_hand_side.nil?
|
82
|
+
|
83
|
+
find_default_minimal_known_ruby(right_hand_side)
|
84
|
+
end
|
85
|
+
|
86
|
+
def gemspec_filename
|
87
|
+
@gemspec_filename ||= begin
|
88
|
+
basename = Pathname.new(@config.base_dir_for_path_parameters).basename.to_s
|
89
|
+
"#{basename}#{GEMSPEC_EXTENSION}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def gemspec_filepath
|
94
|
+
@gemspec_filepath ||=
|
95
|
+
@config.find_file_upwards(gemspec_filename, @config.base_dir_for_path_parameters)
|
96
|
+
end
|
97
|
+
|
98
|
+
def version_from_gemspec_file(file)
|
99
|
+
processed_source = ProcessedSource.from_file(
|
100
|
+
file, DEFAULT_VERSION, parser_engine: @config.parser_engine
|
101
|
+
)
|
102
|
+
required_ruby_version(processed_source.ast).first
|
103
|
+
end
|
104
|
+
|
105
|
+
def version_from_right_hand_side(right_hand_side)
|
106
|
+
gem_requirement_versions = gem_requirement_versions(right_hand_side)
|
107
|
+
|
108
|
+
if right_hand_side.array_type?
|
109
|
+
version_from_array(right_hand_side)
|
110
|
+
elsif gem_requirement_versions
|
111
|
+
gem_requirement_versions.map(&:value)
|
112
|
+
elsif right_hand_side.str_type?
|
113
|
+
right_hand_side.value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def version_from_array(array)
|
118
|
+
array.children.map(&:value)
|
119
|
+
end
|
120
|
+
|
121
|
+
def find_default_minimal_known_ruby(right_hand_side)
|
122
|
+
version = version_from_right_hand_side(right_hand_side)
|
123
|
+
requirement = Gem::Requirement.new(version)
|
124
|
+
|
125
|
+
KNOWN_RUBIES.detect do |v|
|
126
|
+
v >= DEFAULT_VERSION && requirement.satisfied_by?(Gem::Version.new("#{v}.99"))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
51
131
|
# The target ruby version may be found in a .ruby-version file.
|
52
132
|
# @api private
|
53
133
|
class RubyVersionFile < Source
|
@@ -143,84 +223,6 @@ module RuboCop
|
|
143
223
|
end
|
144
224
|
end
|
145
225
|
|
146
|
-
# The target ruby version may be found in a .gemspec file.
|
147
|
-
# @api private
|
148
|
-
class GemspecFile < Source
|
149
|
-
extend NodePattern::Macros
|
150
|
-
|
151
|
-
GEMSPEC_EXTENSION = '.gemspec'
|
152
|
-
|
153
|
-
# @!method required_ruby_version(node)
|
154
|
-
def_node_search :required_ruby_version, <<~PATTERN
|
155
|
-
(send _ :required_ruby_version= $_)
|
156
|
-
PATTERN
|
157
|
-
|
158
|
-
# @!method gem_requirement_versions(node)
|
159
|
-
def_node_matcher :gem_requirement_versions, <<~PATTERN
|
160
|
-
(send (const(const _ :Gem):Requirement) :new
|
161
|
-
{$str+ | (send $str :freeze)+ | (array $str+) | (array (send $str :freeze)+)}
|
162
|
-
)
|
163
|
-
PATTERN
|
164
|
-
|
165
|
-
def name
|
166
|
-
"`required_ruby_version` parameter (in #{gemspec_filename})"
|
167
|
-
end
|
168
|
-
|
169
|
-
private
|
170
|
-
|
171
|
-
def find_version
|
172
|
-
file = gemspec_filepath
|
173
|
-
return unless file && File.file?(file)
|
174
|
-
|
175
|
-
right_hand_side = version_from_gemspec_file(file)
|
176
|
-
return if right_hand_side.nil?
|
177
|
-
|
178
|
-
find_default_minimal_known_ruby(right_hand_side)
|
179
|
-
end
|
180
|
-
|
181
|
-
def gemspec_filename
|
182
|
-
@gemspec_filename ||= begin
|
183
|
-
basename = Pathname.new(@config.base_dir_for_path_parameters).basename.to_s
|
184
|
-
"#{basename}#{GEMSPEC_EXTENSION}"
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def gemspec_filepath
|
189
|
-
@gemspec_filepath ||=
|
190
|
-
@config.find_file_upwards(gemspec_filename, @config.base_dir_for_path_parameters)
|
191
|
-
end
|
192
|
-
|
193
|
-
def version_from_gemspec_file(file)
|
194
|
-
processed_source = ProcessedSource.from_file(file, DEFAULT_VERSION)
|
195
|
-
required_ruby_version(processed_source.ast).first
|
196
|
-
end
|
197
|
-
|
198
|
-
def version_from_right_hand_side(right_hand_side)
|
199
|
-
gem_requirement_versions = gem_requirement_versions(right_hand_side)
|
200
|
-
|
201
|
-
if right_hand_side.array_type?
|
202
|
-
version_from_array(right_hand_side)
|
203
|
-
elsif gem_requirement_versions
|
204
|
-
gem_requirement_versions.map(&:value)
|
205
|
-
else
|
206
|
-
right_hand_side.value
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def version_from_array(array)
|
211
|
-
array.children.map(&:value)
|
212
|
-
end
|
213
|
-
|
214
|
-
def find_default_minimal_known_ruby(right_hand_side)
|
215
|
-
version = version_from_right_hand_side(right_hand_side)
|
216
|
-
requirement = Gem::Requirement.new(version)
|
217
|
-
|
218
|
-
KNOWN_RUBIES.detect do |v|
|
219
|
-
v >= DEFAULT_VERSION && requirement.satisfied_by?(Gem::Version.new("#{v}.99"))
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
226
|
# If all else fails, a default version will be picked.
|
225
227
|
# @api private
|
226
228
|
class Default < Source
|
@@ -241,10 +243,10 @@ module RuboCop
|
|
241
243
|
|
242
244
|
SOURCES = [
|
243
245
|
RuboCopConfig,
|
246
|
+
GemspecFile,
|
244
247
|
RubyVersionFile,
|
245
248
|
ToolVersionsFile,
|
246
249
|
BundlerLockFile,
|
247
|
-
GemspecFile,
|
248
250
|
Default
|
249
251
|
].freeze
|
250
252
|
|
data/lib/rubocop/version.rb
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
module RuboCop
|
4
4
|
# This module holds the RuboCop version information.
|
5
5
|
module Version
|
6
|
-
STRING = '1.
|
6
|
+
STRING = '1.62.0'
|
7
7
|
|
8
|
-
MSG = '%<version>s (using
|
8
|
+
MSG = '%<version>s (using %<parser_version>s, ' \
|
9
9
|
'rubocop-ast %<rubocop_ast_version>s, ' \
|
10
10
|
'running on %<ruby_engine>s %<ruby_version>s)%<server_mode>s [%<ruby_platform>s]'
|
11
11
|
|
@@ -20,7 +20,7 @@ module RuboCop
|
|
20
20
|
# @api private
|
21
21
|
def self.version(debug: false, env: nil)
|
22
22
|
if debug
|
23
|
-
verbose_version = format(MSG, version: STRING, parser_version:
|
23
|
+
verbose_version = format(MSG, version: STRING, parser_version: parser_version,
|
24
24
|
rubocop_ast_version: RuboCop::AST::Version::STRING,
|
25
25
|
ruby_engine: RUBY_ENGINE, ruby_version: RUBY_VERSION,
|
26
26
|
server_mode: server_mode,
|
@@ -39,6 +39,21 @@ module RuboCop
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
# @api private
|
43
|
+
def self.parser_version
|
44
|
+
config_path = ConfigFinder.find_config_path(Dir.pwd)
|
45
|
+
yaml = YAML.safe_load(
|
46
|
+
File.read(config_path), permitted_classes: [Regexp, Symbol], aliases: true
|
47
|
+
)
|
48
|
+
|
49
|
+
if yaml.dig('AllCops', 'ParserEngine') == 'parser_prism'
|
50
|
+
require 'prism'
|
51
|
+
"Prism #{Prism::VERSION}"
|
52
|
+
else
|
53
|
+
"Parser #{Parser::VERSION}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
42
57
|
# @api private
|
43
58
|
def self.extension_versions(env)
|
44
59
|
features = Util.silence_warnings do
|