Class: Rigor::Plugin::AdditionalInitializer

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/plugin/additional_initializer.rb

Overview

ADR-38 declaration: “on ‘receiver_constraint` (and its subclasses), every method named in `methods` also establishes instance-variable state — treat it like `initialize` for the read-before-write nil soundness gate.”

Authored on a plugin manifest:

manifest(
  id: "minitest",
  version: "0.1.0",
  additional_initializers: [
    Rigor::Plugin::AdditionalInitializer.new(
      receiver_constraint: "Minitest::Test",
      methods: [:setup]
    )
  ]
)

The Ruby analogue of PHPStan’s ‘AdditionalConstructorsExtension`. `Rigor::Inference::ScopeIndexer` consults the aggregated set at its single read-before-write gate: for a `def` whose name is in `methods` on a class that equals or inherits from `receiver_constraint` (matched via `Environment#class_ordering`, the same mechanism ADR-16 Tier A uses), the method’s ivar writes are folded into the class’s ‘init_writes` set, so a sibling method reading those ivars no longer gets a `Constant` widening.

The contribution can only ever suppress a nil widening — it never makes the analyzer stricter — so a missed or over-broad match is false-positive-safe by construction (ADR-38 § “Why this is FP-safe”).

## Fields

  • ‘receiver_constraint` — fully-qualified class name (String). The entry applies to that class and its subclasses.

  • ‘methods` — Array of Symbol method names treated as initializers on a matching class.

## Ractor-shareability

Both fields are frozen at construction (ADR-15 Phase 1); ‘Ractor.shareable?` returns true after `#initialize`, so the value object survives `Plugin::Registry.materialize` into a worker Ractor.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(receiver_constraint:, methods:) ⇒ AdditionalInitializer

Returns a new instance of AdditionalInitializer.



54
55
56
57
58
59
60
61
# File 'lib/rigor/plugin/additional_initializer.rb', line 54

def initialize(receiver_constraint:, methods:)
  validate_receiver_constraint!(receiver_constraint)
  validate_methods!(methods)

  @receiver_constraint = receiver_constraint.dup.freeze
  @methods = methods.map(&:to_sym).freeze
  freeze
end

Instance Attribute Details

#methodsObject (readonly)

Returns the value of attribute methods.



52
53
54
# File 'lib/rigor/plugin/additional_initializer.rb', line 52

def methods
  @methods
end

#receiver_constraintObject (readonly)

Returns the value of attribute receiver_constraint.



52
53
54
# File 'lib/rigor/plugin/additional_initializer.rb', line 52

def receiver_constraint
  @receiver_constraint
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



77
78
79
# File 'lib/rigor/plugin/additional_initializer.rb', line 77

def ==(other)
  other.is_a?(AdditionalInitializer) && to_h == other.to_h
end

#covers_method?(method_name) ⇒ Boolean

True when ‘method_name` (a Symbol) is declared an initializer by this entry. The class-constraint match is the caller’s responsibility (it needs the environment’s class graph).

Returns:

  • (Boolean)


66
67
68
# File 'lib/rigor/plugin/additional_initializer.rb', line 66

def covers_method?(method_name)
  methods.include?(method_name)
end

#hashObject



82
83
84
# File 'lib/rigor/plugin/additional_initializer.rb', line 82

def hash
  to_h.hash
end

#to_hObject



70
71
72
73
74
75
# File 'lib/rigor/plugin/additional_initializer.rb', line 70

def to_h
  {
    "receiver_constraint" => receiver_constraint,
    "methods" => methods.map(&:to_s)
  }
end