Class: Rigor::Plugin::Registry
- Inherits:
-
Object
- Object
- Rigor::Plugin::Registry
- Defined in:
- lib/rigor/plugin/registry.rb,
sig/rigor/plugin/registry.rbs
Overview
Read-side query API over the plugins loaded for a single Analysis::Runner.run. Constructed by
Loader.load and exposed downstream so the contribution merger (slice 3) and diagnostic
provenance (slice 5) can iterate over loaded plugin instances in deterministic order.
The registry is read-only after construction; ordering is the order in which Loader resolved configuration entries, which is project-config order with plugin-id alphabetical as the tie-breaker.
ADR-15 Phase 3 — alongside the instantiated plugins, the registry carries blueprints: a frozen,
Ractor-shareable Array<Blueprint> that records how to re-instantiate the same plugin set in a worker
Ractor. The eventual Phase 4 pool ships blueprints across the boundary and calls Registry.materialize
per-Ractor; the live plugins carriage on the coordinator registry stays unchanged.
Constant Summary collapse
- EMPTY =
Assigned after the class body completes —
Registry.newruns at assignment time and#initializecalls private helpers defined late in the body. Registry.new.freeze
Instance Attribute Summary collapse
-
#additional_initializers ⇒ Object
readonly
ADR-38 — flat, ordered list of every loaded plugin's manifest-declared
Rigor::Plugin::AdditionalInitializerentries. -
#blueprints ⇒ Object
readonly
Returns the value of attribute blueprints.
-
#contribution_index ⇒ Object
readonly
Returns the value of attribute contribution_index.
-
#load_errors ⇒ Object
readonly
Returns the value of attribute load_errors.
-
#node_rule_walk ⇒ Object
readonly
ADR-52 WD4 — the per-run node-rule walk (see NodeRuleWalk).
-
#open_receivers ⇒ Object
readonly
ADR-26 — the aggregate set of "open" receiver class names declared across loaded plugins (manifest
open_receivers:). -
#plugins ⇒ Object
readonly
Returns the value of attribute plugins.
-
#protocol_contracts ⇒ Object
readonly
ADR-28 — flat, ordered list of every loaded plugin's path-scoped method-protocol contracts, in plugin registration order.
Class Method Summary collapse
-
.materialize(blueprints:, services:) ⇒ Rigor::Plugin::Registry
ADR-15 Phase 3 — build a fresh Registry from the supplied blueprint set by replaying Blueprint#materialize per entry against
services.
Instance Method Summary collapse
- #any_load_errors? ⇒ Boolean
-
#contracts_for_path(path) ⇒ Object
ADR-28 — the subset of
protocol_contractswhosepath_globmatchespath. - #empty? ⇒ Boolean
- #find(id) ⇒ Object
-
#hkt_overlay_registry ⇒ Object
ADR-20 slice 6 — aggregate every loaded plugin's manifest-declared HKT registrations + definitions into a single
Inference::HktRegistryoverlay thatEnvironment#hkt_registrymerges on top of the bundledBuiltins::HktBuiltins.registry. - #ids ⇒ Array[String]
-
#initialize(plugins: [], load_errors: [], blueprints: []) ⇒ Registry
constructor
A new instance of Registry.
- #open_receiver?(class_name) ⇒ Boolean
-
#signature_paths ⇒ Object
ADR-25 — flat, ordered list of every loaded plugin's resolved RBS signature directories (absolute paths), in plugin registration order.
-
#source_rbs_synthesizers ⇒ Object
ADR-32 WD4 + WD5 — flat ordered list of
[plugin, callable]pairs for every loaded plugin that declares asource_rbs_synthesizer:in its manifest. -
#type_node_resolvers ⇒ Array[untyped]
ADR-13 — flat ordered list of every loaded plugin's manifest-declared TypeNodeResolver instances, in plugin registration order.
Constructor Details
#initialize(plugins: [], load_errors: [], blueprints: []) ⇒ Registry
Returns a new instance of Registry.
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/rigor/plugin/registry.rb', line 226 def initialize(plugins: [], load_errors: [], blueprints: []) @plugins = plugins.dup.freeze @load_errors = load_errors.dup.freeze @blueprints = blueprints.dup.freeze @contribution_index = ContributionIndex.new(@plugins) # ADR-52 WD1 — aggregate queries the engine issues per def / per diagnostic candidate / per path are # compiled once here (the registry is frozen, so the flat_map-on-every-call versions re-derived an # invariant). `@contracts_by_path` is a mutable per-path memo inside the frozen registry — safe # because the contract set and the glob semantics are fixed for the lifetime of the run. @additional_initializers = @plugins.flat_map { |p| safe_manifest(p)&.additional_initializers || [] }.freeze @open_receivers = @plugins.flat_map { |p| (safe_manifest(p)&.open_receivers || []).map(&:to_s) }.uniq.freeze @open_receivers_set = @open_receivers.to_set.freeze @protocol_contracts = @plugins.flat_map { |p| safe_protocol_contracts(p) }.freeze @contracts_by_path = {} # ADR-52 WD4 — the single engine-owned node-rule walk, compiled once per run from the node-rule # plugin subset (registry order). The runner reuses it for every file; it builds fresh per-file # state internally, so it is safe to freeze and share. @node_rule_walk = NodeRuleWalk.new(@plugins) freeze end |
Instance Attribute Details
#additional_initializers ⇒ Object (readonly)
ADR-38 — flat, ordered list of every loaded plugin's manifest-declared
Rigor::Plugin::AdditionalInitializer entries. Inference::ScopeIndexer consults the set at its
read-before-write nil soundness gate: a def whose name an entry covers, on a class that equals or
inherits from the entry's receiver_constraint, is treated like initialize. Compiled at
construction (ADR-52 WD1) — consulted per def node, ×2 sites in ScopeIndexer.
336 337 338 |
# File 'lib/rigor/plugin/registry.rb', line 336 def additional_initializers @additional_initializers end |
#blueprints ⇒ Object (readonly)
Returns the value of attribute blueprints.
218 219 220 |
# File 'lib/rigor/plugin/registry.rb', line 218 def blueprints @blueprints end |
#contribution_index ⇒ Object (readonly)
Returns the value of attribute contribution_index.
218 219 220 |
# File 'lib/rigor/plugin/registry.rb', line 218 def contribution_index @contribution_index end |
#load_errors ⇒ Object (readonly)
Returns the value of attribute load_errors.
218 219 220 |
# File 'lib/rigor/plugin/registry.rb', line 218 def load_errors @load_errors end |
#node_rule_walk ⇒ Object (readonly)
ADR-52 WD4 — the per-run node-rule walk (see NodeRuleWalk).
248 249 250 |
# File 'lib/rigor/plugin/registry.rb', line 248 def node_rule_walk @node_rule_walk end |
#open_receivers ⇒ Object (readonly)
ADR-26 — the aggregate set of "open" receiver class names declared across loaded plugins (manifest
open_receivers:). A class is open when a plugin vouches that it responds beyond its RBS-declared
method surface. open_receiver? is the membership predicate Analysis::CheckRules consults to skip
the call.undefined-method rule for such a class. Compiled at construction (ADR-52 WD1) — the
predicate runs per undefined-method candidate, so the previous per-call flat_map re-derived a frozen
invariant.
314 315 316 |
# File 'lib/rigor/plugin/registry.rb', line 314 def open_receivers @open_receivers end |
#plugins ⇒ Object (readonly)
Returns the value of attribute plugins.
218 219 220 |
# File 'lib/rigor/plugin/registry.rb', line 218 def plugins @plugins end |
#protocol_contracts ⇒ Object (readonly)
ADR-28 — flat, ordered list of every loaded plugin's path-scoped method-protocol contracts, in
plugin registration order. Read from each plugin's #protocol_contracts (which the manifest backs
by default but a plugin MAY override to fold in per-project config). Consumed by
Inference::MethodParameterBinder (the parameter-type provision) and by contributing plugins'
#diagnostics_for_file hooks (the presence + return-type check). Compiled at construction (ADR-52
WD1); a plugin's config-folding #protocol_contracts override is stable for the run because config
is injected at construction.
329 330 331 |
# File 'lib/rigor/plugin/registry.rb', line 329 def protocol_contracts @protocol_contracts end |
Class Method Details
.materialize(blueprints:, services:) ⇒ Rigor::Plugin::Registry
ADR-15 Phase 3 — build a fresh Registry from the supplied blueprint set by replaying
Blueprint#materialize per entry against services. The returned registry carries NEW plugin
instances (mutable per-Ractor accumulators included) and the same blueprint set, so a worker can hand
the materialised registry to Environment without losing the replay handle. load_errors is
intentionally empty: load-time failures already surfaced in the coordinator registry and don't repeat
per worker.
256 257 258 259 |
# File 'lib/rigor/plugin/registry.rb', line 256 def self.materialize(blueprints:, services:) plugins = blueprints.map { |bp| bp.materialize(services: services) } new(plugins: plugins, blueprints: blueprints, load_errors: []) end |
Instance Method Details
#any_load_errors? ⇒ Boolean
274 275 276 |
# File 'lib/rigor/plugin/registry.rb', line 274 def any_load_errors? !load_errors.empty? end |
#contracts_for_path(path) ⇒ Object
ADR-28 — the subset of protocol_contracts whose path_glob matches path. Contract globs are
authored project-root-relative (lib/controller/**/*.rb); the analyzer may hand this method either a
project-relative path (rigor check run from the project root) or an absolute one (run from
elsewhere, or a spec tmpdir), so the glob is matched both directly and as a **/-prefixed path
suffix. File::FNM_PATHNAME keeps * from crossing /; File::FNM_EXTGLOB enables {a,b} groups.
Returns [] for a nil path so the binder can call this unconditionally. Memoised per path (ADR-52
WD1) — consulted per def node by MethodParameterBinder, and the fnmatch sweep over every contract
is pure in (contract set, path).
346 347 348 349 350 351 352 |
# File 'lib/rigor/plugin/registry.rb', line 346 def contracts_for_path(path) return [] if path.nil? path_s = path.to_s @contracts_by_path[path_s] ||= protocol_contracts.select { |contract| path_matches_glob?(contract.path_glob, path_s) }.freeze end |
#empty? ⇒ Boolean
270 271 272 |
# File 'lib/rigor/plugin/registry.rb', line 270 def empty? plugins.empty? end |
#find(id) ⇒ Object
261 262 263 264 |
# File 'lib/rigor/plugin/registry.rb', line 261 def find(id) id_s = id.to_s plugins.find { |plugin| plugin.manifest.id == id_s } end |
#hkt_overlay_registry ⇒ Object
ADR-20 slice 6 — aggregate every loaded plugin's manifest-declared HKT registrations + definitions
into a single Inference::HktRegistry overlay that Environment#hkt_registry merges on top of the
bundled Builtins::HktBuiltins.registry. Last plugin to register a URI wins (registration order
determined by the user's plugins: list); user .rbs overlays merge on top of this overlay last.
Returns Inference::HktRegistry::EMPTY when no plugin contributes HKT entries so callers can skip the
merge.
292 293 294 295 296 297 298 |
# File 'lib/rigor/plugin/registry.rb', line 292 def registrations = plugins.flat_map { |plugin| plugin.manifest.hkt_registrations } definitions = plugins.flat_map { |plugin| plugin.manifest.hkt_definitions } return Inference::HktRegistry::EMPTY if registrations.empty? && definitions.empty? Inference::HktRegistry.new(registrations: registrations, definitions: definitions) end |
#ids ⇒ Array[String]
266 267 268 |
# File 'lib/rigor/plugin/registry.rb', line 266 def ids plugins.map { |plugin| plugin.manifest.id } end |
#open_receiver?(class_name) ⇒ Boolean
316 317 318 319 320 |
# File 'lib/rigor/plugin/registry.rb', line 316 def open_receiver?(class_name) return false if class_name.nil? @open_receivers_set.include?(class_name.to_s) end |
#signature_paths ⇒ Object
ADR-25 — flat, ordered list of every loaded plugin's resolved RBS signature directories (absolute
paths), in plugin registration order. Environment.for_project merges these into the signature-path
set fed to RbsLoader, alongside the configuration's signature_paths: and the bundler: /
rbs_collection: discovery output.
304 305 306 |
# File 'lib/rigor/plugin/registry.rb', line 304 def signature_paths plugins.flat_map(&:signature_paths) end |
#source_rbs_synthesizers ⇒ Object
ADR-32 WD4 + WD5 — flat ordered list of [plugin, callable] pairs for every loaded plugin that
declares a source_rbs_synthesizer: in its manifest. The engine invokes each callable once per
analysed Ruby source file at env-build time; non-nil return strings are merged into the RBS
environment as virtual signature sources. The full plugin instance is carried alongside the callable
so the engine's cache layer (WD5) can compose plugin.plugin_entry into its per-file descriptor — a
config change to the plugin (e.g. flipping require_magic_comment:) invalidates the dependent
synthesizer cache without any plugin-side bookkeeping.
361 362 363 364 365 366 367 368 |
# File 'lib/rigor/plugin/registry.rb', line 361 def source_rbs_synthesizers plugins.filter_map do |plugin| synthesizer = plugin.manifest.source_rbs_synthesizer next nil if synthesizer.nil? [plugin, synthesizer] end end |
#type_node_resolvers ⇒ Array[untyped]
ADR-13 — flat ordered list of every loaded plugin's manifest-declared TypeNodeResolver instances,
in plugin registration order. Environment#build_name_scope builds a TypeNode::ResolverChain from
this list (environment.rb). The first non-nil #resolve(node, scope) return wins per ADR-13 WD3 /
WD5 — registration order is the user's lever.
282 283 284 |
# File 'lib/rigor/plugin/registry.rb', line 282 def type_node_resolvers plugins.flat_map { |plugin| plugin.manifest.type_node_resolvers } end |