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 method names, 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: / method_names: 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(method_name) ⇒ Object
The
Macro::BlockAsMethodentries whosemethod_namesincludemethod_name, 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 everydynamic_returnrule ismethods:-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_returnrules at all, or when every rule ismethods:-gated and none listsmethod_name— i.e. -
#initialize(plugins) ⇒ ContributionIndex
constructor
A new instance of ContributionIndex.
-
#owns_receiver?(class_name, environment) ⇒ Boolean
True when
class_nameequals or inherits from any plugin's manifest-declaredowns_receivers:entry. -
#statement_candidate?(method_name) ⇒ Boolean
O(1) statement-path sibling of #dispatch_candidate? over the
type_specifierrules (which are alwaysmethods:-gated). - #type_specifier?(plugin) ⇒ Boolean
-
#type_specifier_candidate_for?(plugin, method_name) ⇒ Boolean
Per-plugin gate over
type_specifierrules; same contract as #dynamic_candidate_for?.
Constructor Details
#initialize(plugins) ⇒ ContributionIndex
Returns a new instance of ContributionIndex.
28 29 30 31 32 33 34 35 36 37 |
# File 'lib/rigor/plugin/registry.rb', line 28 def initialize(plugins) compile_memberships(plugins) compile_gates @block_entries_by_method_name = 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.
23 24 25 |
# File 'lib/rigor/plugin/registry.rb', line 23 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.
23 24 25 |
# File 'lib/rigor/plugin/registry.rb', line 23 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.
23 24 25 |
# File 'lib/rigor/plugin/registry.rb', line 23 def for_statement @for_statement end |
Instance Method Details
#block_entries_for(method_name) ⇒ Object
The Macro::BlockAsMethod entries whose method_names include method_name, in (plugin
registration, manifest declaration) order — the same first-match order the previous plugins × entries
walk visited.
81 82 83 |
# File 'lib/rigor/plugin/registry.rb', line 81 def block_entries_for(method_name) @block_entries_by_method_name.fetch(method_name, 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.
45 46 47 48 49 |
# File 'lib/rigor/plugin/registry.rb', line 45 def dispatch_candidate?(method_name) return true if @dynamic_global_gate.nil? @dynamic_global_gate.include?(method_name) end |
#dynamic?(plugin) ⇒ Boolean
39 |
# File 'lib/rigor/plugin/registry.rb', line 39 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.
63 64 65 66 67 68 |
# File 'lib/rigor/plugin/registry.rb', line 63 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.
88 89 90 91 92 93 94 95 96 |
# File 'lib/rigor/plugin/registry.rb', line 88 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).
53 54 55 56 57 |
# File 'lib/rigor/plugin/registry.rb', line 53 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
40 |
# File 'lib/rigor/plugin/registry.rb', line 40 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?.
71 72 73 74 75 76 |
# File 'lib/rigor/plugin/registry.rb', line 71 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 |