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` (def-form) or `block_methods` (block-form) also establishes instance-variable state — treat it like `initialize` for the read-before-write nil soundness gate.”

Def-form (‘methods:`) — applies when the ivar write lives in a named `def` body. Example: Minitest `def setup; @conn = …; end`.

Block-form (‘block_methods:`) — applies when the ivar write lives in a block passed to a method call. Example: RSpec `before { @user = create(:user) }` / `let(:x) { @y = … }`. `ScopeIndexer` descends the block body of any `CallNode` whose method name is in `block_methods`, collecting ivar writes exactly as it would for a def-form initializer.

At least one of ‘methods:` or `block_methods:` must be non-empty.

Authored on a plugin manifest:

# def-form (Minitest):
AdditionalInitializer.new(
  receiver_constraint: "Minitest::Test",
  methods: [:setup]
)

# block-form (RSpec):
AdditionalInitializer.new(
  receiver_constraint: "RSpec::ExampleGroup",
  block_methods: [:before, :let, :subject]
)

The Ruby analogue of PHPStan’s ‘AdditionalConstructorsExtension`. `Rigor::Inference::ScopeIndexer` consults the aggregated set at its read-before-write gate.

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 `def`-form method names (may be empty when only block_methods is used).

  • ‘block_methods` — Array of Symbol call-with-block method names (may be empty when only methods is used).

## Ractor-shareability

All fields are frozen at construction (ADR-15 Phase 1); ‘Ractor.shareable?` returns true after `#initialize`.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(receiver_constraint:, methods: [], block_methods: []) ⇒ AdditionalInitializer

Returns a new instance of AdditionalInitializer.



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rigor/plugin/additional_initializer.rb', line 62

def initialize(receiver_constraint:, methods: [], block_methods: [])
  validate_receiver_constraint!(receiver_constraint)
  validate_method_list!(methods, :methods)
  validate_method_list!(block_methods, :block_methods)
  validate_at_least_one!(methods, block_methods)

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

Instance Attribute Details

#block_methodsObject (readonly)

Returns the value of attribute block_methods.



60
61
62
# File 'lib/rigor/plugin/additional_initializer.rb', line 60

def block_methods
  @block_methods
end

#methodsObject (readonly)

Returns the value of attribute methods.



60
61
62
# File 'lib/rigor/plugin/additional_initializer.rb', line 60

def methods
  @methods
end

#receiver_constraintObject (readonly)

Returns the value of attribute receiver_constraint.



60
61
62
# File 'lib/rigor/plugin/additional_initializer.rb', line 60

def receiver_constraint
  @receiver_constraint
end

Instance Method Details

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



94
95
96
# File 'lib/rigor/plugin/additional_initializer.rb', line 94

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

#covers_block_method?(method_name) ⇒ Boolean

True when ‘method_name` (a Symbol) is declared a block-form initializer by this entry.

Returns:

  • (Boolean)


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

def covers_block_method?(method_name)
  block_methods.include?(method_name)
end

#covers_method?(method_name) ⇒ Boolean

True when ‘method_name` (a Symbol) is declared a def-form initializer by this entry.

Returns:

  • (Boolean)


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

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

#hashObject



99
100
101
# File 'lib/rigor/plugin/additional_initializer.rb', line 99

def hash
  to_h.hash
end

#to_hObject



86
87
88
89
90
91
92
# File 'lib/rigor/plugin/additional_initializer.rb', line 86

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