Class: Rigor::Analysis::Runner

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

Constructor Details

#initialize(configuration:, explain: false, cache_store: Cache::Store.new(root: DEFAULT_CACHE_ROOT), plugin_requirer: nil) ⇒ Runner

Returns a new instance of Runner.

Parameters:

  • configuration (Rigor::Configuration)
  • explain (Boolean) (defaults to: false)

    surface fail-soft fallback events as ‘:info` diagnostics.

  • cache_store (Rigor::Cache::Store, nil) (defaults to: Cache::Store.new(root: DEFAULT_CACHE_ROOT))

    the persistent cache the runner exposes to producers (‘RbsConstantTable` and successors). Pass `nil` to disable caching for this run; the CLI’s ‘–no-cache` flag wires `nil` through. v0.0.9 group A slice 1 introduces the surface; later slices route real producers through it.



38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rigor/analysis/runner.rb', line 38

def initialize(configuration:, explain: false,
               cache_store: Cache::Store.new(root: DEFAULT_CACHE_ROOT),
               plugin_requirer: nil)
  @configuration = configuration
  @explain = explain
  @cache_store = cache_store
  @plugin_requirer = plugin_requirer
  @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_reporterObject (readonly)

Returns the value of attribute boundary_cross_reporter.



26
27
28
# File 'lib/rigor/analysis/runner.rb', line 26

def boundary_cross_reporter
  @boundary_cross_reporter
end

#cache_storeObject (readonly)

Returns the value of attribute cache_store.



26
27
28
# File 'lib/rigor/analysis/runner.rb', line 26

def cache_store
  @cache_store
end

#dependency_source_indexObject (readonly)

Returns the value of attribute dependency_source_index.



26
27
28
# File 'lib/rigor/analysis/runner.rb', line 26

def dependency_source_index
  @dependency_source_index
end

#plugin_registryObject (readonly)

Returns the value of attribute plugin_registry.



26
27
28
# File 'lib/rigor/analysis/runner.rb', line 26

def plugin_registry
  @plugin_registry
end

#rbs_extended_reporterObject (readonly)

Returns the value of attribute rbs_extended_reporter.



26
27
28
# File 'lib/rigor/analysis/runner.rb', line 26

def rbs_extended_reporter
  @rbs_extended_reporter
end

Instance Method Details

#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.



93
94
95
96
97
98
99
100
# File 'lib/rigor/analysis/runner.rb', line 93

def pre_file_diagnostics(expansion)
  plugin_load_diagnostics +
    plugin_prepare_diagnostics +
    dependency_source_diagnostics +
    dependency_source_budget_diagnostics +
    dependency_source_config_conflict_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.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/rigor/analysis/runner.rb', line 59

def run(paths = @configuration.paths)
  Inference::MethodDispatcher::FileFolding.fold_platform_specific_paths =
    @configuration.fold_platform_specific_paths

  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)
  environment = Environment.for_project(
    libraries: @configuration.libraries,
    signature_paths: @configuration.signature_paths,
    cache_store: @cache_store,
    plugin_registry: @plugin_registry,
    dependency_source_index: @dependency_source_index,
    rbs_extended_reporter: @rbs_extended_reporter,
    boundary_cross_reporter: @boundary_cross_reporter
  )
  expansion = expand_paths(paths)

  diagnostics = pre_file_diagnostics(expansion)
  diagnostics += expansion.fetch(:files).flat_map { |path| analyze_file(path, environment) }
  diagnostics += rbs_extended_reporter_diagnostics
  diagnostics += boundary_cross_diagnostics

  Result.new(diagnostics: apply_severity_profile(diagnostics))
end

#validate_target_rubyObject

‘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.



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/rigor/analysis/runner.rb', line 108

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.message}",
    severity: :error,
    rule: "configuration-error",
    source_family: :builtin
  )
end