Class: Rigor::Effects::FileCollection
- Inherits:
-
Object
- Object
- Rigor::Effects::FileCollection
- Defined in:
- lib/rigor/effects/file_collection.rb
Overview
What one analyzed file contributes to the project's effect graph (ADR-103 WD12).
The collector produces one of these per file and the runner marshals it back from a fork-pool worker
with the file's diagnostics, so every field is Marshal-clean: frozen Hashes of Strings, Summary
values, and Data edges. Nothing here holds a Prism node, a Scope or an environment.
It carries four tables:
- #summaries — the direct summary of each method the file defines, keyed
Class#m/Class.m/<toplevel>#m(WD14). A reopening in another file contributes the same key and the two join. - #edges — per method key, the calls that must be resolved against the project before they become graph edges. Resolution is deferred to the propagator because a file cannot see the whole class graph; the collector only records what the typer decided about the receiver.
- #superclasses / #includes — the ancestry the propagator needs to resolve an edge through inherited methods and to find every project-known override of a call's target (the closed-world join of WD4).
Merging is associative and commutative in every table, so folding a run's files in pool-completion order yields exactly the table sequential analysis yields.
Defined Under Namespace
Classes: Edge
Instance Attribute Summary collapse
-
#edges ⇒ Object
readonly
Returns the value of attribute edges.
-
#includes ⇒ Object
readonly
Returns the value of attribute includes.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#summaries ⇒ Object
readonly
Returns the value of attribute summaries.
-
#superclasses ⇒ Object
readonly
Returns the value of attribute superclasses.
Class Method Summary collapse
-
.empty(path = nil) ⇒ Object
The collection a file with nothing to say contributes — a parse failure, a file of constants, or a run where the collector was never activated.
-
.merge_all(collections) ⇒ Object
Folds a run's collections in one linear pass: each key's summaries join once, each table is built once, and the frozen result is constructed once at the end.
Instance Method Summary collapse
- #==(other) ⇒ Object (also: #eql?)
- #empty? ⇒ Boolean
-
#failed? ⇒ Boolean
Whether the collector gave up on this file entirely (the fail-soft path).
- #hash ⇒ Object
-
#initialize(path: nil, summaries: NO_TABLE, edges: NO_TABLE, superclasses: NO_TABLE, includes: NO_TABLE, failed: false) ⇒ FileCollection
constructor
A new instance of FileCollection.
-
#merge(other) ⇒ Object
Folds another collection into this one.
Constructor Details
#initialize(path: nil, summaries: NO_TABLE, edges: NO_TABLE, superclasses: NO_TABLE, includes: NO_TABLE, failed: false) ⇒ FileCollection
Returns a new instance of FileCollection.
55 56 57 58 59 60 61 62 63 64 |
# File 'lib/rigor/effects/file_collection.rb', line 55 def initialize(path: nil, summaries: NO_TABLE, edges: NO_TABLE, superclasses: NO_TABLE, includes: NO_TABLE, failed: false) @path = path @summaries = freeze_table(summaries) @edges = freeze_edges(edges) @superclasses = freeze_table(superclasses) @includes = freeze_table(includes) @failed = failed ? true : false freeze end |
Instance Attribute Details
#edges ⇒ Object (readonly)
Returns the value of attribute edges.
53 54 55 |
# File 'lib/rigor/effects/file_collection.rb', line 53 def edges @edges end |
#includes ⇒ Object (readonly)
Returns the value of attribute includes.
53 54 55 |
# File 'lib/rigor/effects/file_collection.rb', line 53 def includes @includes end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
53 54 55 |
# File 'lib/rigor/effects/file_collection.rb', line 53 def path @path end |
#summaries ⇒ Object (readonly)
Returns the value of attribute summaries.
53 54 55 |
# File 'lib/rigor/effects/file_collection.rb', line 53 def summaries @summaries end |
#superclasses ⇒ Object (readonly)
Returns the value of attribute superclasses.
53 54 55 |
# File 'lib/rigor/effects/file_collection.rb', line 53 def superclasses @superclasses end |
Class Method Details
.empty(path = nil) ⇒ Object
The collection a file with nothing to say contributes — a parse failure, a file of constants, or a run where the collector was never activated.
49 50 51 |
# File 'lib/rigor/effects/file_collection.rb', line 49 def self.empty(path = nil) new(path: path) end |
.merge_all(collections) ⇒ Object
Folds a run's collections in one linear pass: each key's summaries join once, each table is built
once, and the frozen result is constructed once at the end. Order-independent in every table
except superclasses, where a later collection's spelling wins exactly as a chain of #merge
calls would leave it, so a path-sorted fold is reproducible.
A collection that is #empty? and not #failed? contributes nothing, which is #merge's own short-circuit spelled once: a file with no methods and no calls has no summary to fold, and its ancestry has no unit to attach to.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/rigor/effects/file_collection.rb', line 97 def self.merge_all(collections) summaries = {} edges = {} superclasses = {} includes = {} failed = false collections.each do |collection| failed ||= collection.failed? next if collection.empty? fold_summaries(summaries, collection.summaries) fold_lists(edges, collection.edges) superclasses.update(collection.superclasses) fold_lists(includes, collection.includes) end includes.each_value(&:uniq!) new(path: nil, summaries: summaries, edges: edges, superclasses: superclasses, includes: includes, failed: failed) end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
137 138 139 140 |
# File 'lib/rigor/effects/file_collection.rb', line 137 def ==(other) other.is_a?(FileCollection) && other.summaries == @summaries && other.edges == @edges && other.superclasses == @superclasses && other.includes == @includes && other.failed? == @failed end |
#empty? ⇒ Boolean
72 73 74 |
# File 'lib/rigor/effects/file_collection.rb', line 72 def empty? @summaries.empty? && @edges.empty? end |
#failed? ⇒ Boolean
Whether the collector gave up on this file entirely (the fail-soft path). Its methods contribute
nothing rather than contributing a wrong summary; rigor check is unaffected either way.
68 69 70 |
# File 'lib/rigor/effects/file_collection.rb', line 68 def failed? @failed end |
#hash ⇒ Object
143 144 145 |
# File 'lib/rigor/effects/file_collection.rb', line 143 def hash [self.class, @summaries, @edges, @superclasses, @includes, @failed].hash end |
#merge(other) ⇒ Object
Folds another collection into this one. Summaries join per key, edge lists union, ancestry merges.
Fold a whole run with merge_all, not with this in a reduce. Every call here rebuilds and
re-freezes the accumulated tables, so folding a run one file at a time costs O(files × methods) —
it was 5.1 s of mastodon's 6.4 s collection overhead and the whole of gitlab's superlinear one
(docs/notes/20260817-effect-collection-perf.md). This stays for a two-collection merge, which is
what its cost model fits.
83 84 85 86 87 |
# File 'lib/rigor/effects/file_collection.rb', line 83 def merge(other) return self if other.empty? && !other.failed? self.class.merge_all([self, other]) end |