Class: Rigor::Effects::Scanner
- Inherits:
-
Object
- Object
- Rigor::Effects::Scanner
- Defined in:
- lib/rigor/effects/scanner.rb
Overview
Turns one file's AST plus the call decisions the typer recorded for it into a FileCollection.
The scanner owns identity — which effect units the file defines and what each is keyed as — and
delegates each unit's body to UnitScan. Keys follow the existing symbol tables (ADR-103 WD14):
Class#m for an instance method, Class.m for a singleton one, and <toplevel>#m for a def
outside any class body. Reopenings in one file join here; reopenings across files join when the
runner merges the collections.
Three kinds of unit exist beyond a plain def:
define_method(:literal) { … }— the block is the method's body. The def-node discovery tables skip it, so this is the minimal extension WD14 calls for, made here rather than inScopeIndexerbecause nothing outside effects needs it yet.attr_reader/attr_writer/attr_accessor— synthesised: a reader is ∅, a writer ismutate.self. Without them a caller's edge into an accessor would read as unresolved.- a nested
def— its own unit under the same class, never contained in the enclosing method.
This walk exists only when collection is on. ADR-103 WD13 prefers riding ScopeIndexer's
existing def descent; a separate walk is taken here because the scanner must also attribute each
recorded call node to its enclosing unit, and doing that inside the indexer would put an
effects-shaped concern on the hot path for every run. Off, this file is never loaded past require.
Constant Summary collapse
- TOP_LEVEL_KEY =
Mirrors
Inference::ScopeIndexer::TOP_LEVEL_DEF_KEY. Spelled again rather than required so the effects namespace does not pull the indexer in; the two are pinned together by spec. "<toplevel>"- DECLARATION_MACROS =
Receiver-less calls in a class / module body that #record_declaration interprets. Everything else in a class body is out of scope in v1 — its statements run at load time, which is a unit of its own that no slice models yet.
%i[include prepend attr_reader attr_writer attr_accessor define_method].to_set.freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(path:, calls:, attribution: Attribution.empty, envelopes: EnvelopeIndex.empty, plugin_facts: PluginFacts.empty) ⇒ Scanner
constructor
A new instance of Scanner.
- #scan(root) ⇒ Object
Constructor Details
#initialize(path:, calls:, attribution: Attribution.empty, envelopes: EnvelopeIndex.empty, plugin_facts: PluginFacts.empty) ⇒ Scanner
Returns a new instance of Scanner.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/rigor/effects/scanner.rb', line 64 def initialize(path:, calls:, attribution: Attribution.empty, envelopes: EnvelopeIndex.empty, plugin_facts: PluginFacts.empty) @path = path @calls = calls @attribution = attribution @envelopes = envelopes @plugin_facts = plugin_facts @summaries = {} @edges = {} @superclasses = {} @includes = {} # ADR-103 WD10 / #387 — the class-body facts the framework-edge strategies read, harvested only # when a loaded plugin declared one. A run with no `effect_edges:` never allocates them. @harvest = plugin_facts.edges? ? {} : nil end |
Class Method Details
.scan(root:, path:, calls:, attribution: Attribution.empty, envelopes: EnvelopeIndex.empty, plugin_facts: PluginFacts.empty) ⇒ Object
58 59 60 61 62 |
# File 'lib/rigor/effects/scanner.rb', line 58 def self.scan(root:, path:, calls:, attribution: Attribution.empty, envelopes: EnvelopeIndex.empty, plugin_facts: PluginFacts.empty) new(path: path, calls: calls, attribution: attribution, envelopes: envelopes, plugin_facts: plugin_facts).scan(root) end |
Instance Method Details
#scan(root) ⇒ Object
80 81 82 83 84 85 86 87 |
# File 'lib/rigor/effects/scanner.rb', line 80 def scan(root) walk(root, [], false) synthesize_framework_units FileCollection.new( path: @path, summaries: @summaries, edges: @edges, superclasses: @superclasses, includes: @includes ) end |