Class: Rigor::Plugin::ContributionIndex
- Inherits:
-
Object
- Object
- Rigor::Plugin::ContributionIndex
- Defined in:
- lib/rigor/plugin/registry.rb
Overview
ADR-52 WD1 — the compiled contribution table. Categorises a loaded plugin set by which per-call contribution paths each plugin actually implements, AND compiles the declarative gates (method names, ‘block_as_methods` verbs, `owns_receivers`) into frozen lookup structures, so the engine’s hot sites discover “no plugin cares about this call” in O(1) instead of O(plugins × rules) — a top hotspot on plugin-heavy projects (GitLab’s 11 plugins, of which only 2 implement any per-call path). Built once per Registry.
Ordering contract: the gates only PRUNE consultations that could not fire (every pruned rule would have failed its own ‘methods:` / `verbs:` check); the engine still iterates the plugin subsets in registry order and each plugin’s rules in declaration order, so the surviving contributions arrive in exactly the order the ungated walk produced — diagnostics stay byte-identical. The receiver-class ancestry match for ‘dynamic_return` still happens per-dispatch inside `Plugin::Base#dynamic_return_type`.
Instance Attribute Summary collapse
-
#for_file_diagnostics ⇒ Object
readonly
Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the paths within a plugin.
-
#for_method_dispatch ⇒ Object
readonly
Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the paths within a plugin.
-
#for_statement ⇒ Object
readonly
Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the paths within a plugin.
Instance Method Summary collapse
-
#block_entries_for(verb) ⇒ Object
The ‘Macro::BlockAsMethod` entries whose `verbs` include `verb`, in (plugin registration, manifest declaration) order — the same first-match order the previous plugins × entries walk visited.
-
#dispatch_candidate?(method_name) ⇒ Boolean
O(1) “could any plugin contribute a return type for a call named ‘method_name`?” — false only when every `dynamic_return` rule is `methods:`-gated on other names, in which case the ungated walk would have produced zero contributions too.
- #dynamic?(plugin) ⇒ Boolean
-
#dynamic_candidate_for?(plugin, method_name) ⇒ Boolean
Per-plugin gate: false when the plugin declares no ‘dynamic_return` rules at all, or when every rule is `methods:`-gated and none lists `method_name` — i.e.
-
#initialize(plugins) ⇒ ContributionIndex
constructor
A new instance of ContributionIndex.
-
#owns_receiver?(class_name, environment) ⇒ Boolean
True when ‘class_name` equals or inherits from any plugin’s manifest-declared ‘owns_receivers:` entry.
-
#statement_candidate?(method_name) ⇒ Boolean
O(1) statement-path sibling of #dispatch_candidate? over the ‘type_specifier` rules (which are always `methods:`-gated).
- #type_specifier?(plugin) ⇒ Boolean
-
#type_specifier_candidate_for?(plugin, method_name) ⇒ Boolean
Per-plugin gate over ‘type_specifier` rules; same contract as #dynamic_candidate_for?.
Constructor Details
#initialize(plugins) ⇒ ContributionIndex
Returns a new instance of ContributionIndex.
36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/rigor/plugin/registry.rb', line 36 def initialize(plugins) compile_memberships(plugins) compile_gates @block_entries_by_verb = build_block_entries(plugins) @owns_receivers = plugins.flat_map { |p| manifest_for(p)&.owns_receivers || [] }.uniq.freeze # Per-run ancestry verdict memo, keyed by environment identity # then class name. Mutable inside the frozen index — sound # because the class graph is fixed for the lifetime of a run. @owns_receiver_memo = {}.compare_by_identity freeze end |
Instance Attribute Details
#for_file_diagnostics ⇒ Object (readonly)
Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the paths within a plugin. ‘for_file_diagnostics` is the subset the runner’s per-file diagnostic loop visits: plugins overriding ‘#diagnostics_for_file` or declaring at least one `node_rule`.
31 32 33 |
# File 'lib/rigor/plugin/registry.rb', line 31 def for_file_diagnostics @for_file_diagnostics end |
#for_method_dispatch ⇒ Object (readonly)
Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the paths within a plugin. ‘for_file_diagnostics` is the subset the runner’s per-file diagnostic loop visits: plugins overriding ‘#diagnostics_for_file` or declaring at least one `node_rule`.
31 32 33 |
# File 'lib/rigor/plugin/registry.rb', line 31 def for_method_dispatch @for_method_dispatch end |
#for_statement ⇒ Object (readonly)
Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the paths within a plugin. ‘for_file_diagnostics` is the subset the runner’s per-file diagnostic loop visits: plugins overriding ‘#diagnostics_for_file` or declaring at least one `node_rule`.
31 32 33 |
# File 'lib/rigor/plugin/registry.rb', line 31 def for_statement @for_statement end |
Instance Method Details
#block_entries_for(verb) ⇒ Object
The ‘Macro::BlockAsMethod` entries whose `verbs` include `verb`, in (plugin registration, manifest declaration) order — the same first-match order the previous plugins × entries walk visited.
94 95 96 |
# File 'lib/rigor/plugin/registry.rb', line 94 def block_entries_for(verb) @block_entries_by_verb.fetch(verb, EMPTY_BLOCK_ENTRIES) end |
#dispatch_candidate?(method_name) ⇒ Boolean
O(1) “could any plugin contribute a return type for a call named ‘method_name`?” — false only when every `dynamic_return` rule is `methods:`-gated on other names, in which case the ungated walk would have produced zero contributions too.
55 56 57 58 59 |
# File 'lib/rigor/plugin/registry.rb', line 55 def dispatch_candidate?(method_name) return true if @dynamic_global_gate.nil? @dynamic_global_gate.include?(method_name) end |
#dynamic?(plugin) ⇒ Boolean
48 |
# File 'lib/rigor/plugin/registry.rb', line 48 def dynamic?(plugin) = @dynamic.include?(plugin) |
#dynamic_candidate_for?(plugin, method_name) ⇒ Boolean
Per-plugin gate: false when the plugin declares no ‘dynamic_return` rules at all, or when every rule is `methods:`-gated and none lists `method_name` — i.e. when `#dynamic_return_type` would return nil without ever entering a rule block. Subsumes the old `dynamic?(plugin)` membership check at the collector’s call site.
75 76 77 78 79 80 |
# File 'lib/rigor/plugin/registry.rb', line 75 def dynamic_candidate_for?(plugin, method_name) return false unless @dynamic.include?(plugin) gate = @dynamic_gates[plugin] gate.nil? || gate.include?(method_name) end |
#owns_receiver?(class_name, environment) ⇒ Boolean
True when ‘class_name` equals or inherits from any plugin’s manifest-declared ‘owns_receivers:` entry. The union is compiled at build time (almost always empty → O(1) false) and per-class verdicts memoise per environment.
102 103 104 105 106 107 108 109 110 |
# File 'lib/rigor/plugin/registry.rb', line 102 def owns_receiver?(class_name, environment) return false if @owns_receivers.empty? || class_name.nil? memo = (@owns_receiver_memo[environment] ||= {}) memo.fetch(class_name) do memo[class_name] = @owns_receivers.any? { |owner| class_matches_owner?(class_name, owner, environment) } end end |
#statement_candidate?(method_name) ⇒ Boolean
O(1) statement-path sibling of #dispatch_candidate? over the ‘type_specifier` rules (which are always `methods:`-gated).
63 64 65 66 67 |
# File 'lib/rigor/plugin/registry.rb', line 63 def statement_candidate?(method_name) return true if @type_specifier_global_gate.nil? @type_specifier_global_gate.include?(method_name) end |
#type_specifier?(plugin) ⇒ Boolean
49 |
# File 'lib/rigor/plugin/registry.rb', line 49 def type_specifier?(plugin) = @type_specifier.include?(plugin) |
#type_specifier_candidate_for?(plugin, method_name) ⇒ Boolean
Per-plugin gate over ‘type_specifier` rules; same contract as #dynamic_candidate_for?.
84 85 86 87 88 89 |
# File 'lib/rigor/plugin/registry.rb', line 84 def type_specifier_candidate_for?(plugin, method_name) return false unless @type_specifier.include?(plugin) gate = @type_specifier_gates[plugin] gate.nil? || gate.include?(method_name) end |