Module: RubyLLM::Contract::Concerns::StubHelpers

Included in:
MinitestHelpers, RSpec::Helpers
Defined in:
lib/ruby_llm/contract/concerns/stub_helpers.rb

Overview

Shared implementation of ‘stub_step`, `stub_steps`, and `stub_all_steps`. Included by both `RubyLLM::Contract::RSpec::Helpers` and `RubyLLM::Contract::MinitestHelpers` so the two test-framework adapters cannot drift on stub semantics (Codex DRY finding #1: the prior parallel implementations had already diverged on `normalize_test_response` — RSpec had it, Minitest didn’t).

Cleanup between examples is the responsibility of the host helper:

  • RSpec: ‘around(:each)` hook in `lib/ruby_llm/contract/rspec.rb` restores `step_adapter_overrides`.

  • Minitest: ‘teardown` in `MinitestHelpers` clears overrides and restores `default_adapter`.

Instance Method Summary collapse

Instance Method Details

#stub_all_steps(response: nil, responses: nil, &block) ⇒ Object

Set a global test adapter for ALL steps. Block form restores the previous adapter on exit; non-block form persists until host cleanup.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ruby_llm/contract/concerns/stub_helpers.rb', line 63

def stub_all_steps(response: nil, responses: nil, &block)
  adapter = build_test_adapter(response: response, responses: responses)

  if block
    previous = RubyLLM::Contract.configuration.default_adapter
    begin
      RubyLLM::Contract.configuration.default_adapter = adapter
      yield
    ensure
      RubyLLM::Contract.configuration.default_adapter = previous
    end
  else
    RubyLLM::Contract.configure { |c| c.default_adapter = adapter }
  end
end

#stub_step(step_class, response: nil, responses: nil, &block) ⇒ Object

Stub a single step to return a canned response without API calls. Block form scopes the stub to the block; non-block form lives until the host’s teardown/around hook fires.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/ruby_llm/contract/concerns/stub_helpers.rb', line 22

def stub_step(step_class, response: nil, responses: nil, &block)
  adapter = build_test_adapter(response: response, responses: responses)
  overrides = RubyLLM::Contract.step_adapter_overrides

  if block
    previous = overrides[step_class]
    overrides[step_class] = adapter
    begin
      yield
    ensure
      previous ? (overrides[step_class] = previous) : overrides.delete(step_class)
    end
  else
    overrides[step_class] = adapter
  end
end

#stub_steps(stubs, &block) ⇒ Object

Stub multiple steps with different responses. Requires a block.

Raises:

  • (ArgumentError)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/ruby_llm/contract/concerns/stub_helpers.rb', line 40

def stub_steps(stubs, &block)
  raise ArgumentError, "stub_steps requires a block" unless block

  overrides = RubyLLM::Contract.step_adapter_overrides
  previous = {}

  stubs.each do |step_class, opts|
    opts = opts.transform_keys(&:to_sym)
    previous[step_class] = overrides[step_class]
    overrides[step_class] = build_test_adapter(**opts.slice(:response, :responses))
  end

  begin
    yield
  ensure
    stubs.each_key do |step_class|
      previous[step_class] ? (overrides[step_class] = previous[step_class]) : overrides.delete(step_class)
    end
  end
end