Class: RuboCop::Runner
| Relationships & Source Files | |
| Namespace Children | |
|
Exceptions:
| |
| Extension / Inclusion / Inheritance Descendants | |
|
Subclasses:
|
|
| Inherits: | Object |
| Defined in: | lib/rubocop/runner.rb |
Overview
This class handles the processing of files, which includes dealing with formatters and letting cops inspect the files.
Constant Summary
-
MAX_ITERATIONS =
# File 'lib/rubocop/runner.rb', line 49200 -
REDUNDANT_COP_DISABLE_DIRECTIVE_RULES =
# File 'lib/rubocop/runner.rb', line 52%w[ Lint/RedundantCopDisableDirective RedundantCopDisableDirective Lint ].freeze
Class Method Summary
Instance Attribute Summary
- #aborting=(value) rw
- #aborting? ⇒ Boolean rw
- #errors readonly
- #warnings readonly
- #cached_run? ⇒ Boolean readonly private
- #except_redundant_cop_disable_directive? ⇒ Boolean readonly private
-
#in_memory_corrections_possible? ⇒ Boolean
readonly
private
Custom ruby extractors may derive their fragments from the file on disk rather than from the passed processed source, so corrections can only be kept in memory when the default extractor is used.
-
#parallel_supported_by_options? ⇒ Boolean
readonly
private
--auto-gen-configneeds the offenses of every file in one place, and--diffcollects the diffs in this process, where a worker’s copy of them would be lost. - #project_index_disables_parallel? ⇒ Boolean readonly private
- #project_index_enabled? ⇒ Boolean readonly private
Instance Method Summary
-
#diffs
The
--diffpatches, one per file, from the source on disk (or stdin) to the source once every correction, redundant directive removal included, has been applied. - #run(paths)
- #add_redundant_disables(file, offenses, source) private
- #assemble_team(config) private
- #build_project_index(target_files) private
- #bundled_gem_files private
- #cached_result(file, team) private
-
#check_for_infinite_loop(processed_source, offenses_by_iteration)
private
Check whether a run created source identical to a previous run, which means that we definitely have an infinite loop.
- #check_for_redundant_disables?(source) ⇒ Boolean private
-
#collect_problems
private
Keeps the errors and warnings a file causes apart from the rest of the run’s.
- #considered_failure?(offense) ⇒ Boolean private
- #default_config(cop_name) private
- #do_inspection_loop(file, source = nil) private
- #extract_ruby_sources(processed_source) private
- #file_finished(file, offenses) private
- #file_iterator(files, &block) private
- #file_offense_cache(file) private
- #file_offenses(file) private
-
#file_problems(file, errors, warnings)
private
Formatters get the messages without the colors added for the terminal.
- #file_started(file) private
-
#finalize_corrections(file, original_source, corrected_source)
private
Write the file once, even when the loop was left through an exception (e.g. an infinite correction loop), like the per-iteration writes used to be.
- #find_target_files(paths) private
- #finished_report(file, index, offenses, problems) private
-
#forget_mobilized_cops
private
Lets a runner that is reused from run to run pick up a different
--onlyor--except. - #formatter_set private
-
#get_processed_source(file, prism_result, source: nil)
private
rubocop:disable-next Metrics/MethodLength.
-
#initial_processed_source(file, source)
private
sourceis the corrected source to continue from when the corrections are kept in memory rather than written to the file (--diff). - #inspect_and_correct(processed_source, offenses_by_iteration) private
- #inspect_file(processed_source, team = mobilize_team(processed_source)) private
- #inspect_files(files) private
- #inspect_iteration(processed_source) private
- #iterate_until_no_changes(source, offenses_by_iteration) private
- #list_files(paths) private
- #mark_as_safe_by_config?(config) ⇒ Boolean private
- #minimum_severity_to_fail private
- #mobilize_cop_badge?(badge, config) ⇒ Boolean private
- #mobilize_team(processed_source) private
- #mobilized_cop_classes(config) private
- #offense_displayed?(offense) ⇒ Boolean private
-
#offense_limit
private
Files are reported in order, so which offenses survive the limit does not depend on how the run was parallelized.
- #offenses_to_report(offenses) private
-
#only_changed(target_files)
private
The project index is deliberately built from the unfiltered file list: cross-file offenses must not depend on which files happen to have changed.
- #parallel_file_iterator(files, on_start, on_finish, &block) private
- #plain_messages(problems) private
- #process_file(file) private
- #process_remaining_report_queue private
- #process_report_queue_entry(index) private
-
#project_index_files(target_files)
private
The index always covers the whole project, not just the files being inspected: cross-file offenses must not depend on which files a particular run happens to include, or single-file runs (editors, CI sharding) would see different offenses than full runs.
- #qualify_option_cop_names private
-
#record_diff(file, original_source, corrected_source)
private
--diffreports what autocorrection would do instead of doing it. - #redundant_cop_disable_directive(file) {|cop| ... } private
- #run_in_parallel?(files) ⇒ Boolean private
- #save_in_cache(cache, offenses) private
- #serial_file_iterator(files, on_start, on_finish, &block) private
-
#standby_team(config)
private
A Cop::Team instance is stateful and may change when inspecting.
- #style_guide_cops_only?(config) ⇒ Boolean private
- #supports_safe_autocorrect?(offense) ⇒ Boolean private
- #team_for_redundant_disables(file, offenses, source) {|team| ... } private
- #warn_about_elided_offenses private
Constructor Details
.new(options, config_store) ⇒ Runner
# File 'lib/rubocop/runner.rb', line 59
def initialize(, config_store) @options = @config_store = config_store @errors = [] @warnings = [] @aborting = false @inspected_files = [] @diff_sources = {} @report_queue = {} end
Class Method Details
.default_ruby_extractor ⇒ #call (private)
# File 'lib/rubocop/runner.rb', line 36
def default_ruby_extractor lambda do |processed_source| [ { offset: 0, processed_source: processed_source } ] end end
.ruby_extractors ⇒ Array<#call>
# File 'lib/rubocop/runner.rb', line 29
def ruby_extractors @ruby_extractors ||= [default_ruby_extractor] end
Instance Attribute Details
#aborting=(value) (rw)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 57
attr_writer :aborting
#aborting? ⇒ Boolean (rw)
[ GitHub ]
# File 'lib/rubocop/runner.rb', line 103
def aborting? @aborting end
#cached_run? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/runner.rb', line 419
def cached_run? @cached_run ||= (@options[:cache] == 'true' || (@options[:cache] != 'false' && @config_store.for_pwd.for_all_cops['UseCache'])) && # We can't cache results from code which is piped in to stdin !@options[:stdin] end
#errors (readonly)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 56
attr_reader :errors, :warnings
#except_redundant_cop_disable_directive? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/runner.rb', line 395
def except_redundant_cop_disable_directive? @options[:except] && (@options[:except] & REDUNDANT_COP_DISABLE_DIRECTIVE_RULES).any? end
#in_memory_corrections_possible? ⇒ Boolean (readonly, private)
Custom ruby extractors may derive their fragments from the file on disk rather than from the passed processed source, so corrections can only be kept in memory when the default extractor is used.
# File 'lib/rubocop/runner.rb', line 530
def in_memory_corrections_possible? self.class.ruby_extractors.one? end
#parallel_supported_by_options? ⇒ Boolean (readonly, private)
--auto-gen-config needs the offenses of every file in one place, and
--diff collects the diffs in this process, where a worker’s copy of
them would be lost.
# File 'lib/rubocop/runner.rb', line 249
def @options[:parallel] && !@options[:auto_gen_config] && !@options[:diff] end
#project_index_disables_parallel? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/runner.rb', line 253
def project_index_disables_parallel? return false if @project_index.nil? || !Gem.win_platform? if @options[:debug] puts 'Skipping parallel inspection: the project index is enabled and parallel ' \ 'inspection is not yet supported on Windows.' end true end
#project_index_enabled? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/runner.rb', line 156
def project_index_enabled? return false unless @config_store.for_pwd.for_all_cops['UseProjectIndex'] unless ProjectIndexLoader.available? ProjectIndexLoader.warn_unavailable return false end true end
#warnings (readonly)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 56
attr_reader :errors, :warnings
Instance Method Details
#add_redundant_disables(file, offenses, source) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 345
def add_redundant_disables(file, offenses, source) team_for_redundant_disables(file, offenses, source) do |team| new_offenses, redundant_updated = inspect_file(source, team) offenses += new_offenses if redundant_updated # Do one extra inspection loop if any redundant disables were # removed. This is done in order to find rubocop:enable directives that # have now become useless. It finds the offenses that are left again, # located in the corrected source, so only the corrected ones are kept # from before, as `inspect_and_correct` does. _source, new_offenses = do_inspection_loop(file, team.updated_source) offenses = offenses.select(&:corrected?) | new_offenses end end offenses end
#assemble_team(config) (private)
[ GitHub ]#build_project_index(target_files) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 128
def build_project_index(target_files) return unless project_index_enabled? @project_index = ProjectIndexLoader.build_index(project_index_files(target_files)) end
#bundled_gem_files (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 150
def bundled_gem_files return [] unless @config_store.for_pwd.for_all_cops['ProjectIndexIncludesGems'] ProjectIndexLoader.bundled_gem_source_files end
#cached_result(file, team) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 319
def cached_result(file, team) ResultCache.new(file, team, @options, @config_store) end
#check_for_infinite_loop(processed_source, offenses_by_iteration) (private)
Check whether a run created source identical to a previous run, which means that we definitely have an infinite loop.
# File 'lib/rubocop/runner.rb', line 559
def check_for_infinite_loop(processed_source, offenses_by_iteration) checksum = processed_source.checksum if (loop_start_index = @processed_sources.index(checksum)) raise InfiniteCorrectionLoop.new( processed_source.path, offenses_by_iteration, loop_start: loop_start_index ) end @processed_sources << checksum end
#check_for_redundant_disables?(source) ⇒ Boolean (private)
# File 'lib/rubocop/runner.rb', line 375
def check_for_redundant_disables?(source) return false if except_redundant_cop_disable_directive? # Detached `disable-next` directives produce no disabled ranges but must # still be reported as redundant. if source.disabled_line_ranges.empty? && source.comment_config.detached_next_directives.empty? return false end !@options[:only] end
#collect_problems (private)
Keeps the errors and warnings a file causes apart from the rest of the run’s. A parallel worker inspects files in a copy of the runner that is thrown away, so they have to travel back with the file’s offenses.
#considered_failure?(offense) ⇒ Boolean (private)
# File 'lib/rubocop/runner.rb', line 658
def considered_failure?(offense) return false if offense.disabled? # For :autocorrect level, any correctable offense is a failure, regardless of severity return true if @options[:fail_level] == :autocorrect && offense.correctable? !offense.corrected? && offense.severity >= minimum_severity_to_fail end
#default_config(cop_name) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 716
def default_config(cop_name) RuboCop::ConfigLoader.default_configuration[cop_name] end
#diffs
The --diff patches, one per file, from the source on disk (or stdin) to
the source once every correction, redundant directive removal included,
has been applied.
# File 'lib/rubocop/runner.rb', line 73
def diffs @diffs ||= @diff_sources.filter_map do |file, (original_source, corrected_source)| diff = UnifiedDiff.new(PathUtil.smart_path(file), original_source, corrected_source).to_s diff unless diff.empty? end end
#do_inspection_loop(file, source = nil) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 438
def do_inspection_loop(file, source = nil) processed_source = initial_processed_source(file, source) original_source = processed_source.raw_source # This variable is 2d array used to track corrected offenses after each # inspection iteration. This is used to output meaningful infinite loop # error message. offenses_by_iteration = [] corrected_source = nil # When running with --autocorrect, we need to inspect the file until no # more corrections are made. This is because automatic corrections can # introduce new offenses. In the normal case the loop is only executed # once. The corrections are kept in memory while iterating and written # back to the file when the loop is done. iterate_until_no_changes(processed_source, offenses_by_iteration) do team, updated_source_file = inspect_and_correct(processed_source, offenses_by_iteration) # We have to reprocess the source to pickup the changes. Since the # change could (theoretically) introduce parsing errors, we break the # loop if we find any. break unless updated_source_file # Autocorrect has happened, don't use the prism result since it is stale. # With --stdin the corrected source is kept in @options[:stdin] instead. corrected_source = team.updated_source processed_source = get_processed_source(file, nil, source: corrected_source) end # Return summary of corrected offenses after all iterations [processed_source, offenses_by_iteration.flatten.uniq] ensure finalize_corrections(file, original_source, corrected_source) end
#extract_ruby_sources(processed_source) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 581
def extract_ruby_sources(processed_source) self.class.ruby_extractors.find do |ruby_extractor| result = ruby_extractor.call(processed_source) break result if result rescue StandardError location = if ruby_extractor.is_a?(Proc) ruby_extractor.source_location else ruby_extractor.method(:call).source_location end raise Error, "Ruby extractor #{location[0]} failed to process #{processed_source.path}." end end
#file_finished(file, offenses) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 413
def file_finished(file, offenses) @inspected_files << file offenses = offenses_to_report(offenses) formatter_set.file_finished(file, offenses) end
#file_iterator(files, &block) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 188
def file_iterator(files, &block) all_passed = true on_start = ->(file, _index) { file_started(file) } on_finish = lambda do |file, index, (offenses, passed, problems)| all_passed &&= passed finished_report(file, index, offenses, problems) end if run_in_parallel?(files) parallel_file_iterator(files, on_start, on_finish, &block) else serial_file_iterator(files, on_start, on_finish, &block) end process_remaining_report_queue all_passed end
#file_offense_cache(file) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 323
def file_offense_cache(file) config = @config_store.for_file(file) cache = cached_result(file, standby_team(config)) if cached_run? if cache&.valid? offenses = cache.load # If we're running --autocorrect and the cache says there are # offenses, we need to actually inspect the file. If the cache shows no # offenses, we're good. real_run_needed = @options[:autocorrect] && offenses.any? else real_run_needed = true end if real_run_needed offenses = yield save_in_cache(cache, offenses) unless Cop::Registry.global.warnings?(file) end offenses end
#file_offenses(file) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 310
def file_offenses(file) file_offense_cache(file) do source, offenses = do_inspection_loop(file) offenses = add_redundant_disables(file, offenses.compact.sort, source) offenses = offenses.reject(&:disabled?) unless @options[:display_suppressed] offenses.sort.freeze end end
#file_problems(file, errors, warnings) (private)
Formatters get the messages without the colors added for the terminal.
# File 'lib/rubocop/runner.rb', line 405
def file_problems(file, errors, warnings) formatter_set.file_problems(file, (errors), (warnings)) end
#file_started(file) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 399
def file_started(file) puts "Scanning #{file}" if @options[:debug] formatter_set.file_started(file, cli_options: @options, config_store: @config_store) end
#finalize_corrections(file, original_source, corrected_source) (private)
Write the file once, even when the loop was left through an exception
(e.g. an infinite correction loop), like the per-iteration writes used
to be. Under --diff nothing is written at all.
# File 'lib/rubocop/runner.rb', line 494
def finalize_corrections(file, original_source, corrected_source) if @options[:diff] record_diff(file, original_source, corrected_source) elsif corrected_source Util.replace_file_contents(file, corrected_source) end end
#find_target_files(paths) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 117
def find_target_files(paths) target_finder = TargetFinder.new(@config_store, @options) mode = if @options[:only_recognized_file_types] :only_recognized_file_types else :all_file_types end target_files = target_finder.find(paths, mode) target_files.each(&:freeze).freeze end
#finished_report(file, index, offenses, problems) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 208
def finished_report(file, index, offenses, problems) @report_queue[index] = [file, offenses, problems] @next_index_to_report ||= 0 while @report_queue.key?(@next_index_to_report) process_report_queue_entry(@next_index_to_report) @next_index_to_report += 1 end end
#forget_mobilized_cops (private)
Lets a runner that is reused from run to run pick up a different --only
or --except.
# File 'lib/rubocop/runner.rb', line 619
def forget_mobilized_cops @mobilized_cop_classes = nil end
#formatter_set (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 649
def formatter_set @formatter_set ||= begin set = Formatter::FormatterSet.new(@options) pairs = @options[:formatters] || [['progress']] pairs.each { |formatter_key, output_path| set.add_formatter(formatter_key, output_path) } set end end
#get_processed_source(file, prism_result, source: nil) (private)
rubocop:disable-next Metrics/MethodLength
# File 'lib/rubocop/runner.rb', line 726
def get_processed_source(file, prism_result, source: nil) config = @config_store.for_file(file) ruby_version = config.target_ruby_version parser_engine = config.parser_engine processed_source = if source ProcessedSource.new( Util.emulate_write_read_cycle(source), ruby_version, file, parser_engine: parser_engine ) elsif @options[:stdin] ProcessedSource.new( @options[:stdin], ruby_version, file, parser_engine: parser_engine, prism_result: prism_result ) else begin ProcessedSource.from_file( file, ruby_version, parser_engine: parser_engine ) rescue Errno::ENOENT raise RuboCop::Error, "No such file or directory: #{file}" end end processed_source.config = config processed_source.registry = mobilized_cop_classes(config) processed_source end
#initial_processed_source(file, source) (private)
source is the corrected source to continue from when the corrections
are kept in memory rather than written to the file (--diff).
# File 'lib/rubocop/runner.rb', line 474
def initial_processed_source(file, source) return get_processed_source(file, nil, source: source) if source # We can reuse the prism result since the source did not change yet. get_processed_source(file, @prism_result) end
#inspect_and_correct(processed_source, offenses_by_iteration) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 481
def inspect_and_correct(processed_source, offenses_by_iteration) # The offenses that couldn't be corrected will be found again so we # only keep the corrected ones in order to avoid duplicate reporting. !offenses_by_iteration.empty? && offenses_by_iteration.last.select!(&:corrected?) team, new_offenses, updated_source_file = inspect_iteration(processed_source) offenses_by_iteration.push(new_offenses) [team, updated_source_file] end
#inspect_file(processed_source, team = mobilize_team(processed_source)) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 573
def inspect_file(processed_source, team = mobilize_team(processed_source)) extracted_ruby_sources = extract_ruby_sources(processed_source) offenses = team.investigate_fragments(extracted_ruby_sources, original: processed_source) @errors.concat(team.errors) @warnings.concat(team.warnings) [offenses, team.updated_source_file?] end
#inspect_files(files) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 167
def inspect_files(files) # rubocop:disable Metrics/AbcSize formatter_set.started(files) formatters_started = true file_iterator(files) do |file| offenses, problems = collect_problems { process_file(file) } succeeded = offenses.none? { |o| considered_failure?(o) && offense_displayed?(o) } [offenses, succeeded, problems] end ensure # OPTIMIZE: Calling `ResultCache.cleanup` takes time. This optimization # mainly targets editors that integrates RuboCop. When RuboCop is run # by an editor, it should be inspecting only one file. if files.size > 1 && cached_run? ResultCache.cleanup(@config_store, @options[:debug], @options[:cache_root]) end formatter_set.finished(@inspected_files.freeze) if formatters_started formatter_set.close_output_files warn_about_elided_offenses end
#inspect_iteration(processed_source) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 520
def inspect_iteration(processed_source) team = mobilize_team(processed_source) team.defer_corrections = @options[:diff] || in_memory_corrections_possible? offenses, updated_source_file = inspect_file(processed_source, team) [team, offenses, updated_source_file] end
#iterate_until_no_changes(source, offenses_by_iteration) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 534
def iterate_until_no_changes(source, offenses_by_iteration) # Keep track of the state of the source. If a cop modifies the source # and another cop undoes it producing identical source we have an # infinite loop. @processed_sources = [] # It is also possible for a cop to keep adding indefinitely to a file, # making it bigger and bigger. If the inspection loop runs for an # excessively high number of iterations, this is likely happening. iterations = 0 loop do check_for_infinite_loop(source, offenses_by_iteration) if (iterations += 1) > MAX_ITERATIONS raise InfiniteCorrectionLoop.new(source.path, offenses_by_iteration) end source = yield break unless source end end
#list_files(paths) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 281
def list_files(paths) paths.each { |path| puts PathUtil.relative_path(path) } end
#mark_as_safe_by_config?(config) ⇒ Boolean (private)
#minimum_severity_to_fail (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 720
def minimum_severity_to_fail @minimum_severity_to_fail ||= RuboCop::Cop::Severity.minimum_to_fail(@options, @config_store.for_pwd) end
#mobilize_cop_badge?(badge, config) ⇒ Boolean (private)
# File 'lib/rubocop/runner.rb', line 623
def mobilize_cop_badge?(badge, config) return false if badge.department == :Test return false if badge.match_name?(@options[:except]) if @options[:only] badge.match_name?(@options[:only]) else # use only cops that link to a style guide if requested. !style_guide_cops_only?(config) || config.for_cop(badge.to_s)['StyleGuide'] end end
#mobilize_team(processed_source) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 595
def mobilize_team(processed_source) config = @config_store.for_file(processed_source.path) @inspection_team_by_config ||= {}.compare_by_identity @inspection_team_by_config[config] ||= assemble_team(config) end
#mobilized_cop_classes(config) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 601
def mobilized_cop_classes(config) @mobilized_cop_classes ||= {}.compare_by_identity @mobilized_cop_classes[config] ||= begin # `@options[:only]` and `@options[:except]` are not qualified until # needed so that the registry contains any cops added by `require`s, # which register eagerly when their files are loaded. qualify_option_cop_names OptionsValidator.new(@options). # Filtering by badge keeps lazy-loaded cops unloaded; only the cops # that survive the filter and are enabled will be loaded. Cop::Registry.global.filter_by_badge(@options) { |badge| mobilize_cop_badge?(badge, config) } end end
#offense_displayed?(offense) ⇒ Boolean (private)
# File 'lib/rubocop/runner.rb', line 667
def offense_displayed?(offense) if @options[:display_only_fail_level_offenses] considered_failure?(offense) elsif @options[:display_only_safe_correctable] supports_safe_autocorrect?(offense) elsif @options[:display_only_correctable] offense.correctable? else true end end
#offense_limit (private)
Files are reported in order, so which offenses survive the limit does not depend on how the run was parallelized.
# File 'lib/rubocop/runner.rb', line 687
def offense_limit return @offense_limit if defined?(@offense_limit) max = @options[:max_offenses_per_cop] @offense_limit = (OffenseLimit.new(max.to_i) if max) end
#offenses_to_report(offenses) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 679
def offenses_to_report(offenses) offenses = offenses.select { |o| offense_displayed?(o) } offenses = offense_limit.filter(offenses) if offense_limit offenses end
#only_changed(target_files) (private)
The project index is deliberately built from the unfiltered file list: cross-file offenses must not depend on which files happen to have changed.
# File 'lib/rubocop/runner.rb', line 111
def only_changed(target_files) return target_files unless @options[:changed] ChangedFiles.new(@options[:changed]).filter(target_files).freeze end
#parallel_file_iterator(files, on_start, on_finish, &block) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 264
def parallel_file_iterator(files, on_start, on_finish, &block) Parallel.each(files, start: on_start, finish: on_finish, &block) end
#plain_messages(problems) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 409
def (problems) problems.map { |problem| Rainbow::StringUtils.uncolor(problem.to_s) } end
#process_file(file) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 300
def process_file(file) file_offenses(file) rescue InfiniteCorrectionLoop => e raise e if @options[:raise_cop_error] errors << e warn Rainbow(e.).red e.offenses.compact.sort.freeze end
#process_remaining_report_queue (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 225
def process_remaining_report_queue @report_queue.keys.sort.each do |index| process_report_queue_entry(index) end end
#process_report_queue_entry(index) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 217
def process_report_queue_entry(index) file, offenses, (errors, warnings) = @report_queue.delete(index) @errors.concat(errors) @warnings.concat(warnings) file_problems(file, errors, warnings) unless errors.empty? && warnings.empty? file_finished(file, offenses) end
#project_index_files(target_files) (private)
The index always covers the whole project, not just the files being inspected: cross-file offenses must not depend on which files a particular run happens to include, or single-file runs (editors, CI sharding) would see different offenses than full runs. The project is rooted at the directory of the configuration that enabled the index.
# File 'lib/rubocop/runner.rb', line 139
def project_index_files(target_files) root = @config_store.for_pwd.base_dir_for_path_parameters project_files = begin find_target_files([root]) | target_files rescue Errno::ENOENT target_files end (project_files | bundled_gem_files).sort end
#qualify_option_cop_names (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 635
def qualify_option_cop_names %i[only except].each do |option| next unless @options[option] @options[option] = @options[option].map do |cop_name| Cop::Registry.qualified_cop_name(cop_name, "--#{option} option") end end end
#record_diff(file, original_source, corrected_source) (private)
--diff reports what autocorrection would do instead of doing it. With
--stdin the corrected source is handed back through the options rather
than deferred, so that is where the new source comes from. A file can go
through more than one inspection loop, so the diff runs from the source
the first loop started with to the one the last loop ended with.
# File 'lib/rubocop/runner.rb', line 507
def record_diff(file, original_source, corrected_source) return unless original_source new_source = @options[:stdin] || corrected_source # The original source is the file as it is on disk, so the corrected one # has to go through the same line ending conversion `File.write` would # apply, or on Windows every single line reads as changed. new_source = new_source ? Util.emulate_write_read_cycle(new_source) : original_source sources = (@diff_sources[file] ||= [original_source]) sources[1] = new_source end
#redundant_cop_disable_directive(file) {|cop| ... } (private)
# File 'lib/rubocop/runner.rb', line 387
def redundant_cop_disable_directive(file) config = @config_store.for_file(file) return unless config.for_cop(Cop::Lint::RedundantCopDisableDirective).fetch('Enabled') cop = Cop::Lint::RedundantCopDisableDirective.new(config, @options) yield cop if cop.relevant_file?(file) end
#run(paths)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 80
def run(paths) @inspection_team_by_config = {}.compare_by_identity # Compute the cache source checksum once to avoid potential # inconsistencies between workers. ResultCache.source_checksum target_files = only_changed(find_target_files(paths)) build_project_index(target_files) if @options[:list_target_files] list_files(target_files) else inspect_files(target_files) end rescue Interrupt self.aborting = true warn '' warn 'Exiting...' false end
#run_in_parallel?(files) ⇒ Boolean (private)
# File 'lib/rubocop/runner.rb', line 231
def run_in_parallel?(files) return false unless if files.size <= 1 puts 'Skipping parallel inspection: only a single file needs inspection' if @options[:debug] return false end return false if project_index_disables_parallel? puts 'Running parallel inspection' if @options[:debug] true end
#save_in_cache(cache, offenses) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 427
def save_in_cache(cache, offenses) return unless cache # Caching results when a cop has crashed would prevent the crash in the # next run, since the cop would not be called then. We want crashes to # show up the same in each run. Only this file's errors and warnings are # visible here, see `collect_problems`. return if errors.any? || warnings.any? cache.save(offenses) end
#serial_file_iterator(files, on_start, on_finish, &block) (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 268
def serial_file_iterator(files, on_start, on_finish, &block) files.each_with_index do |file, index| on_start.call(file, index) result = yield file on_finish.call(file, index, result) # Report and count the offending file before stopping so `--fail-fast` # still shows its offenses and exits with a failing status. _offenses, succeeded = result break if @options[:fail_fast] && !succeeded end end
#standby_team(config) (private)
A Cop::Team instance is stateful and may change when inspecting. The "standby" team for a given config is an initialized but otherwise dormant team that can be used for config- and option- level caching in ResultCache.
# File 'lib/rubocop/runner.rb', line 764
def standby_team(config) @standby_team_by_config ||= {}.compare_by_identity @standby_team_by_config[config] ||= assemble_team(config) end
#style_guide_cops_only?(config) ⇒ Boolean (private)
#supports_safe_autocorrect?(offense) ⇒ Boolean (private)
# File 'lib/rubocop/runner.rb', line 704
def supports_safe_autocorrect?(offense) cop_class = Cop::Registry.global.find_by_cop_name(offense.cop_name) default_cfg = default_config(offense.cop_name) offense.correctable? && cop_class&.support_autocorrect? && mark_as_safe_by_config?(default_cfg) end
#team_for_redundant_disables(file, offenses, source) {|team| ... } (private)
# File 'lib/rubocop/runner.rb', line 362
def team_for_redundant_disables(file, offenses, source) return unless check_for_redundant_disables?(source) config = @config_store.for_file(file) team = Cop::Team.mobilize([Cop::Lint::RedundantCopDisableDirective], config, @options) return if team.cops.empty? team.defer_corrections = @options[:diff] team.cops.first.offenses_to_check = offenses yield team end
#warn_about_elided_offenses (private)
[ GitHub ]# File 'lib/rubocop/runner.rb', line 694
def warn_about_elided_offenses elided = offense_limit&.elided_per_cop return unless elided&.any? warn Rainbow( "#{elided.values.sum} more offenses were not reported because of " \ "--max-offenses-per-cop=#{offense_limit.max} (#{elided.keys.join(', ')})." ).yellow end