Class: Rigor::Analysis::Runner
- Inherits:
-
Object
- Object
- Rigor::Analysis::Runner
- Defined in:
- lib/rigor/analysis/runner.rb
Overview
rubocop:disable Metrics/ClassLength
Constant Summary collapse
- RUBY_GLOB =
"**/*.rb"- DEFAULT_CACHE_ROOT =
".rigor/cache"
Instance Attribute Summary collapse
-
#boundary_cross_reporter ⇒ Object
readonly
Returns the value of attribute boundary_cross_reporter.
-
#cache_store ⇒ Object
readonly
Returns the value of attribute cache_store.
-
#dependency_source_index ⇒ Object
readonly
Returns the value of attribute dependency_source_index.
-
#plugin_registry ⇒ Object
readonly
Returns the value of attribute plugin_registry.
-
#rbs_extended_reporter ⇒ Object
readonly
Returns the value of attribute rbs_extended_reporter.
Instance Method Summary collapse
-
#analyze_files(files) ⇒ Object
ADR-15 Phase 4b — routes per-file analysis to either the sequential coordinator-side Environment (legacy path, default) or a Ractor worker pool built around WorkerSession (opt-in via ‘workers:`).
-
#initialize(configuration:, explain: false, cache_store: Cache::Store.new(root: DEFAULT_CACHE_ROOT), plugin_requirer: nil, workers: 0, collect_stats: true) ⇒ Runner
constructor
A new instance of Runner.
-
#pre_file_diagnostics(expansion) ⇒ Object
Pre-file diagnostic streams that fire once per run rather than per analyzed file: plugin load / prepare envelopes, the ADR-10 dependency-source resolution surface, and the ‘expand_paths` errors for `paths:` entries that don’t exist or aren’t ‘.rb`.
-
#run(paths = @configuration.paths) ⇒ Object
Walks every Ruby file under ‘paths`, parses it, builds a per-node scope index through `Rigor::Inference::ScopeIndexer`, and runs the `Rigor::Analysis::CheckRules` catalogue over it.
-
#validate_target_ruby ⇒ Object
‘target_ruby` flows through to Prism’s ‘version:` option.
Constructor Details
#initialize(configuration:, explain: false, cache_store: Cache::Store.new(root: DEFAULT_CACHE_ROOT), plugin_requirer: nil, workers: 0, collect_stats: true) ⇒ Runner
Returns a new instance of Runner.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/rigor/analysis/runner.rb', line 55 def initialize(configuration:, explain: false, cache_store: Cache::Store.new(root: DEFAULT_CACHE_ROOT), plugin_requirer: nil, workers: 0, collect_stats: true) @configuration = configuration @explain = explain @cache_store = cache_store @plugin_requirer = plugin_requirer @workers = workers @collect_stats = collect_stats @plugin_registry = Plugin::Registry::EMPTY @dependency_source_index = DependencySourceInference::Index::EMPTY @rbs_extended_reporter = RbsExtended::Reporter.new @boundary_cross_reporter = DependencySourceInference::BoundaryCrossReporter.new end |
Instance Attribute Details
#boundary_cross_reporter ⇒ Object (readonly)
Returns the value of attribute boundary_cross_reporter.
29 30 31 |
# File 'lib/rigor/analysis/runner.rb', line 29 def boundary_cross_reporter @boundary_cross_reporter end |
#cache_store ⇒ Object (readonly)
Returns the value of attribute cache_store.
29 30 31 |
# File 'lib/rigor/analysis/runner.rb', line 29 def cache_store @cache_store end |
#dependency_source_index ⇒ Object (readonly)
Returns the value of attribute dependency_source_index.
29 30 31 |
# File 'lib/rigor/analysis/runner.rb', line 29 def dependency_source_index @dependency_source_index end |
#plugin_registry ⇒ Object (readonly)
Returns the value of attribute plugin_registry.
29 30 31 |
# File 'lib/rigor/analysis/runner.rb', line 29 def plugin_registry @plugin_registry end |
#rbs_extended_reporter ⇒ Object (readonly)
Returns the value of attribute rbs_extended_reporter.
29 30 31 |
# File 'lib/rigor/analysis/runner.rb', line 29 def rbs_extended_reporter @rbs_extended_reporter end |
Instance Method Details
#analyze_files(files) ⇒ Object
ADR-15 Phase 4b — routes per-file analysis to either the sequential coordinator-side Environment (legacy path, default) or a Ractor worker pool built around WorkerSession (opt-in via ‘workers:`). The sequential path is bit-for-bit unchanged from v0.1.4 / earlier; the pool path is the substrate exercised by phase 4c when `RIGOR_RACTOR_WORKERS` / `.rigor.yml` `parallel.workers:` is wired.
Sequential mode also snapshots ‘class_decl_paths` from the local environment after the per-file loop completes so `RunStats` can attribute the RBS class universe between project-sig and bundled sources. The env stays a LOCAL variable (not an ivar) so it goes GC-eligible when the method returns — holding it as long-lived state added memory pressure that surfaced as a Bus Error during the spec suite under Ruby 4.0 + rbs 4.0.2.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/rigor/analysis/runner.rb', line 130 def analyze_files(files) return [] if files.empty? if pool_mode? analyze_files_in_pool(files) else environment = build_runner_environment result = files.flat_map { |path| analyze_file(path, environment) } if @collect_stats loader = environment.rbs_loader @class_decl_paths_snapshot = loader&.class_decl_paths || {}.freeze @signature_paths_snapshot = loader&.signature_paths || [].freeze end result end end |
#pre_file_diagnostics(expansion) ⇒ Object
Pre-file diagnostic streams that fire once per run rather than per analyzed file: plugin load / prepare envelopes, the ADR-10 dependency-source resolution surface, and the ‘expand_paths` errors for `paths:` entries that don’t exist or aren’t ‘.rb`. Aggregated here so `#run` stays under the ABC budget.
ADR-15 Phase 4b — ‘plugin_prepare_diagnostics` runs on the coordinator’s plugin registry under sequential mode; under pool mode each worker re-runs ‘prepare` against its own plugin instances, so the pool path drains the first worker’s prepare-diagnostic snapshot into the aggregated diagnostic stream instead (see #analyze_files_in_pool). Skipping the coordinator prepare in pool mode avoids double-running ‘#prepare` against the coordinator-side plugin instances (which the pool path never consults for per-file analysis).
164 165 166 167 168 169 170 171 172 173 |
# File 'lib/rigor/analysis/runner.rb', line 164 def pre_file_diagnostics(expansion) prepare = pool_mode? ? [] : plugin_prepare_diagnostics plugin_load_diagnostics + prepare + dependency_source_diagnostics + dependency_source_budget_diagnostics + dependency_source_config_conflict_diagnostics + rbs_coverage_diagnostics + expansion.fetch(:errors) end |
#run(paths = @configuration.paths) ⇒ Object
Walks every Ruby file under ‘paths`, parses it, builds a per-node scope index through `Rigor::Inference::ScopeIndexer`, and runs the `Rigor::Analysis::CheckRules` catalogue over it. Returns a `Rigor::Analysis::Result` aggregating every produced diagnostic plus any Prism parse errors. The Environment is built once at run start through `Environment.for_project` so all files share the same RBS load.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/rigor/analysis/runner.rb', line 78 def run(paths = @configuration.paths) Inference::MethodDispatcher::FileFolding.fold_platform_specific_paths = @configuration.fold_platform_specific_paths wall_started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) target_ruby_error = validate_target_ruby return Result.new(diagnostics: [target_ruby_error]) if target_ruby_error @plugin_registry = load_plugins @dependency_source_index = DependencySourceInference::Builder.build(@configuration.dependencies) expansion = (paths) @class_decl_paths_snapshot = {}.freeze @signature_paths_snapshot = [] # ADR-16 slice 2b — Tier C pre-pass. Built once per run # against the resolved file set + the loaded plugin # registry's `heredoc_templates` so synthetic methods are # visible cross-file when per-file inference dispatches. @synthetic_method_index = Inference::SyntheticMethodScanner.scan( plugin_registry: @plugin_registry, paths: expansion.fetch(:files), environment: nil ) diagnostics = pre_file_diagnostics(expansion) diagnostics += analyze_files(expansion.fetch(:files)) diagnostics += rbs_extended_reporter_diagnostics diagnostics += boundary_cross_diagnostics Result.new( diagnostics: apply_severity_profile(diagnostics), stats: @collect_stats ? build_run_stats(wall_started_at: wall_started_at, expansion: expansion) : nil ) end |
#validate_target_ruby ⇒ Object
‘target_ruby` flows through to Prism’s ‘version:` option. Prism enforces the supported range and raises `ArgumentError` for versions it does not recognise. Run a one-time smoke parse here so a misconfigured target_ruby surfaces as a single project-level diagnostic instead of crashing the whole run on the first file.
181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/rigor/analysis/runner.rb', line 181 def validate_target_ruby Prism.parse("nil", version: @configuration.target_ruby) nil rescue ArgumentError => e Diagnostic.new( path: ".rigor.yml", line: 1, column: 1, message: "target_ruby #{@configuration.target_ruby.inspect} is not accepted by Prism: #{e.}", severity: :error, rule: "configuration-error", source_family: :builtin ) end |